From 36c8cadb49829bc6547b688354d5b8718435e959 Mon Sep 17 00:00:00 2001
From: nala
Date: Tue, 3 Nov 2026 23:32:32 +0200
Subject: [PATCH] feat: consolidar desenvolvimentos do portal InvestMoz
---
AGENTS.md | 4 +
.../OpportunityWorkflowUnavailable.php | 21 +
.../Api/V1/OpportunityController.php | 2 +
.../CompanyComparisonController.php | 33 +
.../CompanyPreparationController.php | 24 +
app/Http/Controllers/CrmController.php | 90 +-
app/Http/Controllers/DashboardController.php | 13 +-
.../DeskRequestCheckpointController.php | 20 +
.../DeskServiceEditorController.php | 7 +-
.../Controllers/DocumentMalwareController.php | 30 +-
app/Http/Controllers/EducationController.php | 145 +-
.../EducationDeclarationDraftController.php | 34 +
.../ExistingBusinessController.php | 2 +
.../InvestmentDiscoveryController.php | 8 +-
.../Controllers/InvestmentGuideController.php | 31 +
.../InvestmentPortfolioController.php | 8 +-
.../InvestmentWorkspaceController.php | 49 +-
.../Controllers/InvestmentZoneController.php | 4 +
.../Controllers/InvestorPathController.php | 16 +-
.../Controllers/LegacyContentController.php | 2 +
.../OpportunityManagementController.php | 2 +
.../OpportunityResourceController.php | 30 +-
.../PartnershipExchangeController.php | 206 +-
.../Controllers/PortalProfileController.php | 15 +-
.../PortalProfileInstallationController.php | 14 +
.../Controllers/PortalServicesController.php | 3 +
.../Controllers/ProactiveSupplyController.php | 15 +
.../ProductExperimentController.php | 41 +
.../ProductUsageMetricsController.php | 19 +
.../PublicBusinessOpportunityController.php | 43 +-
.../TechnicalSupportController.php | 45 +
.../Controllers/VirtualDeskController.php | 183 +-
.../VirtualDeskInstallationController.php | 11 +-
.../VirtualDeskOperationsController.php | 86 +-
.../Middleware/CollectPublicSearchMetrics.php | 25 +
.../PublicBusinessOpportunityResource.php | 5 +
app/Jobs/ScanDocumentForMalware.php | 127 +-
app/Models/CrmTask.php | 21 +
app/Services/Ai/AssistiveRules.php | 5 +-
app/Services/Ai/InvestorGuidance.php | 12 +-
app/Services/BusinessFormSchema.php | 41 +-
app/Services/BusinessPointPublication.php | 125 +
app/Services/BusinessProximitySearch.php | 53 +
app/Services/CompanyComparison.php | 208 +
app/Services/CompanyPreparation.php | 285 +
app/Services/CrmNextAction.php | 27 +
app/Services/CrmTaskCreation.php | 76 +
app/Services/CrmTaskPreparations.php | 117 +
app/Services/DashboardWorkQueue.php | 88 +
app/Services/DeskAttachments.php | 116 +
app/Services/DeskPaymentEvidence.php | 46 +
app/Services/DeskRequestCheckpoints.php | 88 +
app/Services/DeskServiceAvailability.php | 47 +
app/Services/DeskServiceEditor.php | 103 +-
app/Services/EducationAccess.php | 21 +
app/Services/EducationDeclarationDrafts.php | 142 +
app/Services/EducationDeclarationRules.php | 29 +
app/Services/EducationReviews.php | 101 +
app/Services/EducationWorkQueue.php | 40 +
app/Services/ExistingBusinessDrafts.php | 3 +-
app/Services/ExistingBusinessIntake.php | 4 +-
app/Services/InvestmentGuides.php | 169 +
app/Services/InvestmentProfileCommands.php | 68 +
app/Services/InvestorPath.php | 4 +-
app/Services/Malware/DocumentScanAttempts.php | 76 +
app/Services/Malware/DocumentScanDelivery.php | 46 +
app/Services/Malware/DocumentScanRetry.php | 78 +
app/Services/OpportunityImageProcessor.php | 18 +-
app/Services/OpportunityProfileWorkflow.php | 12 +
.../OpportunityResourceFileCleanup.php | 65 +
app/Services/OpportunityResources.php | 24 +-
app/Services/OpportunityScanDispatch.php | 50 +
.../OpportunityTechnicalExecution.php | 40 +
.../OpportunityTechnicalIncidents.php | 134 +
app/Services/OpportunityTechnicalSupport.php | 128 +
app/Services/OpportunityWorkflowExecution.php | 28 +
app/Services/OrganizationCountry.php | 28 +-
app/Services/PartnershipAgreementHistory.php | 141 +
.../PartnershipAgreementProjection.php | 84 +
app/Services/PartnershipAgreements.php | 140 +
app/Services/PartnershipCandidacies.php | 188 +
app/Services/PartnershipCandidacyHistory.php | 198 +
app/Services/PartnershipDraftSaves.php | 46 +
app/Services/PartnershipExchange.php | 252 +-
app/Services/PartnershipMilestones.php | 78 +
app/Services/PartnershipNotifications.php | 145 +
app/Services/PartnershipPublication.php | 110 +
.../PartnershipPublicationHistory.php | 195 +
app/Services/PartnershipRoomUploads.php | 69 +
app/Services/PortalAudit.php | 15 +-
app/Services/PortalProfileAccess.php | 4 +
app/Services/PortalProfileAdministration.php | 6 +-
app/Services/PortalProfileInstallation.php | 107 +-
app/Services/ProactiveSupply.php | 79 +-
app/Services/ProductExperiments.php | 307 +
app/Services/ProductUsageMetrics.php | 170 +
app/Services/PublicBusinessLocations.php | 57 +
app/Services/PublicSearchMetrics.php | 144 +
app/Services/TechnicalIncidentHandling.php | 138 +
.../TechnicalSupportProfileSchema.php | 40 +
app/Services/VerifiedDocumentBinary.php | 2 +-
app/Services/VirtualDesk.php | 177 +-
app/Services/VirtualDeskInstallation.php | 3 +
bootstrap/app.php | 2 +
config/bvm-admission-guide.php | 101 +
config/company-comparison.php | 30 +
config/investment-guides.php | 37 +
config/product-experiments.php | 17 +
config/product-metrics.php | 26 +
config/search-metrics.php | 30 +
...02_230000_education_declaration_drafts.php | 38 +
...000_existing_business_location_sources.php | 27 +
...03_010000_desk_service_effective_dates.php | 24 +
...1_03_020000_create_product_experiments.php | 71 +
...03_030000_create_product_search_counts.php | 50 +
...040000_create_desk_request_checkpoints.php | 33 +
...11_03_050000_scope_desk_document_links.php | 26 +
...60000_crm_task_creation_commands_index.php | 17 +
...03_070000_create_crm_task_preparations.php | 32 +
...3_080000_add_technical_support_profile.php | 26 +
.../local-validation-20261029.json | 51257 ++++++++++++++++
.../unification/traceability-and-manual.md | 1058 +
docs/investmoz/v2/auditoria-portal/backlog.md | 247 +-
.../v2/auditoria-portal/matriz-requisitos.csv | 393 +-
.../visao-consolidada-modulos.md | 184 +-
.../js/components/business-point-summary.tsx | 131 +
.../js/components/crm-edit-comparison.tsx | 120 +
resources/js/components/crm-task-creation.tsx | 293 +
.../js/components/dashboard-work-queue.tsx | 167 +
.../js/components/desk-attachment-field.tsx | 453 +
.../js/components/desk-case-state-form.tsx | 124 +
.../js/components/desk-document-picker.tsx | 175 +
.../js/components/desk-draft-recovery.tsx | 691 +
.../components/desk-internal-operations.tsx | 59 +-
.../components/desk-payment-document-form.tsx | 138 +
.../js/components/desk-service-history.tsx | 12 +
resources/js/components/desk-typed-choice.tsx | 88 +
resources/js/components/education-review.tsx | 229 +
.../education-submitted-snapshot.tsx | 110 +
.../funding-criteria-assessment.tsx | 197 +
.../components/investment-profile-editor.tsx | 313 +
resources/js/components/investor-guidance.tsx | 44 +-
.../opportunity-technical-incidents.tsx | 81 +
.../organization-country-editor.tsx | 233 +
.../components/organization-country-reuse.tsx | 155 +
.../partnership-agreement-instrument.tsx | 86 +
.../js/components/partnership-candidacies.tsx | 730 +
.../partnership-edit-comparison.tsx | 275 +
.../partnership-publication-summary.tsx | 85 +
.../js/components/partnership-publication.tsx | 210 +
.../partnership-room-comparison.tsx | 175 +
resources/js/components/proactive-supply.tsx | 31 +-
.../js/components/profile-navigation.tsx | 13 +
.../js/components/search-usage-report.tsx | 118 +
.../js/components/similar-businesses.tsx | 250 +-
.../technical-incident-handling.tsx | 122 +
.../components/technical-incident-notice.tsx | 108 +
resources/js/lib/business-locations.ts | 52 +
resources/js/lib/company-comparison.ts | 17 +
resources/js/lib/company-preparation.ts | 72 +
resources/js/lib/crm-record-edit.ts | 213 +
resources/js/lib/crm-task-creation.ts | 371 +
resources/js/lib/crm-task-preparation.ts | 384 +
resources/js/lib/desk-checkpoints.ts | 154 +
resources/js/lib/desk-field-values.ts | 61 +
resources/js/lib/desk-field-visibility.ts | 19 +-
resources/js/lib/education-review.ts | 388 +
resources/js/lib/investment-guides.ts | 34 +
resources/js/lib/investment-profile-editor.ts | 433 +
.../js/lib/organization-country-reuse.ts | 325 +
resources/js/lib/page-preparation-guard.ts | 28 +
resources/js/lib/partnership-agreement.ts | 63 +
.../js/lib/partnership-candidacy-edit.ts | 805 +
resources/js/lib/partnership-edit.ts | 862 +
resources/js/lib/partnership-history.ts | 26 +
resources/js/lib/partnership-publication.ts | 465 +
resources/js/lib/partnership-room-delivery.ts | 199 +
resources/js/lib/partnership-room-edit.ts | 845 +
resources/js/lib/product-experiments.ts | 107 +
resources/js/lib/product-usage.ts | 69 +
resources/js/lib/profile-json.ts | 14 +-
.../js/lib/profile-support-installation.ts | 406 +
.../js/lib/technical-incident-handling.ts | 368 +
resources/js/lib/technical-incident-labels.ts | 45 +
resources/js/pages/crm/investor.tsx | 116 +-
resources/js/pages/crm/lead.tsx | 207 +-
resources/js/pages/crm/types.ts | 3 +
resources/js/pages/dashboard.tsx | 12 +
resources/js/pages/desk/case.tsx | 240 +-
resources/js/pages/desk/catalogue.tsx | 20 +-
resources/js/pages/desk/request.tsx | 723 +-
resources/js/pages/desk/service-editor.tsx | 337 +-
resources/js/pages/education/declaration.tsx | 154 +
resources/js/pages/education/index.tsx | 728 +-
resources/js/pages/funding/show.tsx | 157 +-
.../pages/investment/business-marketplace.tsx | 82 +-
.../pages/investment/business-opportunity.tsx | 25 +-
.../js/pages/investment/business-wizard.tsx | 88 +-
resources/js/pages/investment/business.tsx | 31 +-
.../pages/investment/company-comparison.tsx | 386 +
.../pages/investment/company-preparation.tsx | 790 +
resources/js/pages/investment/guide.tsx | 676 +
resources/js/pages/investment/profile.tsx | 293 +-
.../js/pages/investment/zone-attachments.tsx | 18 +-
resources/js/pages/investor-path/index.tsx | 41 +-
resources/js/pages/investor-path/show.tsx | 23 +
.../js/pages/management/experiments/edit.tsx | 722 +
.../js/pages/management/experiments/index.tsx | 122 +
.../js/pages/management/opportunity-draft.tsx | 8 +
.../management/opportunity-resources.tsx | 6 +
.../management/proactive-supply-review.tsx | 419 +
.../js/pages/management/product-usage.tsx | 267 +
resources/js/pages/management/shared.tsx | 10 +-
.../pages/partnerships/agreement-history.tsx | 199 +
resources/js/pages/partnerships/dashboard.tsx | 51 +-
resources/js/pages/partnerships/detail.tsx | 508 +-
resources/js/pages/partnerships/editor.tsx | 848 +-
.../pages/partnerships/interest-history.tsx | 350 +
.../partnerships/publication-history.tsx | 349 +
resources/js/pages/partnerships/room.tsx | 781 +-
resources/js/pages/partnerships/shared.tsx | 6 +
resources/js/pages/portal/privacy-policy.tsx | 22 +
resources/js/pages/portal/services.tsx | 24 +-
.../js/pages/profiles/administration.tsx | 33 +-
resources/js/pages/profiles/installation.tsx | 28 +
.../pages/profiles/support-installation.tsx | 170 +
.../js/pages/profiles/technical-incident.tsx | 98 +
.../js/pages/profiles/technical-support.tsx | 150 +
resources/js/types/profile-access.ts | 2 +
.../views/desk/receipt-answers.blade.php | 9 +
resources/views/desk/receipt.blade.php | 16 +
routes/investor-path.php | 11 +
routes/partnerships.php | 3 +
routes/virtual-desk.php | 6 +
routes/web.php | 26 +
.../Feature/BusinessPointPublicationTest.php | 242 +
tests/Feature/BusinessProximitySearchTest.php | 157 +
tests/Feature/BvmAdmissionGuideTest.php | 174 +
tests/Feature/CompanyComparisonTest.php | 199 +
tests/Feature/CompanyPreparationTest.php | 198 +
tests/Feature/CrmIntakeTest.php | 12 +-
tests/Feature/CrmNextActionTest.php | 199 +
tests/Feature/CrmRecordVersionsTest.php | 140 +
tests/Feature/CrmTaskCreationTest.php | 168 +
tests/Feature/CrmTaskPreparationTest.php | 232 +
tests/Feature/DashboardWorkQueueTest.php | 275 +
tests/Feature/DeskAttachmentFieldsTest.php | 409 +
tests/Feature/DeskCaseStateTest.php | 132 +
tests/Feature/DeskClosedLifecycleTest.php | 164 +
tests/Feature/DeskDocumentReuseTest.php | 166 +
tests/Feature/DeskPaymentEvidenceTest.php | 213 +
tests/Feature/DeskRequestCheckpointTest.php | 204 +
.../Feature/DeskServiceEffectiveDatesTest.php | 198 +
tests/Feature/DeskTypedFieldsTest.php | 247 +
tests/Feature/DocumentScanRetryTest.php | 204 +
.../EducationDeclarationDraftsTest.php | 136 +
tests/Feature/EducationWorkQueueTest.php | 294 +
tests/Feature/InvestmentGuidesTest.php | 186 +
.../Feature/InvestmentProfileCommandsTest.php | 107 +
.../OpportunityCanonicalWorkflowTest.php | 120 +
.../OpportunityTechnicalIncidentsTest.php | 258 +
.../OrganizationCountryCommandsTest.php | 130 +
.../OrganizationCountryReuseCommandsTest.php | 148 +
.../PartnershipAgreementHistoryTest.php | 256 +
.../PartnershipAgreementProjectionTest.php | 235 +
.../PartnershipAgreementRecoveryTest.php | 232 +
tests/Feature/PartnershipCandidaciesTest.php | 250 +
.../PartnershipCandidacyHistoryTest.php | 204 +
.../PartnershipDashboardPrivacyTest.php | 324 +
.../Feature/PartnershipDraftRecoveryTest.php | 184 +
tests/Feature/PartnershipEditingTest.php | 211 +
tests/Feature/PartnershipParticipantsTest.php | 186 +
.../PartnershipPublicationHistoryTest.php | 223 +
.../PartnershipPublicationRecoveryTest.php | 189 +
.../PartnershipPublicationSummaryTest.php | 171 +
tests/Feature/PartnershipRoomRecoveryTest.php | 214 +
tests/Feature/ProactiveSupplyReviewTest.php | 188 +
tests/Feature/ProductExperimentsTest.php | 272 +
tests/Feature/ProductUsageMetricsTest.php | 206 +
tests/Feature/PublicSearchMetricsTest.php | 275 +
.../ResourceTechnicalIncidentsTest.php | 247 +
tests/Feature/ScanTechnicalIncidentsTest.php | 422 +
tests/Feature/SupportIncidentNoticesTest.php | 173 +
.../SupportProfileInstallationTest.php | 251 +
.../Feature/TechnicalIncidentHandlingTest.php | 200 +
.../business-point-publication.test.mjs | 426 +
.../business-proximity-catalogue.test.mjs | 177 +
tests/frontend/bvm-admission-guide.test.mjs | 296 +
tests/frontend/company-comparison.test.mjs | 335 +
tests/frontend/company-preparation.test.mjs | 389 +
tests/frontend/crm-next-action.test.mjs | 171 +
tests/frontend/crm-record-versions.test.mjs | 463 +
tests/frontend/crm-task-creation.test.mjs | 207 +
tests/frontend/crm-task-preparation.test.mjs | 326 +
tests/frontend/dashboard-work-queue.test.mjs | 274 +
tests/frontend/desk-attachments.test.mjs | 569 +
tests/frontend/desk-case-state.test.mjs | 278 +
tests/frontend/desk-checkpoints.test.mjs | 778 +
tests/frontend/desk-closed-lifecycle.test.mjs | 453 +
tests/frontend/desk-document-picker.test.mjs | 495 +
tests/frontend/desk-effective-dates.test.mjs | 349 +
tests/frontend/desk-payment-evidence.test.mjs | 310 +
.../frontend/desk-request-conditions.test.mjs | 85 +-
tests/frontend/desk-typed-fields.test.mjs | 400 +
tests/frontend/document-scan-retry.test.mjs | 143 +
tests/frontend/education-drafts.test.mjs | 367 +
tests/frontend/education-review.test.mjs | 255 +
tests/frontend/education-work-queue.test.mjs | 164 +
.../funding-criteria-assessment.test.mjs | 175 +
tests/frontend/helpers/crm-task-creation.mjs | 437 +
.../frontend/helpers/crm-task-preparation.mjs | 505 +
tests/frontend/helpers/education-review.mjs | 475 +
.../helpers/investment-profile-editor.mjs | 402 +
.../helpers/partnership-candidacy.mjs | 548 +
tests/frontend/helpers/partnership-room.mjs | 459 +
.../helpers/profile-support-installation.mjs | 378 +
.../helpers/resource-incident-form.mjs | 334 +
.../helpers/technical-incident-handling.mjs | 348 +
tests/frontend/investment-guides.test.mjs | 431 +
.../investment-profile-editor.test.mjs | 234 +
.../opportunity-technical-incidents.test.mjs | 354 +
.../organization-country-editor.test.mjs | 165 +
.../organization-country-reuse.test.mjs | 158 +
.../partnership-agreement-history.test.mjs | 284 +
.../frontend/partnership-agreements.test.mjs | 257 +
.../frontend/partnership-candidacies.test.mjs | 611 +
tests/frontend/partnership-dashboard.test.mjs | 142 +
tests/frontend/partnership-editing.test.mjs | 878 +
tests/frontend/partnership-history.test.mjs | 237 +
.../partnership-participants.test.mjs | 149 +
.../partnership-publication-history.test.mjs | 269 +
.../partnership-publication-summary.test.mjs | 244 +
.../frontend/partnership-publication.test.mjs | 267 +
.../partnership-room-recovery.test.mjs | 420 +
.../frontend/proactive-supply-review.test.mjs | 405 +
tests/frontend/product-experiments.test.mjs | 479 +
tests/frontend/product-usage.test.mjs | 131 +
.../profile-support-installation.test.mjs | 237 +
.../frontend/resource-incident-form.test.mjs | 56 +
tests/frontend/search-usage-report.test.mjs | 152 +
tests/frontend/similar-businesses.test.mjs | 126 +
.../technical-incident-handling.test.mjs | 288 +
.../technical-incident-notices.test.mjs | 102 +
tools/verify-education-draft-concurrency.php | 164 +
tools/verify-funding-concurrency.php | 42 +-
345 files changed, 110714 insertions(+), 2799 deletions(-)
create mode 100644 app/Exceptions/OpportunityWorkflowUnavailable.php
create mode 100644 app/Http/Controllers/CompanyComparisonController.php
create mode 100644 app/Http/Controllers/CompanyPreparationController.php
create mode 100644 app/Http/Controllers/DeskRequestCheckpointController.php
create mode 100644 app/Http/Controllers/EducationDeclarationDraftController.php
create mode 100644 app/Http/Controllers/InvestmentGuideController.php
create mode 100644 app/Http/Controllers/ProductExperimentController.php
create mode 100644 app/Http/Controllers/ProductUsageMetricsController.php
create mode 100644 app/Http/Controllers/TechnicalSupportController.php
create mode 100644 app/Http/Middleware/CollectPublicSearchMetrics.php
create mode 100644 app/Services/BusinessPointPublication.php
create mode 100644 app/Services/BusinessProximitySearch.php
create mode 100644 app/Services/CompanyComparison.php
create mode 100644 app/Services/CompanyPreparation.php
create mode 100644 app/Services/CrmNextAction.php
create mode 100644 app/Services/CrmTaskCreation.php
create mode 100644 app/Services/CrmTaskPreparations.php
create mode 100644 app/Services/DashboardWorkQueue.php
create mode 100644 app/Services/DeskAttachments.php
create mode 100644 app/Services/DeskPaymentEvidence.php
create mode 100644 app/Services/DeskRequestCheckpoints.php
create mode 100644 app/Services/DeskServiceAvailability.php
create mode 100644 app/Services/EducationAccess.php
create mode 100644 app/Services/EducationDeclarationDrafts.php
create mode 100644 app/Services/EducationDeclarationRules.php
create mode 100644 app/Services/EducationReviews.php
create mode 100644 app/Services/EducationWorkQueue.php
create mode 100644 app/Services/InvestmentGuides.php
create mode 100644 app/Services/InvestmentProfileCommands.php
create mode 100644 app/Services/Malware/DocumentScanAttempts.php
create mode 100644 app/Services/Malware/DocumentScanDelivery.php
create mode 100644 app/Services/Malware/DocumentScanRetry.php
create mode 100644 app/Services/OpportunityResourceFileCleanup.php
create mode 100644 app/Services/OpportunityScanDispatch.php
create mode 100644 app/Services/OpportunityTechnicalExecution.php
create mode 100644 app/Services/OpportunityTechnicalIncidents.php
create mode 100644 app/Services/OpportunityTechnicalSupport.php
create mode 100644 app/Services/OpportunityWorkflowExecution.php
create mode 100644 app/Services/PartnershipAgreementHistory.php
create mode 100644 app/Services/PartnershipAgreementProjection.php
create mode 100644 app/Services/PartnershipAgreements.php
create mode 100644 app/Services/PartnershipCandidacies.php
create mode 100644 app/Services/PartnershipCandidacyHistory.php
create mode 100644 app/Services/PartnershipDraftSaves.php
create mode 100644 app/Services/PartnershipMilestones.php
create mode 100644 app/Services/PartnershipNotifications.php
create mode 100644 app/Services/PartnershipPublication.php
create mode 100644 app/Services/PartnershipPublicationHistory.php
create mode 100644 app/Services/PartnershipRoomUploads.php
create mode 100644 app/Services/ProductExperiments.php
create mode 100644 app/Services/ProductUsageMetrics.php
create mode 100644 app/Services/PublicBusinessLocations.php
create mode 100644 app/Services/PublicSearchMetrics.php
create mode 100644 app/Services/TechnicalIncidentHandling.php
create mode 100644 app/Services/TechnicalSupportProfileSchema.php
create mode 100644 config/bvm-admission-guide.php
create mode 100644 config/company-comparison.php
create mode 100644 config/investment-guides.php
create mode 100644 config/product-experiments.php
create mode 100644 config/product-metrics.php
create mode 100644 config/search-metrics.php
create mode 100644 database/migrations/2026_11_02_230000_education_declaration_drafts.php
create mode 100644 database/migrations/2026_11_03_000000_existing_business_location_sources.php
create mode 100644 database/migrations/2026_11_03_010000_desk_service_effective_dates.php
create mode 100644 database/migrations/2026_11_03_020000_create_product_experiments.php
create mode 100644 database/migrations/2026_11_03_030000_create_product_search_counts.php
create mode 100644 database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php
create mode 100644 database/migrations/2026_11_03_050000_scope_desk_document_links.php
create mode 100644 database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php
create mode 100644 database/migrations/2026_11_03_070000_create_crm_task_preparations.php
create mode 100644 database/migrations/2026_11_03_080000_add_technical_support_profile.php
create mode 100644 resources/js/components/business-point-summary.tsx
create mode 100644 resources/js/components/crm-edit-comparison.tsx
create mode 100644 resources/js/components/crm-task-creation.tsx
create mode 100644 resources/js/components/dashboard-work-queue.tsx
create mode 100644 resources/js/components/desk-attachment-field.tsx
create mode 100644 resources/js/components/desk-case-state-form.tsx
create mode 100644 resources/js/components/desk-document-picker.tsx
create mode 100644 resources/js/components/desk-draft-recovery.tsx
create mode 100644 resources/js/components/desk-payment-document-form.tsx
create mode 100644 resources/js/components/desk-typed-choice.tsx
create mode 100644 resources/js/components/education-review.tsx
create mode 100644 resources/js/components/education-submitted-snapshot.tsx
create mode 100644 resources/js/components/funding-criteria-assessment.tsx
create mode 100644 resources/js/components/investment-profile-editor.tsx
create mode 100644 resources/js/components/opportunity-technical-incidents.tsx
create mode 100644 resources/js/components/organization-country-editor.tsx
create mode 100644 resources/js/components/organization-country-reuse.tsx
create mode 100644 resources/js/components/partnership-agreement-instrument.tsx
create mode 100644 resources/js/components/partnership-candidacies.tsx
create mode 100644 resources/js/components/partnership-edit-comparison.tsx
create mode 100644 resources/js/components/partnership-publication-summary.tsx
create mode 100644 resources/js/components/partnership-publication.tsx
create mode 100644 resources/js/components/partnership-room-comparison.tsx
create mode 100644 resources/js/components/search-usage-report.tsx
create mode 100644 resources/js/components/technical-incident-handling.tsx
create mode 100644 resources/js/components/technical-incident-notice.tsx
create mode 100644 resources/js/lib/company-comparison.ts
create mode 100644 resources/js/lib/company-preparation.ts
create mode 100644 resources/js/lib/crm-record-edit.ts
create mode 100644 resources/js/lib/crm-task-creation.ts
create mode 100644 resources/js/lib/crm-task-preparation.ts
create mode 100644 resources/js/lib/desk-checkpoints.ts
create mode 100644 resources/js/lib/desk-field-values.ts
create mode 100644 resources/js/lib/education-review.ts
create mode 100644 resources/js/lib/investment-guides.ts
create mode 100644 resources/js/lib/investment-profile-editor.ts
create mode 100644 resources/js/lib/organization-country-reuse.ts
create mode 100644 resources/js/lib/page-preparation-guard.ts
create mode 100644 resources/js/lib/partnership-agreement.ts
create mode 100644 resources/js/lib/partnership-candidacy-edit.ts
create mode 100644 resources/js/lib/partnership-edit.ts
create mode 100644 resources/js/lib/partnership-history.ts
create mode 100644 resources/js/lib/partnership-publication.ts
create mode 100644 resources/js/lib/partnership-room-delivery.ts
create mode 100644 resources/js/lib/partnership-room-edit.ts
create mode 100644 resources/js/lib/product-experiments.ts
create mode 100644 resources/js/lib/product-usage.ts
create mode 100644 resources/js/lib/profile-support-installation.ts
create mode 100644 resources/js/lib/technical-incident-handling.ts
create mode 100644 resources/js/lib/technical-incident-labels.ts
create mode 100644 resources/js/pages/education/declaration.tsx
create mode 100644 resources/js/pages/investment/company-comparison.tsx
create mode 100644 resources/js/pages/investment/company-preparation.tsx
create mode 100644 resources/js/pages/investment/guide.tsx
create mode 100644 resources/js/pages/management/experiments/edit.tsx
create mode 100644 resources/js/pages/management/experiments/index.tsx
create mode 100644 resources/js/pages/management/proactive-supply-review.tsx
create mode 100644 resources/js/pages/management/product-usage.tsx
create mode 100644 resources/js/pages/partnerships/agreement-history.tsx
create mode 100644 resources/js/pages/partnerships/interest-history.tsx
create mode 100644 resources/js/pages/partnerships/publication-history.tsx
create mode 100644 resources/js/pages/profiles/support-installation.tsx
create mode 100644 resources/js/pages/profiles/technical-incident.tsx
create mode 100644 resources/js/pages/profiles/technical-support.tsx
create mode 100644 tests/Feature/BusinessPointPublicationTest.php
create mode 100644 tests/Feature/BusinessProximitySearchTest.php
create mode 100644 tests/Feature/BvmAdmissionGuideTest.php
create mode 100644 tests/Feature/CompanyComparisonTest.php
create mode 100644 tests/Feature/CompanyPreparationTest.php
create mode 100644 tests/Feature/CrmNextActionTest.php
create mode 100644 tests/Feature/CrmRecordVersionsTest.php
create mode 100644 tests/Feature/CrmTaskCreationTest.php
create mode 100644 tests/Feature/CrmTaskPreparationTest.php
create mode 100644 tests/Feature/DashboardWorkQueueTest.php
create mode 100644 tests/Feature/DeskAttachmentFieldsTest.php
create mode 100644 tests/Feature/DeskCaseStateTest.php
create mode 100644 tests/Feature/DeskClosedLifecycleTest.php
create mode 100644 tests/Feature/DeskDocumentReuseTest.php
create mode 100644 tests/Feature/DeskPaymentEvidenceTest.php
create mode 100644 tests/Feature/DeskRequestCheckpointTest.php
create mode 100644 tests/Feature/DeskServiceEffectiveDatesTest.php
create mode 100644 tests/Feature/DeskTypedFieldsTest.php
create mode 100644 tests/Feature/DocumentScanRetryTest.php
create mode 100644 tests/Feature/EducationDeclarationDraftsTest.php
create mode 100644 tests/Feature/EducationWorkQueueTest.php
create mode 100644 tests/Feature/InvestmentGuidesTest.php
create mode 100644 tests/Feature/InvestmentProfileCommandsTest.php
create mode 100644 tests/Feature/OpportunityTechnicalIncidentsTest.php
create mode 100644 tests/Feature/OrganizationCountryCommandsTest.php
create mode 100644 tests/Feature/OrganizationCountryReuseCommandsTest.php
create mode 100644 tests/Feature/PartnershipAgreementHistoryTest.php
create mode 100644 tests/Feature/PartnershipAgreementProjectionTest.php
create mode 100644 tests/Feature/PartnershipAgreementRecoveryTest.php
create mode 100644 tests/Feature/PartnershipCandidaciesTest.php
create mode 100644 tests/Feature/PartnershipCandidacyHistoryTest.php
create mode 100644 tests/Feature/PartnershipDashboardPrivacyTest.php
create mode 100644 tests/Feature/PartnershipDraftRecoveryTest.php
create mode 100644 tests/Feature/PartnershipEditingTest.php
create mode 100644 tests/Feature/PartnershipParticipantsTest.php
create mode 100644 tests/Feature/PartnershipPublicationHistoryTest.php
create mode 100644 tests/Feature/PartnershipPublicationRecoveryTest.php
create mode 100644 tests/Feature/PartnershipPublicationSummaryTest.php
create mode 100644 tests/Feature/PartnershipRoomRecoveryTest.php
create mode 100644 tests/Feature/ProactiveSupplyReviewTest.php
create mode 100644 tests/Feature/ProductExperimentsTest.php
create mode 100644 tests/Feature/ProductUsageMetricsTest.php
create mode 100644 tests/Feature/PublicSearchMetricsTest.php
create mode 100644 tests/Feature/ResourceTechnicalIncidentsTest.php
create mode 100644 tests/Feature/ScanTechnicalIncidentsTest.php
create mode 100644 tests/Feature/SupportIncidentNoticesTest.php
create mode 100644 tests/Feature/SupportProfileInstallationTest.php
create mode 100644 tests/Feature/TechnicalIncidentHandlingTest.php
create mode 100644 tests/frontend/business-point-publication.test.mjs
create mode 100644 tests/frontend/business-proximity-catalogue.test.mjs
create mode 100644 tests/frontend/bvm-admission-guide.test.mjs
create mode 100644 tests/frontend/company-comparison.test.mjs
create mode 100644 tests/frontend/company-preparation.test.mjs
create mode 100644 tests/frontend/crm-next-action.test.mjs
create mode 100644 tests/frontend/crm-record-versions.test.mjs
create mode 100644 tests/frontend/crm-task-creation.test.mjs
create mode 100644 tests/frontend/crm-task-preparation.test.mjs
create mode 100644 tests/frontend/dashboard-work-queue.test.mjs
create mode 100644 tests/frontend/desk-attachments.test.mjs
create mode 100644 tests/frontend/desk-case-state.test.mjs
create mode 100644 tests/frontend/desk-checkpoints.test.mjs
create mode 100644 tests/frontend/desk-closed-lifecycle.test.mjs
create mode 100644 tests/frontend/desk-document-picker.test.mjs
create mode 100644 tests/frontend/desk-effective-dates.test.mjs
create mode 100644 tests/frontend/desk-payment-evidence.test.mjs
create mode 100644 tests/frontend/desk-typed-fields.test.mjs
create mode 100644 tests/frontend/document-scan-retry.test.mjs
create mode 100644 tests/frontend/education-drafts.test.mjs
create mode 100644 tests/frontend/education-review.test.mjs
create mode 100644 tests/frontend/education-work-queue.test.mjs
create mode 100644 tests/frontend/funding-criteria-assessment.test.mjs
create mode 100644 tests/frontend/helpers/crm-task-creation.mjs
create mode 100644 tests/frontend/helpers/crm-task-preparation.mjs
create mode 100644 tests/frontend/helpers/education-review.mjs
create mode 100644 tests/frontend/helpers/investment-profile-editor.mjs
create mode 100644 tests/frontend/helpers/partnership-candidacy.mjs
create mode 100644 tests/frontend/helpers/partnership-room.mjs
create mode 100644 tests/frontend/helpers/profile-support-installation.mjs
create mode 100644 tests/frontend/helpers/resource-incident-form.mjs
create mode 100644 tests/frontend/helpers/technical-incident-handling.mjs
create mode 100644 tests/frontend/investment-guides.test.mjs
create mode 100644 tests/frontend/investment-profile-editor.test.mjs
create mode 100644 tests/frontend/opportunity-technical-incidents.test.mjs
create mode 100644 tests/frontend/organization-country-editor.test.mjs
create mode 100644 tests/frontend/organization-country-reuse.test.mjs
create mode 100644 tests/frontend/partnership-agreement-history.test.mjs
create mode 100644 tests/frontend/partnership-agreements.test.mjs
create mode 100644 tests/frontend/partnership-candidacies.test.mjs
create mode 100644 tests/frontend/partnership-dashboard.test.mjs
create mode 100644 tests/frontend/partnership-editing.test.mjs
create mode 100644 tests/frontend/partnership-history.test.mjs
create mode 100644 tests/frontend/partnership-participants.test.mjs
create mode 100644 tests/frontend/partnership-publication-history.test.mjs
create mode 100644 tests/frontend/partnership-publication-summary.test.mjs
create mode 100644 tests/frontend/partnership-publication.test.mjs
create mode 100644 tests/frontend/partnership-room-recovery.test.mjs
create mode 100644 tests/frontend/proactive-supply-review.test.mjs
create mode 100644 tests/frontend/product-experiments.test.mjs
create mode 100644 tests/frontend/product-usage.test.mjs
create mode 100644 tests/frontend/profile-support-installation.test.mjs
create mode 100644 tests/frontend/resource-incident-form.test.mjs
create mode 100644 tests/frontend/search-usage-report.test.mjs
create mode 100644 tests/frontend/technical-incident-handling.test.mjs
create mode 100644 tests/frontend/technical-incident-notices.test.mjs
create mode 100644 tools/verify-education-draft-concurrency.php
diff --git a/AGENTS.md b/AGENTS.md
index 84c44e9e..362a59df 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,5 +1,9 @@
# Instruções permanentes do projeto InvesteMoz
+## Encerramento e reabertura do dossier — decisão do proprietário, 03/11/2026
+
+O proprietário definiu expressamente: «o dossier tem um dono, esse é que deve executar essa acção», em resposta a quem pode encerrar e reabrir o dossier completo. Usar o dono registado no dossier e conservar a verificação do acesso efectivo existente, incluindo a representação actual quando pertence a uma organização. A condição de gestor, analista ou outro representante não substitui por inferência esse dono. Registar a decisão, motivo, versão e histórico. Encerrar ou reabrir o dossier não equivale a decidir/aprovar pedidos, conferir pagamentos ou alterar em cascata estados de documentos e tarefas.
+
## Percurso adaptativo — decisão expressa da Tempo, 23/10/2026
Carteira/projectos âncora e percurso adaptativo têm diagnósticos distintos, mas fazem parte da mesma experiência e responsabilidade de correcção. Separar o diagnóstico não autoriza adiamento, desligamento do percurso ou perda de contexto entre corredor/localização, oportunidades, associações documentadas a âncoras/clusters, dossier e simulador. A reposição prioritária só se considera demonstrada com causa delimitada e disponibilidade recuperada, reutilizando o inventário e os recibos existentes; melhorias noutro ponto não a comprovam. Consultar os registos de reposição antes de voltar a declarar causa desconhecida ou registos desaparecidos.
diff --git a/app/Exceptions/OpportunityWorkflowUnavailable.php b/app/Exceptions/OpportunityWorkflowUnavailable.php
new file mode 100644
index 00000000..8bee0bb5
--- /dev/null
+++ b/app/Exceptions/OpportunityWorkflowUnavailable.php
@@ -0,0 +1,21 @@
+json(['message' => 'Não foi possível confirmar o resultado. Consulte o estado da oportunidade e dos recursos antes de repetir. '.($this->recorded ? 'Incidente técnico registado. ' : 'Não foi possível guardar o incidente; conserve esta referência. ').'Referência: '.$this->reference,
+ 'reference' => $this->reference, 'incident_recorded' => $this->recorded], 503)->header('Cache-Control', 'private, no-store');
+ }
+}
diff --git a/app/Http/Controllers/Api/V1/OpportunityController.php b/app/Http/Controllers/Api/V1/OpportunityController.php
index 17a3333f..6b208018 100644
--- a/app/Http/Controllers/Api/V1/OpportunityController.php
+++ b/app/Http/Controllers/Api/V1/OpportunityController.php
@@ -7,6 +7,7 @@ use App\Models\Opportunity;
use App\Services\InvestmentCatalogue;
use App\Services\OpportunityMaturity;
use App\Services\OpportunityTextSearch;
+use App\Services\PublicSearchMetrics;
use App\Services\SectorOrganization;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -63,6 +64,7 @@ class OpportunityController extends Controller
$results = $query->orderByDesc('is_featured')
->orderByDesc('published_at')
->paginate($validated['per_page'] ?? 12);
+ app(PublicSearchMetrics::class)->candidate($request, 'opportunities_api', $results->total(), $validated);
return response()->json($results->withQueryString()->through(fn ($record) => app(InvestmentCatalogue::class)->presentLocation($record)));
}
diff --git a/app/Http/Controllers/CompanyComparisonController.php b/app/Http/Controllers/CompanyComparisonController.php
new file mode 100644
index 00000000..a6677db4
--- /dev/null
+++ b/app/Http/Controllers/CompanyComparisonController.php
@@ -0,0 +1,33 @@
+answers($request->all());
+ $data = ['definition' => $service->definition(), 'answers' => $answers, 'result' => $service->evaluate($answers),
+ 'case' => null, 'saved' => null, 'canWrite' => false, 'history' => [], 'historyNext' => null, 'historical' => false, 'workingCopy' => false];
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/company-comparison', $data);
+ }
+
+ public function show(Request $request, string $id, CompanyComparison $service): Response|JsonResponse
+ {
+ $data = ['definition' => $service->definition(), ...$service->view($request->user(), $id, $request->all())];
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/company-comparison', $data);
+ }
+
+ public function save(Request $request, string $id, CompanyComparison $service): JsonResponse
+ {
+ return response()->json($service->save($request->user(), $id, $request->all()));
+ }
+}
diff --git a/app/Http/Controllers/CompanyPreparationController.php b/app/Http/Controllers/CompanyPreparationController.php
new file mode 100644
index 00000000..ab981811
--- /dev/null
+++ b/app/Http/Controllers/CompanyPreparationController.php
@@ -0,0 +1,24 @@
+view($request->user(), $id, $request->all());
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/company-preparation', $data);
+ }
+
+ public function save(Request $request, string $id, CompanyPreparation $service): JsonResponse
+ {
+ return response()->json($service->save($request->user(), $id, $request->all()));
+ }
+}
diff --git a/app/Http/Controllers/CrmController.php b/app/Http/Controllers/CrmController.php
index b94fd90a..4cc0c352 100644
--- a/app/Http/Controllers/CrmController.php
+++ b/app/Http/Controllers/CrmController.php
@@ -10,9 +10,14 @@ use App\Models\Lead;
use App\Models\User;
use App\Services\ConvertInterestToLead;
use App\Services\CountryCatalogue;
+use App\Services\CrmNextAction;
+use App\Services\CrmTaskCreation;
+use App\Services\CrmTaskPreparations;
use App\Services\DeclaredOriginStatistics;
use App\Services\PortalAudit;
+use App\Services\VirtualDesk;
use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -23,6 +28,12 @@ use Inertia\Response;
class CrmController extends Controller
{
+ private const VERSION_MESSAGES = [
+ 'version.required' => 'Actualize os dados para recuperar a versão deste registo antes de gravar. As suas edições foram conservadas.',
+ 'version.integer' => 'A versão do registo não foi reconhecida. Recupere os dados actuais.',
+ 'version.min' => 'A versão do registo não foi reconhecida. Recupere os dados actuais.',
+ ];
+
public function investors(Request $request): Response
{
$filters = $request->validate(['q' => ['nullable', 'string', 'max:150']]);
@@ -43,10 +54,12 @@ class CrmController extends Controller
public function saveInvestor(Request $request, Investor $investor): RedirectResponse
{
- $data = $request->validate(['legal_name' => ['required', 'string', 'max:200'],
+ $data = $request->validate(['version' => 'required|integer|min:1', 'legal_name' => ['required', 'string', 'max:200'],
'investor_type' => ['required', Rule::in(['domestic', 'foreign', 'institutional', 'individual'])],
- 'status' => ['required', Rule::in(['prospect', 'active', 'inactive'])]]);
- PortalAudit::save($investor, $data, $request->user()->id);
+ 'status' => ['required', Rule::in(['prospect', 'active', 'inactive'])]], self::VERSION_MESSAGES);
+ $version = (int) $data['version'];
+ unset($data['version']);
+ PortalAudit::save($investor, $data, $request->user()->id, $version);
return back()->with('success', 'Investidor actualizado.');
}
@@ -54,15 +67,17 @@ class CrmController extends Controller
public function saveContact(Request $request, Investor $investor, Contact $contact): RedirectResponse
{
abort_unless(DB::table('investor_contacts')->where('investor_id', $investor->id)->where('contact_id', $contact->id)->exists(), 404);
- $data = $request->validate(['full_name' => ['required', 'string', 'max:150'],
- 'email' => ['required', 'email:rfc', 'max:150'], 'phone' => ['nullable', 'string', 'max:30']]);
+ $data = $request->validate(['version' => 'required|integer|min:1', 'full_name' => ['required', 'string', 'max:150'],
+ 'email' => ['required', 'email:rfc', 'max:150'], 'phone' => ['nullable', 'string', 'max:30']], self::VERSION_MESSAGES);
$data['email'] = strtolower(trim($data['email']));
- DB::transaction(function () use ($contact, $data, $request) {
+ $version = (int) $data['version'];
+ unset($data['version']);
+ DB::transaction(function () use ($contact, $data, $request, $version) {
DB::select('select pg_advisory_xact_lock(170925, hashtext(?))', [$data['email']]);
if (Contact::where('id', '!=', $contact->id)->whereRaw('lower(trim(email)) = ?', [$data['email']])->exists()) {
throw ValidationException::withMessages(['email' => 'Já existe outro contacto com este email. Reveja os registos antes de os fundir.']);
}
- PortalAudit::save($contact, $data, $request->user()->id);
+ PortalAudit::save($contact, $data, $request->user()->id, $version);
});
return back()->with('success', 'Contacto actualizado.');
@@ -82,7 +97,7 @@ class CrmController extends Controller
'owner_user_id' => ['nullable', 'integer', 'exists:users,id'],
'origin' => ['nullable', Rule::in(['unknown', ...array_column(app(CountryCatalogue::class)->all(), 'code')])]]);
$query = Lead::with(['investor:id,legal_name', 'owner:id,name'])
- ->withCount(['tasks as overdue_tasks_count' => fn ($q) => $q->whereIn('status', ['open', 'in_progress'])->where('due_at', '<', now())]);
+ ->withCount(['tasks as overdue_tasks_count' => fn ($q) => $q->availableForWork()->where('due_at', '<', now())]);
if ($term = $filters['q'] ?? null) {
$query->where(fn ($q) => $q->whereLike('title', "%{$term}%")
->orWhereHas('investor', fn ($investor) => $investor->whereLike('legal_name', "%{$term}%")));
@@ -127,29 +142,37 @@ class CrmController extends Controller
return redirect('/management/crm/leads/'.$lead->id)->with('success', 'Pedido convertido em lead com responsável e próxima acção.');
}
- public function show(Lead $lead): Response
+ public function show(Request $request, Lead $lead): Response
{
$lead->load(['investor', 'owner:id,name', 'tasks' => fn ($q) => $q->orderBy('due_at')]);
+ $caseIds = $lead->tasks->pluck('desk_case_id')->filter();
+ $closedCases = $caseIds->isEmpty() ? [] : DB::table('desk_cases')->whereIn('id', $caseIds)->whereNotNull('closed_at')->pluck('id')->all();
+ foreach ($lead->tasks as $task) {
+ $task->setAttribute('can_update', ! in_array($task->getAttribute('desk_case_id'), $closedCases, true));
+ }
$contacts = DB::table('investor_contacts')->join('contacts', 'contacts.id', '=', 'investor_contacts.contact_id')
->where('investor_id', $lead->investor_id)->whereNull('contacts.deleted_at')->get(['contacts.id', 'full_name', 'email', 'phone']);
- return Inertia::render('crm/lead', ['lead' => $lead, 'contacts' => $contacts, 'owners' => $this->owners()]);
+ return Inertia::render('crm/lead', ['lead' => $lead, 'contacts' => $contacts, 'owners' => $this->owners(), 'taskCreation' => app(CrmTaskCreation::class)->context($request->user(), $lead),
+ 'nextAction' => ['future_tasks' => app(CrmNextAction::class)->future($lead)->count()]]);
}
public function update(Request $request, Lead $lead): RedirectResponse
{
- $data = $request->validate(['owner_user_id' => ['required', 'integer', Rule::in($this->owners()->pluck('id'))],
+ $data = $request->validate(['version' => 'required|integer|min:1', 'owner_user_id' => ['required', 'integer', Rule::in($this->owners()->pluck('id'))],
'status' => ['required', Rule::in(['new', 'qualified', 'disqualified'])],
- 'qualification_reason' => ['required', 'string', 'min:10', 'max:2000']]);
- DB::transaction(function () use ($lead, $data, $request) {
+ 'qualification_reason' => ['required', 'string', 'min:10', 'max:2000']], self::VERSION_MESSAGES);
+ $version = (int) $data['version'];
+ unset($data['version']);
+ DB::transaction(function () use ($lead, $data, $request, $version) {
$lead = Lead::lockForUpdate()->findOrFail($lead->id);
if ($lead->status === 'converted') {
throw ValidationException::withMessages(['status' => 'O lead já foi convertido numa negociação.']);
}
- if ($data['status'] !== 'disqualified' && ! $lead->tasks()->whereIn('status', ['open', 'in_progress'])->where('due_at', '>', now())->exists()) {
+ if ($data['status'] !== 'disqualified' && ! app(CrmNextAction::class)->future($lead)->exists()) {
throw ValidationException::withMessages(['status' => 'Registe uma próxima acção com prazo futuro antes de activar ou qualificar o lead.']);
}
- PortalAudit::save($lead, $data, $request->user()->id);
+ PortalAudit::save($lead, $data, $request->user()->id, $version);
});
return back()->with('success', 'Lead actualizado.');
@@ -157,24 +180,39 @@ class CrmController extends Controller
public function task(Request $request, Lead $lead): RedirectResponse
{
- $data = $request->validate(['title' => ['required', 'string', 'max:200'], 'due_at' => ['required', 'date', 'after:now'],
- 'assignee_user_id' => ['required', 'integer', Rule::in($this->owners()->pluck('id'))]]);
- PortalAudit::save(new CrmTask, [...$data, 'lead_id' => $lead->id, 'status' => 'open'], $request->user()->id);
+ $result = app(CrmTaskCreation::class)->create($request->user(), $lead, $request->all(), $this->owners()->pluck('id')->all());
- return back()->with('success', 'Tarefa criada.');
+ return redirect('/management/crm/leads/'.$lead->id)->with('success', $result['replayed'] ? 'A tarefa já tinha sido registada. A criação não foi repetida.' : 'Tarefa criada.');
+ }
+
+ public function taskPreparation(Request $request, Lead $lead): JsonResponse
+ {
+ // Preserve the user's partial text; business validation still occurs only on task creation.
+ $input = json_decode($request->getContent(), true);
+ if (! is_array($input)) {
+ throw ValidationException::withMessages(['snapshot' => 'A preparação deve ser enviada em JSON.']);
+ }
+
+ return response()->json(app(CrmTaskPreparations::class)->save($request->user(), $lead, $input));
}
public function updateTask(Request $request, Lead $lead, CrmTask $task): RedirectResponse
{
abort_unless($task->lead_id === $lead->id, 404);
- $data = $request->validate(['status' => ['required', Rule::in(['open', 'in_progress', 'done', 'cancelled'])]]);
- DB::transaction(function () use ($lead, $task, $data, $request) {
- $lead = Lead::lockForUpdate()->findOrFail($lead->id);
- if (in_array($lead->status, ['new', 'qualified'], true) && in_array($data['status'], ['done', 'cancelled'], true)
- && ! $lead->tasks()->where('id', '!=', $task->id)->whereIn('status', ['open', 'in_progress'])->where('due_at', '>', now())->exists()) {
- throw ValidationException::withMessages(['status' => 'Crie a próxima acção antes de encerrar a última tarefa de um lead activo.']);
+ $data = $request->validate(['version' => 'required|integer|min:1', 'status' => ['required', Rule::in(['open', 'in_progress', 'done', 'cancelled'])]], self::VERSION_MESSAGES);
+ $version = (int) $data['version'];
+ unset($data['version']);
+ DB::transaction(function () use ($lead, $task, $data, $request, $version) {
+ if ($task->getAttribute('desk_case_id')) {
+ $case = DB::table('desk_cases')->where('id', $task->getAttribute('desk_case_id'))->lockForUpdate()->first();
+ abort_unless($case !== null, 404);
+ app(VirtualDesk::class)->assertOpen($case);
}
- PortalAudit::save($task, $data, $request->user()->id);
+ $lead = Lead::lockForUpdate()->findOrFail($lead->id);
+ $task = CrmTask::lockForUpdate()->findOrFail($task->id);
+ abort_unless($task->lead_id === $lead->id, 404);
+ app(CrmNextAction::class)->assertMayFinish($lead, $task, $data['status']);
+ PortalAudit::save($task, $data, $request->user()->id, $version);
});
return back()->with('success', 'Tarefa actualizada.');
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 5a97cab5..6cc2fec2 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Models\InterestRequest;
use App\Models\Opportunity;
use App\Models\Sector;
+use App\Services\DashboardWorkQueue;
use App\Services\InvestorPath;
use App\Services\PortalProfileAccess;
use Illuminate\Http\Request;
@@ -16,12 +17,18 @@ class DashboardController extends Controller
{
public function __invoke(Request $request): Response
{
- if (! $request->user()->can('manage-portal')) {
+ $validated = $request->validate(['interests_page' => 'sometimes|integer|min:1', 'desk_page' => 'sometimes|integer|min:1', 'crm_tasks_page' => 'sometimes|integer|min:1']);
+ $pages = [];
+ foreach (['interests_page', 'desk_page', 'crm_tasks_page'] as $key) {
+ $pages[$key] = (int) ($validated[$key] ?? 1);
+ }
+ $workQueue = app(DashboardWorkQueue::class)->forActor($request->user(), $pages);
+ if (! $request->user()->can('manage-portal') || app(PortalProfileAccess::class)->has($request->user(), 'auditor')) {
$path = app(InvestorPath::class);
$contexts = $path->contexts($request->user());
$current = $contexts ? $path->view($request->user(), $contexts[0]['id']) : null;
- return Inertia::render('dashboard', ['summary' => null, 'investorPath' => $path->available() ? [
+ return Inertia::render('dashboard', ['summary' => null, 'workQueue' => $workQueue, 'investorPath' => $path->available() ? [
'contexts' => $contexts,
'current' => $current ? ['id' => $current['case']['id'], 'next' => $current['next'],
'pending' => count(array_filter($current['steps'], fn ($step) => ! in_array($step['state'], ['completed', 'approved', 'dispensed'], true))),
@@ -36,7 +43,7 @@ class DashboardController extends Controller
$drafts = app(PortalProfileAccess::class)->scope($drafts, $request->user());
}
- return Inertia::render('dashboard', ['summary' => [
+ return Inertia::render('dashboard', ['workQueue' => $workQueue, 'summary' => [
'canCreateOpportunity' => app(PortalProfileAccess::class)->legacyWriteAllowed($request->user()),
'requestsByStatus' => collect(['received', 'in_review', 'contacted', 'closed'])
->mapWithKeys(fn ($status) => [$status => (int) ($counts[$status] ?? 0)]),
diff --git a/app/Http/Controllers/DeskRequestCheckpointController.php b/app/Http/Controllers/DeskRequestCheckpointController.php
new file mode 100644
index 00000000..ce7d90e9
--- /dev/null
+++ b/app/Http/Controllers/DeskRequestCheckpointController.php
@@ -0,0 +1,20 @@
+json($checkpoints->show($request->user(), $id));
+ }
+
+ public function save(Request $request, string $id, DeskRequestCheckpoints $checkpoints): JsonResponse
+ {
+ return response()->json($checkpoints->save($request->user(), $id, $request->all()));
+ }
+}
diff --git a/app/Http/Controllers/DeskServiceEditorController.php b/app/Http/Controllers/DeskServiceEditorController.php
index 3a4f8d10..09bfb0b5 100644
--- a/app/Http/Controllers/DeskServiceEditorController.php
+++ b/app/Http/Controllers/DeskServiceEditorController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Services\DeskServiceAvailability;
use App\Services\DeskServiceEditor;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -13,7 +14,7 @@ final class DeskServiceEditorController extends Controller
{
public function index(Request $request, DeskServiceEditor $editor): Response|JsonResponse
{
- $data = ['services' => $editor->listing()];
+ $data = ['services' => $editor->listing(), 'schedulingAvailable' => app(DeskServiceAvailability::class)->scheduled(), 'today' => now()->toDateString(), 'calendarTimezone' => config('app.timezone')];
return $request->expectsJson() ? response()->json($data) : Inertia::render('desk/service-editor', $data);
}
@@ -22,8 +23,8 @@ final class DeskServiceEditorController extends Controller
{
$row = $editor->publish($request->user(), $code, $request->all());
- return $request->expectsJson() ? response()->json(['id' => $row->id, 'version' => $row->version], 201)
- : back()->with('success', 'Nova versão publicada para pedidos futuros. Os pedidos existentes conservam a sua versão.');
+ return $request->expectsJson() ? response()->json(['id' => $row->id, 'version' => $row->version, 'effective_from' => $row->effective_from ?? null], 201)
+ : back()->with('success', 'Versão publicada'.(($row->effective_from ?? null) ? ' com entrada em vigor em '.$row->effective_from : '').'. Os pedidos existentes conservam a sua versão.');
}
public function history(Request $request, DeskServiceEditor $editor, string $code): JsonResponse
diff --git a/app/Http/Controllers/DocumentMalwareController.php b/app/Http/Controllers/DocumentMalwareController.php
index 26c3ebf3..9276ba2d 100644
--- a/app/Http/Controllers/DocumentMalwareController.php
+++ b/app/Http/Controllers/DocumentMalwareController.php
@@ -2,28 +2,28 @@
namespace App\Http\Controllers;
-use App\Jobs\ScanDocumentForMalware;
-use App\Services\DocumentManagementAccess;
+use App\Services\Malware\DocumentScanRetry;
+use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
-use Illuminate\Support\Facades\DB;
class DocumentMalwareController extends Controller
{
- public function retry(Request $request, string $id): RedirectResponse
+ public function retry(Request $request, string $id): RedirectResponse|JsonResponse
{
- DB::transaction(function () use ($id, $request): void {
- $document = app(DocumentManagementAccess::class)->documents($request->user())->where('id', $id)->lockForUpdate()->first();
- abort_unless($document && $document->status !== 'deleted' && $document->deleted_at === null, 404);
- abort_unless(in_array($document->malware_scan_status, ['pending', 'inconclusive', 'failed'], true), 422,
- 'Só é possível repetir uma análise pendente, inconclusiva ou falhada. Para substituir um ficheiro, carregue uma nova versão.');
+ $result = app(DocumentScanRetry::class)->request($request->user(), $id);
+ $message = match ($result['outcome']) {
+ 'accepted' => 'Pedido de análise aceite pelo serviço de envio. Acompanhe o estado do ficheiro até haver resultado.',
+ 'duplicate' => 'Já existe uma reserva de análise para este ficheiro. Não foi enviado outro pedido. Acompanhe o estado antes de repetir.',
+ 'stale' => 'O ficheiro ou o seu acesso mudou. Actualize a página para consultar o estado antes de repetir.',
+ 'unconfirmed' => 'Não foi possível confirmar o envio da análise. Consulte o estado antes de repetir. Referência: '.$result['reference'],
+ default => 'Pedido preparado para envio após a confirmação da gravação. Acompanhe o estado do ficheiro.',
+ };
- DB::table('documents')->where('id', $id)->update([
- 'status' => 'quarantined', 'malware_scan_status' => 'pending', 'malware_failure_reason' => null, 'updated_at' => now(),
- ]);
- ScanDocumentForMalware::dispatch($id)->afterCommit();
- });
+ if ($request->expectsJson()) {
+ return response()->json([...$result, 'message' => $message], $result['outcome'] === 'unconfirmed' ? 503 : 200)->header('Cache-Control', 'no-store, private');
+ }
- return back()->with('success', 'Nova análise colocada na fila. O ficheiro permanece privado até haver resultado.');
+ return back()->with($result['outcome'] === 'accepted' ? 'success' : 'warning', $message);
}
}
diff --git a/app/Http/Controllers/EducationController.php b/app/Http/Controllers/EducationController.php
index aa04ee83..dd7a40a0 100644
--- a/app/Http/Controllers/EducationController.php
+++ b/app/Http/Controllers/EducationController.php
@@ -11,11 +11,19 @@ use App\Models\Sector;
use App\Models\Skill;
use App\Models\TrainingCapacity;
use App\Models\TrainingProvider;
+use App\Models\User;
+use App\Services\EducationAccess;
+use App\Services\EducationDeclarationDrafts;
+use App\Services\EducationDeclarationRules;
use App\Services\EducationGapCalculator;
+use App\Services\EducationReviews;
+use App\Services\EducationWorkQueue;
use App\Services\InvestmentGeography;
use App\Services\PortalAudit;
+use Carbon\CarbonImmutable;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
@@ -23,16 +31,23 @@ use Inertia\Response;
class EducationController extends Controller
{
- public function index(Request $request): Response
+ public function index(Request $request): \Symfony\Component\HttpFoundation\Response
{
- $filters = $request->validate([
- 'q' => ['nullable', 'string', 'max:150'],
- 'status' => ['nullable', Rule::in(['submitted', 'reviewed', 'rejected', 'expired'])],
- 'geo_location_id' => ['nullable', 'uuid', Rule::exists('geo_locations', 'id')->whereNull('deleted_at')],
- 'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid'],
- 'demand_page' => ['nullable', 'integer', 'min:1'],
- 'capacity_page' => ['nullable', 'integer', 'min:1'],
- ]);
+ app(EducationAccess::class)->authorize($request->user());
+ $filters = $this->filters($request);
+ if (($filters['scope'] ?? 'all') === 'review') {
+ unset($filters['status']);
+ }
+ $draftService = app(EducationDeclarationDrafts::class);
+ $draftsAvailable = $draftService->installed();
+ $selectedDraft = null;
+ if (! empty($filters['draft'])) {
+ abort_unless($draftsAvailable, 404);
+ $kind = DB::table('education_declaration_drafts')->where('id', $filters['draft'])->where('owner_user_id', $request->user()->id)->value('kind');
+ abort_unless($kind !== null, 404);
+ $selectedDraft = $draftService->show($request->user(), $kind, $filters['draft']);
+ }
+ Inertia::encryptHistory();
$demands = LabourDemand::query();
$capacities = TrainingCapacity::query();
$territoryIds = [];
@@ -53,20 +68,36 @@ class EducationController extends Controller
}
}
+ // Viewing one's work must not remove existing territorial catalogue evidence.
$territorialCapacities = clone $capacities;
+ foreach ([$demands, $capacities] as $query) {
+ if (($filters['scope'] ?? 'all') === 'mine') {
+ $query->where('submitted_by', $request->user()->id);
+ } elseif (($filters['scope'] ?? 'all') === 'review') {
+ $query->where('submitted_by', '<>', $request->user()->id)->where('status', 'submitted')->where('valid_until', '>=', now()->toDateString());
+ }
+ }
$providers = TrainingProvider::where('status', '!=', 'inactive');
$courses = Course::where('status', '!=', 'retired')
->whereIn('provider_id', TrainingProvider::where('status', '!=', 'inactive')->select('id'));
if ($territoryIds !== []) {
- // Provider and course location is evidenced by their submitted training capacity.
- // Do not infer locations from provider names, addresses, or unrelated records.
$courses->whereIn('id', $territorialCapacities->select('course_id'));
$providers->whereIn('id', (clone $courses)->select('provider_id'));
}
- return Inertia::render('education/index', [
- 'demands' => $demands->latest()->orderBy('id')->paginate(20, ['*'], 'demand_page')->withQueryString(),
- 'capacities' => $capacities->latest()->orderBy('id')->paginate(20, ['*'], 'capacity_page')->withQueryString(),
+ return tap(Inertia::render('education/index', [
+ 'workQueue' => app(EducationWorkQueue::class)->summary($request->user()),
+ 'draftsAvailable' => $draftsAvailable, 'selectedDraft' => $selectedDraft,
+ 'ownDrafts' => $draftsAvailable ? DB::table('education_declaration_drafts')->where('owner_user_id', $request->user()->id)
+ ->orderByDesc('updated_at')->orderBy('id')->paginate(20, ['id', 'kind', 'version_no', 'state', 'updated_at', 'payload'], 'draft_page')->withQueryString()
+ ->through(function ($row) {
+ $payload = json_decode(Crypt::decryptString($row->payload), true, 512, JSON_THROW_ON_ERROR);
+
+ return ['id' => $row->id, 'kind' => $row->kind, 'version_no' => (int) $row->version_no, 'state' => $row->state,
+ 'updated_at' => CarbonImmutable::parse($row->updated_at)->toIso8601String(), 'label' => $payload['qualification'] ?? null];
+ }) : null,
+ 'demands' => $demands->latest()->orderBy('id')->paginate(20, ['*'], 'demand_page')->withQueryString()->through(fn (LabourDemand $row) => $this->listing($row, 'demands', $request, $filters)),
+ 'capacities' => $capacities->latest()->orderBy('id')->paginate(20, ['*'], 'capacity_page')->withQueryString()->through(fn (TrainingCapacity $row) => $this->listing($row, 'capacities', $request, $filters)),
'filters' => $filters,
'indicators' => [
'demand_records' => LabourDemand::count(),
@@ -83,9 +114,62 @@ class EducationController extends Controller
->whereIn('location_type', ['province', 'district', 'admin_post', 'locality'])
->orderBy('name')->get(['id', 'name', 'parent_id', 'location_type']),
'today' => now()->toDateString(),
+ ])->toResponse($request), static fn (\Symfony\Component\HttpFoundation\Response $response) => $response->headers->set('Cache-Control', 'private, no-store'));
+ }
+
+ /** @return array */
+ private function filters(Request $request): array
+ {
+ return $request->validate([
+ 'q' => ['nullable', 'string', 'max:150'],
+ 'status' => ['nullable', Rule::in(['submitted', 'reviewed', 'rejected', 'expired'])],
+ 'geo_location_id' => ['nullable', 'uuid', Rule::exists('geo_locations', 'id')->whereNull('deleted_at')],
+ 'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid'],
+ 'demand_page' => ['nullable', 'integer', 'min:1'],
+ 'capacity_page' => ['nullable', 'integer', 'min:1'],
+ 'draft' => ['nullable', 'uuid'], 'draft_page' => ['nullable', 'integer', 'min:1'],
+ 'scope' => ['nullable', Rule::in(['all', 'mine', 'review'])],
]);
}
+ /** @param array $filters
+ * @return array */
+ private function listing(LabourDemand|TrainingCapacity $record, string $kind, Request $request, array $filters): array
+ {
+ $unavailable = $record->getAttribute('valid_until') < now()->toDateString() ? 'expired' : ((int) $record->getAttribute('submitted_by') === $request->user()->id ? 'self' : null);
+
+ return [...$record->toArray(), 'can_review' => $unavailable === null, 'review_unavailable' => $unavailable,
+ 'details_url' => route('management.education.declaration', ['kind' => $kind, 'id' => $record->id, ...$filters], false)];
+ }
+
+ public function declaration(Request $request, string $kind, string $id): \Symfony\Component\HttpFoundation\Response
+ {
+ app(EducationAccess::class)->authorize($request->user());
+ $model = match ($kind) {
+ 'demands' => LabourDemand::class,'capacities' => TrainingCapacity::class,default => abort(404)
+ };
+ $record = $model::findOrFail($id);
+ $filters = $this->filters($request);
+ $request->validate(['history_page' => ['nullable', 'integer', 'min:1']]);
+ $row = $this->listing($record, $kind, $request, $filters);
+ $row['review_context'] = app(EducationReviews::class)->context($request->user(), $record);
+ $row['submitted_by_name'] = User::whereKey($record->getAttribute('submitted_by'))->value('name');
+ $row['reviewed_by_name'] = $record->getAttribute('reviewed_by') ? User::whereKey($record->getAttribute('reviewed_by'))->value('name') : null;
+ $references = ['occupation' => Occupation::whereKey($record->getAttribute('occupation_id'))->value('name'),
+ 'skill' => Skill::whereKey($record->getAttribute('skill_id'))->value('name'),
+ 'location' => collect(app(InvestmentGeography::class)->path($record->getAttribute('geo_location_id'), true))->pluck('name')->implode(' › ')];
+ if ($kind === 'demands') {
+ $references['project'] = Project::whereKey($record->getAttribute('project_id'))->value('name');
+ } else {
+ $references['course'] = Course::whereKey($record->getAttribute('course_id'))->value('title');
+ }
+ Inertia::encryptHistory();
+
+ return tap(Inertia::render('education/declaration', ['declaration' => $row, 'kind' => $kind, 'actorId' => $request->user()->id, 'today' => now()->toDateString(),
+ 'history' => app(EducationReviews::class)->history($request->user(), $record),
+ 'backUrl' => route('management.education.index', $filters, false), 'references' => $references])->toResponse($request), static fn (\Symfony\Component\HttpFoundation\Response $response) => $response->headers->set('Cache-Control', 'private, no-store'));
+ }
+
public function catalog(Request $request, string $kind): RedirectResponse
{
$model = match ($kind) {
@@ -112,24 +196,7 @@ class EducationController extends Controller
public function store(Request $request, string $kind): RedirectResponse
{
$demand = $kind === 'demands';
- $data = $request->validate([
- 'occupation_id' => ['required', 'uuid', Rule::exists('occupations', 'id')->whereNull('deleted_at')],
- 'skill_id' => ['required', 'uuid', Rule::exists('skills', 'id')->whereNull('deleted_at')],
- 'geo_location_id' => ['required', 'uuid', Rule::exists('geo_locations', 'id')->whereNull('deleted_at')
- ->whereIn('location_type', ['province', 'district', 'admin_post', 'locality'])],
- $demand ? 'project_id' : 'course_id' => ['required', 'uuid', $demand
- ? Rule::exists('projects', 'id')->whereNull('deleted_at')
- : Rule::exists('courses', 'id')->whereNull('deleted_at')->whereNot('status', 'retired')
- ->where(fn ($query) => $query->whereIn('provider_id', TrainingProvider::where('status', '!=', 'inactive')->select('id')))],
- 'employer' => [$demand ? 'required' : 'exclude', 'string', 'max:200'],
- 'qualification' => ['required', 'string', 'max:150'],
- 'quantity' => ['required', 'integer', 'min:1', 'max:10000000'],
- 'period_start' => ['required', 'date_format:Y-m-d'],
- 'period_end' => ['required', 'date_format:Y-m-d', 'after_or_equal:period_start'],
- 'source' => ['required', 'string', 'min:10', 'max:5000'],
- 'reference_date' => ['required', 'date_format:Y-m-d', 'before_or_equal:today'],
- 'valid_until' => ['required', 'date_format:Y-m-d', 'after_or_equal:reference_date'],
- ]);
+ $data = $request->validate(EducationDeclarationRules::forKind($kind));
PortalAudit::save($demand ? new LabourDemand : new TrainingCapacity,
[...$data, 'submitted_by' => $request->user()->id, 'status' => 'submitted'], $request->user()->id);
@@ -138,19 +205,9 @@ class EducationController extends Controller
public function review(Request $request, string $kind, string $id): RedirectResponse
{
- $data = $request->validate(['version_no' => ['required', 'integer', 'min:1'],
- 'status' => ['required', 'in:reviewed,rejected'], 'review_reason' => ['required', 'string', 'min:15', 'max:3000']]);
- $model = $kind === 'demands' ? LabourDemand::class : TrainingCapacity::class;
- DB::transaction(function () use ($model, $id, $data, $request) {
- $record = $model::whereKey($id)->lockForUpdate()->firstOrFail();
- abort_if((int) $record->getAttribute('submitted_by') === $request->user()->id, 403, 'Outro gestor deve efectuar a revisão.');
- abort_if((int) $record->getAttribute('version_no') !== $data['version_no'], 409, 'A versão foi alterada. Recarregue antes de decidir.');
- abort_if($record->getAttribute('valid_until') < now()->toDateString(), 422, 'A fonte expirou.');
- PortalAudit::save($record, [...$data, 'version_no' => $data['version_no'] + 1,
- 'reviewed_by' => $request->user()->id], $request->user()->id);
- });
+ $result = app(EducationReviews::class)->decide($request->user(), $kind, $id, $request->all());
- return back()->with('success', 'Revisão interna registada; não substitui decisão institucional.');
+ return back()->with('success', $result['replayed'] ? 'A revisão já tinha sido registada.' : 'Revisão interna registada; não substitui decisão institucional.');
}
public function analysis(string $id, EducationGapCalculator $calculator): Response
diff --git a/app/Http/Controllers/EducationDeclarationDraftController.php b/app/Http/Controllers/EducationDeclarationDraftController.php
new file mode 100644
index 00000000..0fffb1a7
--- /dev/null
+++ b/app/Http/Controllers/EducationDeclarationDraftController.php
@@ -0,0 +1,34 @@
+guard($request->user(), $kind);
+
+ return response()->json(DB::table('education_declaration_drafts')->where('owner_user_id', $request->user()->id)->where('kind', $kind)
+ ->orderByDesc('updated_at')->orderBy('id')->paginate(20, ['id', 'kind', 'version_no', 'state', 'updated_at']))->header('Cache-Control', 'private, no-store');
+ }
+
+ public function show(Request $request, string $kind, string $id, EducationDeclarationDrafts $drafts): JsonResponse
+ {
+ return response()->json($drafts->show($request->user(), $kind, $id))->header('Cache-Control', 'private, no-store');
+ }
+
+ public function save(Request $request, string $kind, EducationDeclarationDrafts $drafts, ?string $id = null): JsonResponse
+ {
+ return response()->json($drafts->save($request->user(), $kind, $id, $request->all()))->header('Cache-Control', 'private, no-store');
+ }
+
+ public function submit(Request $request, string $kind, string $id, EducationDeclarationDrafts $drafts): JsonResponse
+ {
+ return response()->json($drafts->submit($request->user(), $kind, $id, $request->all()))->header('Cache-Control', 'private, no-store');
+ }
+}
diff --git a/app/Http/Controllers/ExistingBusinessController.php b/app/Http/Controllers/ExistingBusinessController.php
index afe6d4c4..cdcbc1e5 100644
--- a/app/Http/Controllers/ExistingBusinessController.php
+++ b/app/Http/Controllers/ExistingBusinessController.php
@@ -7,6 +7,7 @@ use App\Models\ExistingBusinessObject;
use App\Models\Sector;
use App\Policies\ExistingBusinessPolicy;
use App\Services\BusinessFormSchema;
+use App\Services\BusinessPointPublication;
use App\Services\CountryCatalogue;
use App\Services\ExistingBusinessDrafts;
use App\Services\ExistingBusinessIntake;
@@ -69,6 +70,7 @@ class ExistingBusinessController extends Controller
Gate::authorize('view', $business);
app(CompatibilityShadow::class)->schedule($id);
$props = ['countries' => app(CountryCatalogue::class)->all(), 'sectors' => Sector::choices()->orderBy('name')->get(['id', 'name', 'slug']), 'formSchema' => BusinessFormSchema::fields(), 'modalityFormType' => ExistingBusinessProfileCategory::formType($business->modality), 'record' => $this->record($business), 'canEdit' => $request->user()->can('update', $business),
+ 'pointPublicationAvailable' => app(BusinessPointPublication::class)->available(), 'registeredLocation' => app(BusinessPointPublication::class)->registered($business),
'owner' => $request->user()->can('owns', $business), 'canReview' => $request->user()->can('review', $business),
'canTriage' => $request->user()->can('triage', $business),
'canApproveLevelOne' => $request->user()->can('approveLevelOne', $business),
diff --git a/app/Http/Controllers/InvestmentDiscoveryController.php b/app/Http/Controllers/InvestmentDiscoveryController.php
index 4f62f91e..c7a94c04 100644
--- a/app/Http/Controllers/InvestmentDiscoveryController.php
+++ b/app/Http/Controllers/InvestmentDiscoveryController.php
@@ -12,6 +12,7 @@ use App\Services\InvestmentGeography;
use App\Services\InvestmentZones;
use App\Services\OpportunityCorridorExplorer;
use App\Services\OpportunityTextSearch;
+use App\Services\PublicSearchMetrics;
use App\Services\SectorInvestment;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\JsonResponse;
@@ -38,6 +39,7 @@ class InvestmentDiscoveryController extends Controller
'href' => ($request->routeIs('investment.education') ? '/educacao' : '/oportunidades').'?'.http_build_query($relatedFilters),
'items' => $catalogue->query($relatedFilters)->limit(6)->get()->map(fn ($record) => $catalogue->presentLocation($record)),
];
+ app(PublicSearchMetrics::class)->candidate($request, $request->routeIs('investment.education') ? 'education_page' : 'opportunities_page', $results->total(), $request->routeIs('investment.education') ? Arr::except($filters, ['education']) : $filters);
return Inertia::render('investment/catalogue', ['filters' => $filters, 'catalogueUrl' => $request->routeIs('investment.education') ? '/educacao' : '/oportunidades', 'references' => $catalogue->references(false, $filters),
'corridorGroups' => ($filters['view'] ?? '') === 'corridors' ? app(OpportunityCorridorExplorer::class)->groups($filters) : [],
@@ -88,7 +90,11 @@ class InvestmentDiscoveryController extends Controller
public function search(Request $request, InvestmentCatalogue $catalogue): JsonResponse
{
- return response()->json($catalogue->query($catalogue->filters($request))->paginate($request->integer('per_page', 12))->withQueryString()->through(fn ($record) => $catalogue->presentLocation($record)));
+ $filters = $catalogue->filters($request);
+ $results = $catalogue->query($filters)->paginate($request->integer('per_page', 12))->withQueryString()->through(fn ($record) => $catalogue->presentLocation($record));
+ app(PublicSearchMetrics::class)->candidate($request, 'opportunities_api', $results->total(), $filters);
+
+ return response()->json($results);
}
public function references(Request $request, InvestmentCatalogue $catalogue): JsonResponse
diff --git a/app/Http/Controllers/InvestmentGuideController.php b/app/Http/Controllers/InvestmentGuideController.php
new file mode 100644
index 00000000..c5e1498c
--- /dev/null
+++ b/app/Http/Controllers/InvestmentGuideController.php
@@ -0,0 +1,31 @@
+publicView($slug, $request->all());
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/guide', $data);
+ }
+
+ public function show(Request $request, string $id, string $slug, InvestmentGuides $guides): Response|JsonResponse
+ {
+ $data = $guides->view($request->user(), $id, $slug, $request->all());
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/guide', $data);
+ }
+
+ public function save(Request $request, string $id, string $slug, InvestmentGuides $guides): JsonResponse
+ {
+ return response()->json($guides->save($request->user(), $id, $slug, $request->all()));
+ }
+}
diff --git a/app/Http/Controllers/InvestmentPortfolioController.php b/app/Http/Controllers/InvestmentPortfolioController.php
index 14bb6f4b..a3df88a2 100644
--- a/app/Http/Controllers/InvestmentPortfolioController.php
+++ b/app/Http/Controllers/InvestmentPortfolioController.php
@@ -13,6 +13,7 @@ use App\Services\InvestmentGeography;
use App\Services\InvestmentRelations;
use App\Services\InvestmentZones;
use App\Services\PortalAudit;
+use App\Services\PublicSearchMetrics;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Http\RedirectResponse;
@@ -85,7 +86,12 @@ class InvestmentPortfolioController extends Controller
app(InvestmentGeography::class)->constrainDossiersToTerritories($query, $territoryIds);
}
- return Inertia::render('portfolio/index', ['records' => $query->orderBy('title')->paginate(30)->withQueryString(),
+ $results = $query->orderBy('title')->paginate(30)->withQueryString();
+ if (! $management) {
+ app(PublicSearchMetrics::class)->candidate($request, 'portfolio', $results->total(), $filters);
+ }
+
+ return Inertia::render('portfolio/index', ['records' => $results,
'management' => $management, 'filters' => $filters, 'sectors' => $sectorOptions, 'territorySelection' => $territorySelection]);
}
diff --git a/app/Http/Controllers/InvestmentWorkspaceController.php b/app/Http/Controllers/InvestmentWorkspaceController.php
index 10a08239..97cafe15 100644
--- a/app/Http/Controllers/InvestmentWorkspaceController.php
+++ b/app/Http/Controllers/InvestmentWorkspaceController.php
@@ -10,6 +10,7 @@ use App\Services\CountryCatalogue;
use App\Services\FundingProgrammes;
use App\Services\InvestmentGeography;
use App\Services\InvestmentOpportunityAlerts;
+use App\Services\InvestmentProfileCommands;
use App\Services\InvestmentWorkspace;
use App\Services\OpportunityManagement;
use App\Services\OrganizationCountry;
@@ -25,9 +26,9 @@ use Inertia\Response;
class InvestmentWorkspaceController extends Controller
{
- public function profile(Request $request, InvestmentWorkspace $workspace): Response|JsonResponse
+ public function profile(Request $request, InvestmentWorkspace $workspace): \Symfony\Component\HttpFoundation\Response
{
- $data = ['organizationCountryAvailable' => app(OrganizationCountry::class)->available(), 'organizations' => app(OrganizationCountry::class)->represented($request->user()), 'countries' => app(CountryCatalogue::class)->all(), 'account' => $workspace->account($request->user()->id), 'companies' => DB::table('investment_company_declarations')
+ $data = ['actorId' => $request->user()->id, 'organizationCountryAvailable' => app(OrganizationCountry::class)->available(), 'organizations' => app(OrganizationCountry::class)->represented($request->user()), 'countries' => app(CountryCatalogue::class)->all(), 'account' => $workspace->account($request->user()->id), 'companies' => DB::table('investment_company_declarations')
->where('user_id', $request->user()->id)->orderByDesc('created_at')->get(['id', 'version', 'payload'])->map(function ($company) {
$company->payload = json_decode(Crypt::decryptString($company->payload), true, 512, JSON_THROW_ON_ERROR);
$company->countrySource = $company->payload['organization_country_snapshot'] ?? null;
@@ -35,12 +36,17 @@ class InvestmentWorkspaceController extends Controller
return $company;
})];
- return $request->expectsJson() ? response()->json($data) : Inertia::render('investment/profile', $data);
+ Inertia::encryptHistory();
+
+ $response = $request->expectsJson() ? response()->json($data) : Inertia::render('investment/profile', $data)->toResponse($request);
+ $response->headers->set('Cache-Control', 'no-store, private');
+
+ return $response;
}
public function saveProfile(Request $request): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => ['required', 'integer', 'min:0'],
+ $data = $request->validate(['version' => ['required', 'integer', 'min:0'], 'operation_key' => ['sometimes', 'required', 'uuid'],
'payload' => ['required', 'array:phone,country,residence_country_code,sector,experience,investment_capacity'],
'payload.residence_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.phone' => ['nullable', 'string', 'max:30'], 'payload.country' => ['nullable', 'string', 'max:100'],
@@ -48,12 +54,19 @@ class InvestmentWorkspaceController extends Controller
'payload.investment_capacity' => ['nullable', 'string', 'max:1000']]);
$version = DB::transaction(function () use ($request, $data) {
DB::table('users')->where('id', $request->user()->id)->lockForUpdate()->firstOrFail();
+ $commands = app(InvestmentProfileCommands::class);
+ $command = ['kind' => 'account', 'target_id' => null, 'version' => (int) $data['version'], 'payload' => $data['payload']];
+ $replay = $commands->replay($request->user(), $data['operation_key'] ?? null, $command);
+ if ($replay !== null) {
+ return $replay['version'];
+ }
$row = DB::table('investment_accounts')->where('user_id', $request->user()->id)->first();
abort_unless((int) ($row->version ?? 0) === (int) $data['version'], 409, 'Perfil alterado. Recarregue.');
$version = (int) $data['version'] + 1;
DB::table('investment_accounts')->updateOrInsert(['user_id' => $request->user()->id], ['version' => $version,
'payload' => Crypt::encryptString(json_encode($data['payload'], JSON_THROW_ON_ERROR)), 'created_at' => $row->created_at ?? now(), 'updated_at' => now()]);
$this->audit($request, 'profile_saved', 'investment_accounts', null, ['version' => $version]);
+ $commands->record($request->user(), $data['operation_key'] ?? null, $command, ['version' => $version]);
return $version;
});
@@ -63,7 +76,7 @@ class InvestmentWorkspaceController extends Controller
public function company(Request $request, ?string $id = null): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => ['required', 'integer', 'min:0'],
+ $data = $request->validate(['version' => ['required', 'integer', 'min:0'], 'operation_key' => ['sometimes', 'required', 'uuid'],
'payload' => ['required', 'array:name,country,incorporation_country_code,registration,sector,role,description'],
'payload.incorporation_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.name' => ['required', 'string', 'min:2', 'max:200'], 'payload.country' => ['required_without:payload.incorporation_country_code', 'nullable', 'string', 'max:100'],
@@ -73,6 +86,12 @@ class InvestmentWorkspaceController extends Controller
DB::table('users')->where('id', $request->user()->id)->lockForUpdate()->firstOrFail();
$row = $id ? DB::table('investment_company_declarations')->where('id', $id)->where('user_id', $request->user()->id)->first() : null;
abort_if($id && ! $row, 404);
+ $commands = app(InvestmentProfileCommands::class);
+ $command = ['kind' => 'company', 'target_id' => $id, 'version' => (int) $data['version'], 'payload' => $data['payload']];
+ $replay = $commands->replay($request->user(), $data['operation_key'] ?? null, $command);
+ if ($replay !== null) {
+ return $replay;
+ }
abort_unless((int) ($row->version ?? 0) === (int) $data['version'], 409, 'Declaração alterada. Recarregue.');
abort_if(! $id && DB::table('investment_company_declarations')->where('user_id', $request->user()->id)->count() >= 20, 422, 'Máximo de vinte empresas declaradas.');
$id ??= (string) Str::uuid();
@@ -86,6 +105,7 @@ class InvestmentWorkspaceController extends Controller
DB::table('investment_company_declarations')->updateOrInsert(['id' => $id], ['user_id' => $request->user()->id, 'version' => $version,
'payload' => $encrypted, 'created_at' => $row->created_at ?? now(), 'updated_at' => now()]);
$this->audit($request, 'company_declared', 'investment_company_declarations', $id, ['version' => $version, 'before_payload' => $row?->payload, 'after_payload' => $encrypted]);
+ $commands->record($request->user(), $data['operation_key'] ?? null, $command, ['id' => $id, 'version' => $version]);
return ['id' => $id, 'version' => $version];
});
@@ -102,13 +122,25 @@ class InvestmentWorkspaceController extends Controller
public function reuseOrganizationCountry(Request $request, string $id, OrganizationCountry $service): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => 'required|integer|min:1', 'organization_id' => 'required|uuid', 'organization_version' => 'required|integer|min:1']);
+ $data = $request->validate(['version' => 'required|integer|min:1', 'organization_id' => 'required|uuid', 'organization_version' => 'required|integer|min:1', 'operation_key' => ['sometimes', 'required', 'uuid']]);
$result = DB::transaction(function () use ($request, $id, $data, $service) {
+ DB::table('users')->where('id', $request->user()->id)->lockForUpdate()->firstOrFail();
$row = DB::table('investment_company_declarations')->where('id', $id)->where('user_id', $request->user()->id)->lockForUpdate()->first();
abort_unless($row !== null, 404);
+ $snapshot = $service->readableSnapshot($request->user(), $data['organization_id']);
+ $commands = app(InvestmentProfileCommands::class);
+ $command = ['kind' => 'organization_country_reuse', 'target_id' => $row->id, 'version' => (int) $data['version'], 'payload' => ['organization_id' => $snapshot['organization_id'], 'organization_version' => (int) $data['organization_version']]];
+ $replay = $commands->replay($request->user(), $data['operation_key'] ?? null, $command);
+ if ($replay !== null) {
+ if (! isset($replay['country'])) {
+ throw new \LogicException('Stored country reuse receipt unavailable.');
+ }
+
+ return ['version' => $replay['version'], 'country' => $replay['country']];
+ }
abort_unless((int) $row->version === (int) $data['version'], 409, 'Declaração alterada. Recarregue.');
- $snapshot = $service->snapshot($request->user(), $data['organization_id']);
abort_unless((int) $snapshot['organization_version'] === (int) $data['organization_version'], 409, 'País mestre alterado. Recarregue.');
+ abort_unless($snapshot['country'] !== null, 422, 'País de constituição não informado no cadastro mestre.');
$payload = json_decode(Crypt::decryptString($row->payload), true, 512, JSON_THROW_ON_ERROR);
$payload['incorporation_country_code'] = $snapshot['country'];
$payload['organization_country_snapshot'] = $snapshot;
@@ -116,11 +148,12 @@ class InvestmentWorkspaceController extends Controller
DB::table('investment_company_declarations')->where('id', $id)->update(['payload' => $encrypted, 'version' => $row->version + 1, 'updated_at' => now()]);
$this->audit($request, 'organization_country_reused', 'investment_company_declarations', $id, ['version' => $row->version + 1,
'before_payload' => $row->payload, 'after_payload' => $encrypted, 'organization_id' => $data['organization_id'], 'organization_version' => $snapshot['organization_version']]);
+ $commands->record($request->user(), $data['operation_key'] ?? null, $command, ['version' => $row->version + 1, 'country' => $snapshot['country']]);
return ['version' => $row->version + 1, 'country' => $snapshot['country']];
});
- return $request->expectsJson() ? response()->json($result) : back()->with('success', 'País mestre reutilizado nesta declaração; manifestações anteriores não alteradas.');
+ return $request->expectsJson() ? response()->json($result)->header('Cache-Control', 'no-store, private') : back()->with('success', 'País mestre reutilizado nesta declaração; manifestações anteriores não alteradas.');
}
public function notifications(Request $request): Response|JsonResponse
diff --git a/app/Http/Controllers/InvestmentZoneController.php b/app/Http/Controllers/InvestmentZoneController.php
index a4fb336a..c52a4e40 100644
--- a/app/Http/Controllers/InvestmentZoneController.php
+++ b/app/Http/Controllers/InvestmentZoneController.php
@@ -16,6 +16,7 @@ use App\Services\InvestmentZoneOperationalProfile;
use App\Services\InvestmentZonePathContext;
use App\Services\InvestmentZoneProfileInstallation;
use App\Services\InvestmentZones;
+use App\Services\PublicSearchMetrics;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -108,6 +109,9 @@ class InvestmentZoneController extends Controller
$publicColumns = array_values(array_filter($publicColumns, fn ($column) => Schema::hasColumn('investment_zones', $column)));
$rows = $zones->search($filters, $management)->orderBy('name')->orderBy('id')
->paginate(12, $management ? ['*'] : $publicColumns)->withQueryString();
+ if (! $management) {
+ app(PublicSearchMetrics::class)->candidate($request, 'zones', $rows->total(), $filters);
+ }
$rows->getCollection()->transform(function (InvestmentZone $zone) use ($management) {
$territoryPath = app(InvestmentGeography::class)->path($zone->primary_territory_id, $management);
$zone->setAttribute('province', collect($territoryPath)->firstWhere('location_type', 'province')->name ?? $zone->province);
diff --git a/app/Http/Controllers/InvestorPathController.php b/app/Http/Controllers/InvestorPathController.php
index 774f06b8..20b69c91 100644
--- a/app/Http/Controllers/InvestorPathController.php
+++ b/app/Http/Controllers/InvestorPathController.php
@@ -2,7 +2,9 @@
namespace App\Http\Controllers;
+use App\Services\CompanyComparison;
use App\Services\FintechInvestment;
+use App\Services\InvestmentGuides;
use App\Services\InvestmentZonePathContext;
use App\Services\InvestorPath;
use App\Services\LegacyContent;
@@ -19,7 +21,9 @@ class InvestorPathController extends Controller
public function index(Request $request, InvestorPath $path): JsonResponse|Response
{
abort_unless($path->available(), 404);
- $data = ['contexts' => $path->contexts($request->user())];
+ $data = ['contexts' => $path->contexts($request->user()),
+ 'companyComparisonAnswers' => $request->has('company_comparison') ? app(CompanyComparison::class)->answers(['answers' => $request->input('company_comparison')]) : null,
+ 'guideSelection' => $request->has('investment_guide') ? app(InvestmentGuides::class)->selection($request->array('investment_guide')) : null];
return $request->expectsJson() ? response()->json($data) : Inertia::render('investor-path/index', $data);
}
@@ -57,6 +61,9 @@ class InvestorPathController extends Controller
public function create(Request $request, InvestorPath $path): JsonResponse|RedirectResponse
{
+ $comparison = $request->has('company_comparison') ? app(CompanyComparison::class)->answers(['answers' => $request->input('company_comparison')]) : null;
+ $guide = $request->has('investment_guide') ? app(InvestmentGuides::class)->selection($request->array('investment_guide')) : null;
+ abort_if($comparison !== null && $guide !== null, 422, 'Escolha o contexto de preparação que pretende continuar.');
$zone = $request->has('zone_id') ? app(InvestmentZonePathContext::class)->input($request->all()) : null;
if ($zone) {
$request->validate(['confirm' => 'required|accepted']);
@@ -92,7 +99,12 @@ class InvestorPathController extends Controller
return $id;
});
- return $request->expectsJson() ? response()->json(['id' => $id], 201) : redirect('/investimentos/'.$id)->with('success', 'Investimento guardado no seu dossier.');
+ $href = $comparison === null ? '/investimentos/'.$id : '/investimentos/'.$id.'/forma-juridica?'.http_build_query(['answers' => $comparison]);
+ if ($guide !== null) {
+ $href = '/investimentos/'.$id.'/guias/'.$guide['slug'].'?'.http_build_query(['current' => 1, 'selection' => 1, 'sha256' => $guide['sha256'], 'instruments' => $guide['instruments']]);
+ }
+
+ return $request->expectsJson() ? response()->json(['id' => $id, ...($comparison !== null ? ['comparison_href' => $href] : []), ...($guide !== null ? ['guide_href' => $href] : [])], 201) : redirect($href)->with('success', 'Investimento guardado no seu dossier.');
}
public function show(Request $request, string $id, InvestorPath $path): JsonResponse|Response
diff --git a/app/Http/Controllers/LegacyContentController.php b/app/Http/Controllers/LegacyContentController.php
index ff13232b..a1246a2c 100644
--- a/app/Http/Controllers/LegacyContentController.php
+++ b/app/Http/Controllers/LegacyContentController.php
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
use App\Services\InvestorPath;
use App\Services\LegacyContent;
+use App\Services\PublicSearchMetrics;
use App\Services\VirtualDesk;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -24,6 +25,7 @@ class LegacyContentController extends Controller
$articles = array_values(array_filter($articles, fn ($item) => $q === ''
|| str_contains(mb_strtolower(strip_tags($item['html'].' '.$item['title'])), mb_strtolower($q))));
$match = $articles !== [];
+ app(PublicSearchMetrics::class)->candidate($request, 'sector_content', count($articles), ['q' => $q]);
return Inertia::render('portal/legacy', ['article' => $article, 'articles' => $articles, 'view' => 'landing', 'query' => $q, 'match' => $match]);
}
diff --git a/app/Http/Controllers/OpportunityManagementController.php b/app/Http/Controllers/OpportunityManagementController.php
index a3f92993..f438477f 100644
--- a/app/Http/Controllers/OpportunityManagementController.php
+++ b/app/Http/Controllers/OpportunityManagementController.php
@@ -14,6 +14,7 @@ use App\Services\OpportunityMaturity;
use App\Services\OpportunityProfileWorkflow;
use App\Services\OpportunityPromotion;
use App\Services\OpportunityResources;
+use App\Services\OpportunityTechnicalIncidents;
use App\Services\OpportunityWorkflowTasks;
use App\Services\PortalProfileAccess;
use App\Services\ProactiveInvestment;
@@ -139,6 +140,7 @@ class OpportunityManagementController extends Controller
'canEditDraft' => $record ? $access->canEdit($request->user(), $record) : false,
'workflowParticipants' => $record && $record->owner_user_id !== null ? app(OpportunityProfileWorkflow::class)->participants($request->user(), $record) : ['validators' => [], 'publishers' => []],
'workflowTasks' => $record && $record->owner_user_id !== null ? app(OpportunityWorkflowTasks::class)->listing($record) : [],
+ 'workflowIncidents' => $record && $record->owner_user_id !== null ? app(OpportunityTechnicalIncidents::class)->recent($request->user(), $record) : [],
'profileMode' => $record ? $record->owner_user_id !== null : str_starts_with($request->path(), 'minhas-oportunidades'),
'profileActions' => $record && $record->owner_user_id !== null ? app(OpportunityProfileWorkflow::class)->actions($request->user(), $record) : [], 'profileContext' => $record?->workflow_context, 'profileOrganization' => $record?->organization_id]);
$values = $record ? $service->values($record) : [];
diff --git a/app/Http/Controllers/OpportunityResourceController.php b/app/Http/Controllers/OpportunityResourceController.php
index b5a66b57..b22f3c2a 100644
--- a/app/Http/Controllers/OpportunityResourceController.php
+++ b/app/Http/Controllers/OpportunityResourceController.php
@@ -10,6 +10,8 @@ use App\Services\OpportunityLibrarySupport;
use App\Services\OpportunityManagement;
use App\Services\OpportunityResourceInstallation;
use App\Services\OpportunityResources;
+use App\Services\OpportunityTechnicalExecution;
+use App\Services\OpportunityTechnicalIncidents;
use App\Services\OpportunityTerritorialPresentation;
use App\Services\OrganizationCountryInstallation;
use App\Services\PortalProfileAccess;
@@ -75,7 +77,7 @@ class OpportunityResourceController extends Controller
return hash('sha256', json_encode([$request->user()->getAuthIdentifier(), $plan['target'], $plan['migration'], $plan['code_hash']], JSON_THROW_ON_ERROR));
}
- public function index(int $id, OpportunityResources $service): Response
+ public function index(int $id, OpportunityResources $service): \Symfony\Component\HttpFoundation\Response
{
$opportunity = Opportunity::withTrashed()->findOrFail($id);
app(PortalProfileAccess::class)->authorize(request()->user(), 'view', $opportunity);
@@ -100,7 +102,9 @@ class OpportunityResourceController extends Controller
}
}
- return Inertia::render('management/opportunity-resources', ['opportunity' => $opportunity, 'etag' => app(OpportunityManagement::class)->etag($opportunity), 'resources' => $resources, 'librarySources' => ! app(PortalProfileAccess::class)->canEdit(request()->user(), $opportunity) ? [] : app(OpportunityLibrarySupport::class)->choices(request()->user()), 'existingLocations' => DB::table('opportunity_locations as l')->join('geo_locations as g', 'g.id', '=', 'l.geo_location_id')->where('opportunity_id', $id)->get(['g.id', 'g.name', 'g.location_type']), 'locationReference' => app(OpportunityTerritorialPresentation::class)->describe($opportunity, $resources['locations']), 'assessment' => $this->assessment($resources)]);
+ Inertia::encryptHistory();
+
+ return tap(Inertia::render('management/opportunity-resources', ['opportunity' => $opportunity, 'etag' => app(OpportunityManagement::class)->etag($opportunity), 'resources' => $resources, 'technicalIncidents' => app(OpportunityTechnicalIncidents::class)->recent(request()->user(), $opportunity), 'librarySources' => ! app(PortalProfileAccess::class)->canEdit(request()->user(), $opportunity) ? [] : app(OpportunityLibrarySupport::class)->choices(request()->user()), 'existingLocations' => DB::table('opportunity_locations as l')->join('geo_locations as g', 'g.id', '=', 'l.geo_location_id')->where('opportunity_id', $id)->get(['g.id', 'g.name', 'g.location_type']), 'locationReference' => app(OpportunityTerritorialPresentation::class)->describe($opportunity, $resources['locations']), 'assessment' => $this->assessment($resources)])->toResponse(request()), static fn (\Symfony\Component\HttpFoundation\Response $response) => $response->headers->set('Cache-Control', 'private, no-store'));
}
public function reuseLibrary(Request $request, int $id): JsonResponse
@@ -116,9 +120,18 @@ class OpportunityResourceController extends Controller
if (is_string($input['payload'] ?? null)) {
$input['payload'] = json_decode($input['payload'], true);
}
- $record = $service->save($request->user(), $id, $kind, $input, $request->file('file'), $resourceId);
+ $operation = function () use ($request, $id, $kind, $input, $resourceId, $service) {
+ $record = $service->save($request->user(), $id, $kind, $input, $request->file('file'), $resourceId);
- return response()->json(['id' => $record->id, 'message' => 'Recurso guardado no servidor. Não publicado; validação final e scan são independentes.', 'etag' => app(OpportunityManagement::class)->etag(Opportunity::findOrFail($id))], $resourceId ? 200 : 201);
+ return response()->json(['id' => $record->id, 'message' => 'Recurso guardado no servidor. Não publicado; validação final e scan são independentes.', 'etag' => app(OpportunityManagement::class)->etag(Opportunity::findOrFail($id))], $resourceId ? 200 : 201);
+ };
+ if (! $request->hasFile('file') || ! in_array($kind, ['documents', 'images'], true)) {
+ return $operation();
+ }
+ $before = Opportunity::withTrashed()->findOrFail($id);
+ app(PortalProfileAccess::class)->authorize($request->user(), 'edit', $before);
+
+ return app(OpportunityTechnicalExecution::class)->run($request->user(), $before, $kind === 'images' ? 'upload_image' : 'upload_document', $input, $operation);
}
public function lifecycle(Request $request, int $id, string $kind, string $resourceId, OpportunityResources $service): JsonResponse
@@ -130,9 +143,14 @@ class OpportunityResourceController extends Controller
public function prepareImage(Request $request, int $id, string $resourceId, OpportunityImageProcessor $service): JsonResponse
{
- $service->prepare($request->user(), $id, $resourceId, $request->all());
+ $before = Opportunity::withTrashed()->findOrFail($id);
+ app(PortalProfileAccess::class)->authorize($request->user(), 'edit', $before);
- return response()->json(['message' => 'Derivadas WebP geradas sem EXIF original; scan independente e revisão de divulgação pendentes.']);
+ return app(OpportunityTechnicalExecution::class)->run($request->user(), $before, 'prepare_image', $request->all(), function () use ($request, $id, $resourceId, $service) {
+ $service->prepare($request->user(), $id, $resourceId, $request->all());
+
+ return response()->json(['message' => 'Derivadas WebP geradas sem EXIF original; scan independente e revisão de divulgação pendentes.']);
+ });
}
public function previewImage(int $id, string $resourceId, string $documentId): \Illuminate\Http\Response|BinaryFileResponse
diff --git a/app/Http/Controllers/PartnershipExchangeController.php b/app/Http/Controllers/PartnershipExchangeController.php
index 87fad76a..84b91aca 100644
--- a/app/Http/Controllers/PartnershipExchangeController.php
+++ b/app/Http/Controllers/PartnershipExchangeController.php
@@ -2,26 +2,35 @@
namespace App\Http\Controllers;
-use App\Jobs\ScanDocumentForMalware;
use App\Models\ExistingBusiness;
use App\Models\Sector;
-use App\Models\User;
use App\Services\InvestmentCatalogue;
use App\Services\InvestmentGeography;
use App\Services\InvestmentRelations;
+use App\Services\PartnershipAgreementHistory;
+use App\Services\PartnershipAgreementProjection;
+use App\Services\PartnershipAgreements;
+use App\Services\PartnershipCandidacies;
+use App\Services\PartnershipCandidacyHistory;
+use App\Services\PartnershipDraftSaves;
use App\Services\PartnershipExchange;
use App\Services\PartnershipMatching;
+use App\Services\PartnershipMilestones;
+use App\Services\PartnershipNotifications;
+use App\Services\PartnershipPublication;
+use App\Services\PartnershipPublicationHistory;
+use App\Services\PartnershipRoomUploads;
use App\Services\PartnershipSources;
+use App\Services\PublicSearchMetrics;
use App\Services\SectorOrganization;
use App\Services\VerifiedDocumentBinary;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
+use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Schema;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -82,6 +91,7 @@ class PartnershipExchangeController extends Controller
}
$results = $query->orderByDesc('p.id')->select(['p.id', 'p.title', 'p.sector', 'p.province', 'p.kind', 'p.partnership_type', 'p.sector_id', 'p.deadline', 'p.published_at'])
->selectRaw("p.payload->>'summary' as summary")->paginate(12)->withQueryString();
+ app(PublicSearchMetrics::class)->candidate($request, 'partnerships', $results->total(), $filters);
if ($request->expectsJson()) {
return response()->json($results);
}
@@ -119,16 +129,23 @@ class PartnershipExchangeController extends Controller
public function dashboard(Request $request): Response
{
$actor = $request->user();
- $organizations = DB::table('memberships')->where('user_id', $actor->id)->whereNull('deleted_at')->pluck('organization_id');
+ $exchange = app(PartnershipExchange::class);
+ $organizations = $exchange->readableOrganizations($actor);
$mine = DB::table('portal_partnerships')->where(fn ($q) => $q->where(fn ($own) => $own->where('user_id', $actor->id)->whereNull('organization_id'))->orWhereIn('organization_id', $organizations))->latest()->limit(100)->get();
$interests = DB::table('partnership_interests as i')->join('portal_partnerships as p', 'p.id', '=', 'i.partnership_id')
->leftJoin('partnership_rooms as room', 'room.interest_id', '=', 'i.id')
->where(fn ($q) => $q->where(fn ($own) => $own->where('i.user_id', $actor->id)->whereNull('i.organization_id'))->orWhereIn('i.organization_id', $organizations))
- ->select(['i.id', 'i.partnership_id', 'i.status', 'i.decision_reason', 'p.title', 'room.id as room_id'])->orderByDesc('i.id')->limit(100)->get();
+ ->select(['i.id', 'i.partnership_id', 'i.status', 'i.decision_reason', 'p.title', 'p.status as partnership_status', 'p.user_id', 'p.organization_id', 'room.id as room_id'])->orderByDesc('i.id')->limit(100)->get()
+ ->map(function ($interest) use ($actor, $exchange) {
+ $canRead = $interest->partnership_status === 'published' || $exchange->owns($actor, $interest, false) || Gate::forUser($actor)->allows('manage-portal');
+
+ return ['id' => $interest->id, 'partnership_id' => $interest->partnership_id, 'status' => $interest->status, 'decision_reason' => $interest->decision_reason,
+ 'title' => $canRead ? $interest->title : null, 'partnership_href' => $canRead ? '/parcerias/'.$interest->partnership_id : null, 'room_id' => $interest->room_id];
+ });
$moderation = Gate::forUser($actor)->allows('manage-portal') ? DB::table('portal_partnerships')->whereIn('status', ['submitted', 'pending'])->orderBy('updated_at')->get(['id', 'title', 'status', 'version']) : [];
return Inertia::render('partnerships/dashboard', ['mine' => $mine->map(fn ($p) => ['id' => $p->id, 'title' => $p->title, 'status' => $p->status, 'version' => $p->version]), 'interests' => $interests, 'moderation' => $moderation,
- 'notifications' => DB::table('partnership_notifications')->where('user_id', $actor->id)->orderByDesc('id')->limit(50)->get()]);
+ 'notifications' => app(PartnershipNotifications::class)->forUser($actor)]);
}
public function edit(Request $request, ?int $id = null): Response
@@ -141,7 +158,10 @@ class PartnershipExchangeController extends Controller
$origins = [['type' => $source['type'], 'target_id' => $source['target_id']]];
}
- return Inertia::render('partnerships/editor', ['record' => $record ? [...(array) $record, 'payload' => json_decode($record->payload, true)] : null, 'origins' => $origins,
+ $payload = $record ? json_decode($record->payload, true) : [];
+ unset($payload['_creation_hash']);
+
+ return Inertia::render('partnerships/editor', ['editorActorId' => $request->user()->id, 'saveCommands' => $record ? app(PartnershipDraftSaves::class)->commands($request->user(), $record) : [], 'record' => $record ? [...(array) $record, 'payload' => $payload] : null, 'origins' => $origins,
'locations' => $record ? DB::table('partnership_locations')->where('partnership_id', $id)->get() : [], ...$this->catalogues($request)]);
}
@@ -149,7 +169,7 @@ class PartnershipExchangeController extends Controller
{
$record = app(PartnershipExchange::class)->save($request->user(), $request->all(), $id);
- return $request->expectsJson() ? response()->json(['id' => $record->id, 'version' => $record->version, 'status' => $record->status]) : redirect('/parcerias/'.$record->id.'/editar')->with('success', 'Rascunho guardado.');
+ return $request->expectsJson() ? response()->json(['id' => $record->id, 'version' => $record->version, 'status' => $record->status, 'replayed' => (bool) ($record->command_replayed ?? false), 'saved_version' => $record->command_saved_version ?? null]) : redirect('/parcerias/'.$record->id.'/editar')->with('success', 'Rascunho guardado.');
}
public function show(Request $request, int $id): Response|JsonResponse
@@ -163,17 +183,23 @@ class PartnershipExchangeController extends Controller
$privateDetails = ($payload['confidentiality'] ?? 'public') === 'private' && ! $owner && ! $moderator;
$mine = $request->user() ? DB::table('partnership_interests')->where('partnership_id', $id)->get()->filter(fn ($i) => app(PartnershipExchange::class)->owns($request->user(), $i, false))->values() : collect();
$interests = $owner ? DB::table('partnership_interests')->where('partnership_id', $id)->orderBy('id')->get() : $mine;
- $interestData = $interests->map(function ($interest) use ($record) {
+ $commands = $request->user() ? app(PartnershipCandidacies::class)->commands($request->user(), $id) : [];
+ $interestData = $interests->map(function ($interest) use ($record, $request, $commands) {
return [...(array) $interest, 'payload' => json_decode($interest->payload, true), 'assessment' => json_decode($interest->assessment, true),
+ 'can_edit' => $request->user() && app(PartnershipExchange::class)->owns($request->user(), $interest), 'commands' => $commands[(int) $interest->id] ?? [],
'match' => app(PartnershipMatching::class)->explain($record, $interest), 'room_id' => DB::table('partnership_rooms')->where('interest_id', $interest->id)->value('id')];
});
$props = ['record' => ['id' => $record->id, 'title' => $record->title, 'status' => $record->status, 'version' => $record->version, 'kind' => $record->kind,
'partnership_type' => $record->partnership_type, 'sector' => $record->sector, 'province' => $record->province, 'sector_id' => $record->sector_id, 'deadline' => $record->deadline,
'offer' => $privateDetails ? null : $record->offer, 'seeking' => $privateDetails ? null : $record->seeking, 'payload' => $privateDetails ? ['summary' => $payload['summary'] ?? '', 'confidentiality' => 'private'] : $payload],
'owner' => (bool) $owner, 'canEdit' => $request->user() && app(PartnershipExchange::class)->owns($request->user(), $record), 'moderator' => (bool) $moderator,
+ 'acceptingInterests' => app(PartnershipCandidacies::class)->accepting($record),
+ 'canStartInterest' => $request->user() && ! $owner && ! DB::table('partnership_interests')->where('partnership_id', $id)->where('user_id', $request->user()->id)->exists(),
'origins' => app(PartnershipSources::class)->forPartnership($id, $owner ? $request->user() : null), 'interests' => $interestData,
'locations' => app(InvestmentRelations::class)->locations(array_values(DB::table('partnership_locations')->where('partnership_id', $id)->get()->map(fn ($l) => ['id' => $l->geo_location_id, 'role' => $l->role, 'source_reference' => $l->source_reference])->all())),
- 'history' => ($owner || $moderator) ? DB::table('partnership_events')->where('partnership_id', $id)->where('event_type', 'like', 'partnership_opportunity.%')->orderBy('occurred_at')->get(['event_type', 'actor_id', 'occurred_at', 'payload']) : [],
+ 'historySummary' => ($owner || $moderator) ? app(PartnershipPublicationHistory::class)->summary($request->user(), $id) : null,
+ 'publicationActions' => app(PartnershipPublication::class)->actions($request->user(), $record),
+ 'publicationCommands' => app(PartnershipPublication::class)->commands($request->user(), $record),
...$this->catalogues($request)];
if ($request->user()) {
Inertia::encryptHistory();
@@ -182,39 +208,74 @@ class PartnershipExchangeController extends Controller
return $request->expectsJson() ? response()->json($props)->header('Cache-Control', 'private, no-store') : Inertia::render('partnerships/detail', $props);
}
+ public function publicationHistory(Request $request, int $id): Response|JsonResponse
+ {
+ $data = $request->validate(['before' => 'nullable|string|max:4000']);
+ $history = app(PartnershipPublicationHistory::class)->page($request->user(), $id, $data['before'] ?? null);
+
+ return $request->expectsJson() ? response()->json($history) : Inertia::render('partnerships/publication-history', $history);
+ }
+
public function transition(Request $request, int $id): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => 'required|integer|min:1', 'action' => 'required|string', 'reason' => 'required|string|max:2000']);
- $record = app(PartnershipExchange::class)->transition($request->user(), $id, $data['version'], $data['action'], $data['reason']);
+ $data = $request->validate(['client_key' => 'nullable|uuid', 'version' => 'required|integer|min:1', 'action' => 'required|string', 'reason' => 'required|string|max:2000']);
+ $record = app(PartnershipExchange::class)->transition($request->user(), $id, $data['version'], $data['action'], $data['reason'], $data['client_key'] ?? null);
- return $request->expectsJson() ? response()->json(['status' => $record->status, 'version' => $record->version]) : back()->with('success', 'Decisão registada.');
+ return $request->expectsJson() ? response()->json(['id' => $record->id, 'status' => $record->status, 'version' => $record->version, 'replayed' => (bool) ($record->command_replayed ?? false)]) : back()->with('success', 'Decisão registada.');
}
public function interest(Request $request, int $id): RedirectResponse|JsonResponse
{
$interest = app(PartnershipExchange::class)->interest($request->user(), $id, $request->all());
- return $request->expectsJson() ? response()->json(['id' => $interest->id, 'version' => $interest->version]) : back()->with('success', 'Interesse guardado.');
+ return $request->expectsJson() ? response()->json(['id' => $interest->id, 'version' => $interest->version, 'replayed' => (bool) ($interest->command_replayed ?? false)]) : back()->with('success', 'Interesse guardado.');
}
public function decide(Request $request, int $id): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => 'required|integer|min:1', 'action' => 'required|string', 'reason' => 'required|string|max:2000', 'assessment' => 'array|max:7']);
- $interest = app(PartnershipExchange::class)->decideInterest($request->user(), $id, $data['version'], $data['action'], $data['reason'], $data['assessment'] ?? []);
+ $data = $request->validate(['client_key' => 'nullable|uuid', 'partnership_version' => 'nullable|integer|min:1', 'weights_hash' => 'nullable|string|regex:/^[a-f0-9]{64}$/', 'version' => 'required|integer|min:1', 'action' => 'required|string', 'reason' => 'required|string|max:2000', 'assessment' => 'array|max:7']);
+ $interest = app(PartnershipExchange::class)->decideInterest($request->user(), $id, $data['version'], $data['action'], $data['reason'], $data['assessment'] ?? [], $data['partnership_version'] ?? null, $data['weights_hash'] ?? null, $data['client_key'] ?? null);
- return $request->expectsJson() ? response()->json(['status' => $interest->status, 'version' => $interest->version]) : back()->with('success', 'Candidatura atualizada.');
+ return $request->expectsJson() ? response()->json(['status' => $interest->status, 'version' => $interest->version, 'replayed' => (bool) ($interest->command_replayed ?? false)]) : back()->with('success', 'Candidatura atualizada.');
+ }
+
+ public function candidacyHistory(Request $request, int $id): Response|JsonResponse
+ {
+ $data = $request->validate(['before' => 'nullable|string|max:4000']);
+ $history = app(PartnershipCandidacyHistory::class)->page($request->user(), $id, $data['before'] ?? null);
+
+ return $request->expectsJson() ? response()->json($history) : Inertia::render('partnerships/interest-history', $history);
+ }
+
+ public function agreementHistory(Request $request, int $id): Response|JsonResponse
+ {
+ $data = $request->validate(['before' => 'nullable|string|max:4000']);
+ $history = app(PartnershipAgreementHistory::class)->page($request->user(), $id, $data['before'] ?? null);
+
+ return $request->expectsJson() ? response()->json($history) : Inertia::render('partnerships/agreement-history', $history);
}
public function room(Request $request, int $id): Response|JsonResponse
{
$context = app(PartnershipExchange::class)->room($request->user(), $id);
- $props = [...$context, 'room' => [...(array) $context['room'], 'agreement' => $context['room']->agreement ? json_decode($context['room']->agreement, true) : null],
- 'messages' => DB::table('partnership_messages as m')->join('users as u', 'u.id', '=', 'm.author_id')->where('room_id', $id)->orderBy('m.id')->get(['m.id', 'm.body', 'm.created_at', 'm.author_id', 'u.name']),
+ $participants = app(PartnershipExchange::class)->participants($context['partnership'], $context['interest']);
+ $participantIds = array_column($participants, 'id');
+ $canWrite = app(PartnershipExchange::class)->owns($request->user(), $context['partnership']) || app(PartnershipExchange::class)->owns($request->user(), $context['interest']);
+ $canAssign = $canWrite && in_array($context['room']->status, ['agreement_recorded', 'agreed', 'execution'], true);
+ $creationKeys = app(PartnershipMilestones::class)->creationKeys($request->user(), (int) $context['partnership']->id, $id);
+ $partnership = (array) $context['partnership'];
+ $payload = json_decode($partnership['payload'], true, 512, JSON_THROW_ON_ERROR);
+ unset($payload['_creation_hash']);
+ $partnership['payload'] = json_encode($payload, JSON_THROW_ON_ERROR);
+ $props = [...$context, 'partnership' => $partnership, 'room' => [...(array) $context['room'], 'agreement' => app(PartnershipAgreementProjection::class)->current($context['room']->agreement)],
+ 'messages' => DB::table('partnership_messages as m')->join('users as u', 'u.id', '=', 'm.author_id')->where('room_id', $id)->orderBy('m.id')->get(['m.id', 'm.body', 'm.created_at', 'm.author_id', 'm.client_key', 'u.name'])
+ ->map(fn ($message) => [...(array) $message, 'client_key' => (int) $message->author_id === $request->user()->id ? $message->client_key : null]),
'documents' => DB::table('partnership_documents as link')->join('documents as d', 'd.id', '=', 'link.document_id')->where('room_id', $id)
->where(fn ($q) => $q->where('link.shared', true)->orWhere('link.owner_id', $request->user()->id))
->get(['link.id', 'link.shared', 'link.owner_id', 'd.file_name', 'd.status', 'd.malware_scan_status', 'd.id as document_id']),
- 'milestones' => DB::table('partnership_milestones')->where('room_id', $id)->orderBy('id')->get(),
- 'canWrite' => app(PartnershipExchange::class)->owns($request->user(), $context['partnership']) || app(PartnershipExchange::class)->owns($request->user(), $context['interest'])];
+ 'milestones' => DB::table('partnership_milestones as m')->leftJoin('users as responsible', 'responsible.id', '=', 'm.responsible_id')->where('m.room_id', $id)->orderBy('m.id')
+ ->get(['m.*', 'responsible.name as responsible_name'])->map(fn ($milestone) => [...(array) $milestone, 'responsible_is_participant' => in_array((int) $milestone->responsible_id, $participantIds, true), 'client_key' => $creationKeys[(int) $milestone->id] ?? null]),
+ 'agreementActorId' => $request->user()->id, 'agreementParty' => app(PartnershipAgreements::class)->party($request->user(), $context), 'agreementCommands' => app(PartnershipAgreements::class)->commands($request->user(), $context), 'participants' => $canAssign ? $participants : [], 'canWrite' => $canWrite];
return $request->expectsJson() ? response()->json($props) : Inertia::render('partnerships/room', $props);
}
@@ -223,9 +284,10 @@ class PartnershipExchangeController extends Controller
{
$data = $request->validate(['client_key' => 'required|uuid', 'body' => 'required|string|max:15000']);
DB::transaction(function () use ($request, $id, $data) {
- $context = app(PartnershipExchange::class)->room($request->user(), $id, true);
+ $context = app(PartnershipExchange::class)->room($request->user(), $id);
+ abort_unless(app(PartnershipExchange::class)->owns($request->user(), $context['partnership']) || app(PartnershipExchange::class)->owns($request->user(), $context['interest']), 403);
$locked = DB::table('partnership_rooms')->where('id', $id)->lockForUpdate()->first();
- abort_unless($locked !== null && ! in_array($locked->status, ['closed', 'cancelled'], true), 409, 'Sala encerrada.');
+ abort_unless($locked !== null, 404);
$key = ['room_id' => $id, 'author_id' => $request->user()->id, 'client_key' => $data['client_key']];
$existing = DB::table('partnership_messages')->where($key)->first();
if ($existing) {
@@ -233,6 +295,7 @@ class PartnershipExchangeController extends Controller
return;
}
+ abort_if(in_array($locked->status, ['closed', 'cancelled'], true), 409, 'Sala encerrada.');
DB::table('partnership_messages')->insert([...$key, 'body' => $data['body']]);
app(PartnershipExchange::class)->event($context['partnership'], $request->user(), 'partnership.message_created.v1', ['room_id' => $id], 'Nova mensagem privada', [$context['partnership']->user_id, $context['interest']->user_id]);
});
@@ -242,100 +305,31 @@ class PartnershipExchangeController extends Controller
public function agreement(Request $request, int $id): RedirectResponse|JsonResponse
{
- $data = $request->validate(['version' => 'required|integer|min:1', 'action' => 'required|in:record,confirm,start,complete,cancel,renew', 'title' => 'required_if:action,record|nullable|string|max:200',
- 'terms' => 'required_if:action,record|nullable|string|max:20000', 'reason' => 'required|string|max:2000']);
- DB::transaction(function () use ($request, $id, $data) {
- $context = app(PartnershipExchange::class)->room($request->user(), $id, true);
- $room = DB::table('partnership_rooms')->where('id', $id)->lockForUpdate()->first();
- abort_unless((int) $room->version === (int) $data['version'], 409, 'Acordo alterado.');
- $agreement = $room->agreement ? json_decode($room->agreement, true) : null;
- $status = $room->status;
- if ($data['action'] === 'record') {
- abort_unless(in_array($status, ['negotiation', 'agreement_recorded'], true), 409);
- $previous = $agreement['previous_versions'] ?? [];
- if ($agreement) {
- $previous[] = ['title' => $agreement['title'], 'terms' => $agreement['terms'], 'confirmations' => $agreement['confirmations'], 'recorded_at' => $agreement['recorded_at']];
- }
- $agreement = ['title' => $data['title'], 'terms' => $data['terms'], 'recorded_by' => $request->user()->id, 'recorded_at' => now()->toIso8601String(), 'confirmations' => [],
- 'parties' => [$context['partnership']->user_id, $context['interest']->user_id], 'legal_signature_status' => 'not_verified', 'previous_versions' => $previous];
- $status = 'agreement_recorded';
- } elseif ($data['action'] === 'confirm') {
- abort_unless($status === 'agreement_recorded' && $agreement, 409);
- $party = app(PartnershipExchange::class)->owns($request->user(), $context['partnership']) ? 'proponent' : 'candidate';
- $agreement['confirmations'][$party] = ['actor_id' => $request->user()->id, 'date' => now()->toIso8601String(), 'reason' => $data['reason']];
- if (count($agreement['confirmations']) === 2) {
- $status = 'agreed';
- }
- } else {
- $allowed = ['start' => ['agreed'], 'complete' => ['execution'], 'cancel' => ['negotiation', 'agreement_recorded', 'agreed', 'execution'], 'renew' => ['agreed', 'execution']];
- abort_unless(in_array($status, $allowed[$data['action']] ?? [], true), 409);
- if ($data['action'] === 'complete') {
- abort_if(DB::table('partnership_milestones')->where('room_id', $id)->where('status', '!=', 'completed')->exists(), 409, 'Existem marcos pendentes.');
- }
- $status = ['start' => 'execution', 'complete' => 'closed', 'cancel' => 'cancelled', 'renew' => 'negotiation'][$data['action']];
- if ($data['action'] === 'renew') {
- $agreement['previous_versions'][] = ['title' => $agreement['title'], 'terms' => $agreement['terms'], 'confirmations' => $agreement['confirmations']];
- $agreement['confirmations'] = [];
- }
- }
- DB::table('partnership_rooms')->where('id', $id)->update(['agreement' => $agreement ? json_encode($agreement) : null, 'status' => $status, 'version' => $room->version + 1, 'updated_at' => now()]);
- app(PartnershipExchange::class)->event($context['partnership'], $request->user(), 'partnership_agreement.changed.v1', ['room_id' => $id, 'status' => $status, 'version' => $room->version + 1, 'reason' => $data['reason']], 'Acordo: '.$status, [$context['partnership']->user_id, $context['interest']->user_id]);
- });
+ $result = app(PartnershipAgreements::class)->act($request->user(), $id, $request->all());
- return $request->expectsJson() ? response()->json(['recorded' => true]) : back()->with('success', 'Acordo atualizado; assinatura jurídica não verificada.');
+ return $request->expectsJson() ? response()->json($result) : back()->with('success', 'Acordo atualizado; assinatura jurídica não verificada.');
}
public function milestone(Request $request, int $id, ?int $milestone = null): RedirectResponse|JsonResponse
{
- $data = $request->validate(['title' => 'required|string|max:200', 'responsible_id' => 'required|integer', 'due_date' => 'nullable|date_format:Y-m-d', 'status' => 'required|in:pending,progress,completed',
+ $data = $request->validate(['client_key' => 'nullable|uuid', 'title' => 'required|string|max:200', 'responsible_id' => 'required|integer', 'due_date' => 'nullable|date_format:Y-m-d', 'status' => 'required|in:pending,progress,completed',
'evidence' => 'required_if:status,completed|nullable|string|max:10000', 'version' => ($milestone ? 'required' : 'nullable').'|integer|min:1']);
- DB::transaction(function () use ($request, $id, $milestone, $data) {
- $context = app(PartnershipExchange::class)->room($request->user(), $id, true);
- $locked = DB::table('partnership_rooms')->where('id', $id)->lockForUpdate()->first();
- abort_unless($locked !== null && in_array($locked->status, ['agreement_recorded', 'agreed', 'execution'], true), 409);
- $responsible = User::query()->whereKey($data['responsible_id'])->first();
- abort_unless($responsible !== null && (app(PartnershipExchange::class)->owns($responsible, $context['partnership']) || app(PartnershipExchange::class)->owns($responsible, $context['interest'])), 422, 'Responsável deve ser participante identificado.');
- if ($milestone) {
- $existing = DB::table('partnership_milestones')->where('room_id', $id)->where('id', $milestone)->lockForUpdate()->first();
- abort_unless($existing !== null, 404);
- abort_unless((int) $existing->version === (int) $data['version'], 409);
- DB::table('partnership_milestones')->where('id', $milestone)->update([...$data, 'version' => $existing->version + 1, 'updated_at' => now()]);
- } else {
- unset($data['version']);
- $milestone = DB::table('partnership_milestones')->insertGetId([...$data, 'room_id' => $id, 'created_at' => now(), 'updated_at' => now()]);
- }
- app(PartnershipExchange::class)->event($context['partnership'], $request->user(), 'partnership_milestone.changed.v1', ['milestone_id' => $milestone, 'status' => $data['status']], 'Marco atualizado', [$context['partnership']->user_id, $context['interest']->user_id]);
- });
+ if (isset($data['client_key'])) {
+ $data['client_key'] = strtolower($data['client_key']);
+ }
+ $result = app(PartnershipMilestones::class)->save($request->user(), $id, $data, $milestone);
- return $request->expectsJson() ? response()->json(['saved' => true]) : back()->with('success', 'Marco guardado.');
+ return $request->expectsJson() ? response()->json($result) : back()->with('success', 'Marco guardado.');
}
public function upload(Request $request, int $id): RedirectResponse|JsonResponse
{
- $data = $request->validate(['file' => 'required|file|mimes:pdf,jpg,jpeg,png|max:10240', 'shared' => 'required|boolean']);
- $context = app(PartnershipExchange::class)->room($request->user(), $id, true);
+ $data = $request->validate(['client_key' => 'nullable|uuid', 'file' => 'required|file|mimes:pdf,jpg,jpeg,png|max:10240', 'shared' => 'required|boolean']);
$file = $request->file('file');
- $documentId = (string) Str::uuid();
- $stored = $file->storeAs('partnerships/'.$id, $documentId, 'local');
- abort_unless(is_string($stored) && $stored !== '', 503);
- try {
- DB::transaction(function () use ($request, $id, $data, $file, $documentId, $stored, $context) {
- app(PartnershipExchange::class)->room($request->user(), $id, true);
- $locked = DB::table('partnership_rooms')->where('id', $id)->lockForUpdate()->first();
- abort_unless($locked !== null && ! in_array($locked->status, ['closed', 'cancelled'], true), 409);
- DB::table('documents')->insert(['id' => $documentId, 'source_system' => 'partnership-exchange', 'data_classification' => 'restricted',
- 'file_name' => basename($file->getClientOriginalName()), 'media_type' => $file->getMimeType(), 'storage_key' => $stored,
- 'sha256' => hash_file('sha256', Storage::disk('local')->path($stored)), 'status' => 'quarantined', 'size_bytes' => $file->getSize(), 'uploaded_by' => $request->user()->id]);
- DB::table('partnership_documents')->insert(['room_id' => $id, 'document_id' => $documentId, 'owner_id' => $request->user()->id, 'shared' => $data['shared']]);
- app(PartnershipExchange::class)->event($context['partnership'], $request->user(), 'partnership.document_added.v1', ['room_id' => $id, 'document_id' => $documentId, 'shared' => $data['shared']], 'Documento privado anexado');
- });
- } catch (\Throwable $e) {
- Storage::disk('local')->delete($stored);
- throw $e;
- }
- ScanDocumentForMalware::dispatch($documentId)->afterCommit();
+ abort_unless($file instanceof UploadedFile, 422);
+ $result = app(PartnershipRoomUploads::class)->save($request->user(), $id, $file, (bool) $data['shared'], isset($data['client_key']) ? strtolower($data['client_key']) : null);
- return $request->expectsJson() ? response()->json(['uploaded' => true]) : back()->with('success', 'Documento privado guardado; análise antimalware pendente.');
+ return $request->expectsJson() ? response()->json($result) : back()->with('success', 'Envio reconciliado com o documento privado. Consulte o estado da análise na lista.')->with('uploaded_document_id', $result['document_id']);
}
public function download(Request $request, int $id, int $attachment): \Illuminate\Http\Response|BinaryFileResponse
@@ -367,7 +361,7 @@ class PartnershipExchangeController extends Controller
public function notification(Request $request, int $id): RedirectResponse
{
- abort_unless(DB::table('partnership_notifications')->where('id', $id)->where('user_id', $request->user()->id)->update(['read_at' => now()]) > 0, 404);
+ app(PartnershipNotifications::class)->markRead($request->user(), $id);
return back();
}
diff --git a/app/Http/Controllers/PortalProfileController.php b/app/Http/Controllers/PortalProfileController.php
index 38d4ea00..6d9ec486 100644
--- a/app/Http/Controllers/PortalProfileController.php
+++ b/app/Http/Controllers/PortalProfileController.php
@@ -2,12 +2,14 @@
namespace App\Http\Controllers;
+use App\Exceptions\OpportunityWorkflowUnavailable;
use App\Models\Opportunity;
use App\Models\User;
use App\Services\OpportunityCanonicalContract;
use App\Services\OpportunityContacts;
use App\Services\OpportunityManagement;
-use App\Services\OpportunityProfileWorkflow;
+use App\Services\OpportunityTechnicalSupport;
+use App\Services\OpportunityWorkflowExecution;
use App\Services\PortalInternalDesignation;
use App\Services\PortalProfileAccess;
use App\Services\PortalProfileAdministration;
@@ -49,7 +51,7 @@ class PortalProfileController extends Controller
{
$service->administrative($request->user());
- return Inertia::render('profiles/administration', ['requests' => DB::table('portal_profile_requests')->latest()->get(),
+ return Inertia::render('profiles/administration', ['technicalSupportAvailable' => app(OpportunityTechnicalSupport::class)->installed(), 'requests' => DB::table('portal_profile_requests')->latest()->get(),
'assignments' => DB::table('portal_role_assignments')->get(), 'pair' => DB::table('portal_superuser_pair')->first(),
'operatorOrganizations' => app(PortalInternalDesignation::class)->organizations(),
'staffAccounts' => User::query()->select(['id', 'name', 'email', 'email_verified_at'])
@@ -150,9 +152,14 @@ class PortalProfileController extends Controller
return app(OpportunityManagementController::class)->edit($request, app(OpportunityManagement::class), $id);
}
- public function workflow(Request $request, int $id, OpportunityProfileWorkflow $service): JsonResponse
+ public function workflow(Request $request, int $id, OpportunityWorkflowExecution $service): JsonResponse
{
- $record = $service->transition($request->user(), $id, $request->all());
+ try {
+ $record = $service->transition($request->user(), $id, $request->all());
+ } catch (OpportunityWorkflowUnavailable $failure) {
+ return response()->json(['message' => 'Não foi possível confirmar o resultado. Consulte o estado da oportunidade antes de repetir. '.($failure->recorded ? 'Incidente técnico registado. ' : 'Não foi possível guardar o incidente; conserve esta referência. ').'Referência: '.$failure->reference,
+ 'reference' => $failure->reference, 'incident_recorded' => $failure->recorded], 503)->header('Cache-Control', 'private, no-store');
+ }
return response()->json(['id' => $id, 'status' => app(PortalProfileAccess::class)->state($record), 'publication_status' => $record->status, 'etag' => app(OpportunityManagement::class)->etag($record), 'message' => 'Ação interna registada; não representa decisão externa.']);
}
diff --git a/app/Http/Controllers/PortalProfileInstallationController.php b/app/Http/Controllers/PortalProfileInstallationController.php
index 597a58e6..9638031f 100644
--- a/app/Http/Controllers/PortalProfileInstallationController.php
+++ b/app/Http/Controllers/PortalProfileInstallationController.php
@@ -7,6 +7,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
+use Symfony\Component\HttpFoundation\Response as HttpResponse;
class PortalProfileInstallationController extends Controller
{
@@ -22,6 +23,19 @@ class PortalProfileInstallationController extends Controller
return response()->json($installation->apply($request->user(), $request->all()));
}
+ public function supportPreview(Request $request, PortalProfileInstallation $installation): HttpResponse
+ {
+ $plan = $installation->supportPreview($request->user());
+ Inertia::encryptHistory();
+
+ return tap($request->expectsJson() ? response()->json($plan) : Inertia::render('profiles/support-installation', $plan)->toResponse($request), static fn (HttpResponse $response) => $response->headers->set('Cache-Control', 'private, no-store'));
+ }
+
+ public function applySupport(Request $request, PortalProfileInstallation $installation): JsonResponse
+ {
+ return response()->json($installation->applySupport($request->user(), $request->all()))->header('Cache-Control', 'private, no-store');
+ }
+
public function bootstrap(Request $request, PortalProfileInstallation $installation): JsonResponse
{
return response()->json($installation->bootstrap($request->user(), $request->all()));
diff --git a/app/Http/Controllers/PortalServicesController.php b/app/Http/Controllers/PortalServicesController.php
index 11717569..51b6c1b9 100644
--- a/app/Http/Controllers/PortalServicesController.php
+++ b/app/Http/Controllers/PortalServicesController.php
@@ -17,6 +17,7 @@ use App\Services\LegacyContent;
use App\Services\Malware\MalwareScanner;
use App\Services\PortalProfileAccess;
use App\Services\PublicDocumentPresentation;
+use App\Services\PublicSearchMetrics;
use App\Services\SectorOrganization;
use App\Services\VerifiedDocumentBinary;
use App\Services\VirtualDesk;
@@ -127,6 +128,7 @@ class PortalServicesController extends Controller
])->paginate(20)->withQueryString();
$pageResult->getCollection()->transform(fn ($resource) => app(PublicDocumentPresentation::class)->resource($resource));
$props['resources'] = $pageResult;
+ app(PublicSearchMetrics::class)->candidate($request, 'documents', $pageResult->total(), $filters);
$props['documentTypes'] = (clone $this->resources())->distinct()->orderBy('r.document_type')->pluck('r.document_type');
$props['languages'] = (clone $this->resources())->distinct()->orderBy('r.language')->pluck('r.language');
$props['issuers'] = (clone $this->resources())->whereNotNull('d.issuer')->distinct()->orderBy('d.issuer')->pluck('d.issuer');
@@ -153,6 +155,7 @@ class PortalServicesController extends Controller
$query->where('title', 'ilike', '%'.$filters['q'].'%');
}
$props['partnerships'] = $query->orderByDesc('id')->select(['id', 'title', 'sector', 'province', 'offer', 'seeking'])->paginate(20)->withQueryString();
+ app(PublicSearchMetrics::class)->candidate($request, 'partnerships', $props['partnerships']->total(), $filters);
}
if ($page === 'desk') {
if (app(VirtualDesk::class)->installed()) {
diff --git a/app/Http/Controllers/ProactiveSupplyController.php b/app/Http/Controllers/ProactiveSupplyController.php
index 4d9977e1..a5248836 100644
--- a/app/Http/Controllers/ProactiveSupplyController.php
+++ b/app/Http/Controllers/ProactiveSupplyController.php
@@ -6,11 +6,26 @@ use App\Models\Opportunity;
use App\Services\ProactiveSupply;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
+use Inertia\Inertia;
+use Inertia\Response;
final class ProactiveSupplyController extends Controller
{
+ public function review(Request $request, ProactiveSupply $service): JsonResponse|Response
+ {
+ $service->authorize($request->user());
+ $v = $request->validate(['record_id' => 'nullable|integer|min:1']);
+ $record = isset($v['record_id']) ? Opportunity::whereKey($v['record_id'])->firstOrFail() : null;
+ $data = $service->review($request->user(), $request->all(), $record);
+ $data['recordId'] = isset($v['record_id']) ? (int) $v['record_id'] : null;
+
+ return $request->expectsJson() ? response()->json($data)->header('Cache-Control', 'private, no-store')
+ : Inertia::render('management/proactive-supply-review', $data);
+ }
+
public function index(Request $request, ProactiveSupply $service): JsonResponse
{
+ $service->authorize($request->user());
$v = $request->validate(['record_id' => 'nullable|integer|min:1']);
$record = isset($v['record_id']) ? Opportunity::whereKey($v['record_id'])->firstOrFail() : null;
diff --git a/app/Http/Controllers/ProductExperimentController.php b/app/Http/Controllers/ProductExperimentController.php
new file mode 100644
index 00000000..f95fc5a2
--- /dev/null
+++ b/app/Http/Controllers/ProductExperimentController.php
@@ -0,0 +1,41 @@
+listing($request->user(), $request->all());
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('management/experiments/index', $data);
+ }
+
+ public function create(Request $request, ProductExperiments $experiments): Response|JsonResponse
+ {
+ return $this->show($request, $experiments);
+ }
+
+ public function show(Request $request, ProductExperiments $experiments, ?string $id = null): Response|JsonResponse
+ {
+ $data = $experiments->view($request->user(), $id, $request->all());
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('management/experiments/edit', $data);
+ }
+
+ public function store(Request $request, ProductExperiments $experiments): JsonResponse
+ {
+ return response()->json($experiments->save($request->user(), null, $request->all()), 201);
+ }
+
+ public function revise(Request $request, ProductExperiments $experiments, string $id): JsonResponse
+ {
+ return response()->json($experiments->save($request->user(), $id, $request->all()));
+ }
+}
diff --git a/app/Http/Controllers/ProductUsageMetricsController.php b/app/Http/Controllers/ProductUsageMetricsController.php
new file mode 100644
index 00000000..1e556069
--- /dev/null
+++ b/app/Http/Controllers/ProductUsageMetricsController.php
@@ -0,0 +1,19 @@
+ $metrics->report($request->user(), $request->all())];
+
+ return $request->expectsJson() ? response()->json($data) : Inertia::render('management/product-usage', $data);
+ }
+}
diff --git a/app/Http/Controllers/PublicBusinessOpportunityController.php b/app/Http/Controllers/PublicBusinessOpportunityController.php
index 8808a920..571ea2a6 100644
--- a/app/Http/Controllers/PublicBusinessOpportunityController.php
+++ b/app/Http/Controllers/PublicBusinessOpportunityController.php
@@ -5,11 +5,14 @@ namespace App\Http\Controllers;
use App\Http\Resources\PublicBusinessOpportunityResource;
use App\Models\ExistingBusiness;
use App\Models\Sector;
+use App\Services\BusinessProximitySearch;
use App\Services\CountryCatalogue;
use App\Services\ExistingBusinessClassification;
use App\Services\ExistingBusinessDrafts;
use App\Services\InvestmentGeography;
use App\Services\OpportunityClassification;
+use App\Services\PublicBusinessLocations;
+use App\Services\PublicSearchMetrics;
use App\Services\SectorOrganization;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
@@ -30,13 +33,7 @@ class PublicBusinessOpportunityController extends Controller
$path = app(InvestmentGeography::class)->selection($filters);
if ($path !== []) {
$territoryIds = app(InvestmentGeography::class)->descendants($path[array_key_last($path)]->id);
- $query->whereExists(fn ($locations) => $locations->selectRaw('1')->from('existing_business_locations as matching_location')
- ->whereColumn('matching_location.existing_business_id', 'existing_businesses.id')->where('matching_location.is_public', true)
- ->where(function ($match) use ($territoryIds): void {
- foreach (['province_id', 'district_id', 'admin_post_id', 'locality_id'] as $field) {
- $match->orWhereIn('matching_location.'.$field, $territoryIds);
- }
- }));
+ $query->whereExists(app(PublicBusinessLocations::class)->matchingArea($territoryIds)->selectRaw('1')->whereColumn('l.existing_business_id', 'existing_businesses.id'));
}
if (! empty($filters['q'])) {
$term = trim($filters['q']);
@@ -52,12 +49,21 @@ class PublicBusinessOpportunityController extends Controller
$query->where('existing_businesses.modality', $filters['modality']);
}
- $results = PublicBusinessOpportunityResource::collection($query->paginate($filters['per_page'] ?? 12)->appends($filters));
+ $coverage = null;
+ if (! empty($filters['near_business'])) {
+ $proximity = app(BusinessProximitySearch::class);
+ $coverage = $proximity->constrain($query, $proximity->origin($filters['near_business']), (float) $filters['radius_km']);
+ } else {
+ $query->orderByDesc('existing_businesses.published_at')->orderBy('existing_businesses.id');
+ }
+ $page = $query->paginate($filters['per_page'] ?? 12)->appends($filters);
+ app(PublicSearchMetrics::class)->candidate($request, 'businesses', $page->total(), $filters);
+ $results = PublicBusinessOpportunityResource::collection($page)->additional(['geographicCoverage' => $coverage]);
if ($request->expectsJson()) {
return $results->response();
}
- return Inertia::render('investment/business-marketplace', ['results' => $results, 'filters' => $filters, 'territorySelection' => $path,
+ return Inertia::render('investment/business-marketplace', ['results' => $results, 'filters' => $filters, 'territorySelection' => $path, 'geographicCoverage' => $coverage,
'classificationOptions' => app(OpportunityClassification::class)->options(),
'authorities' => DB::table('authorities')->where('status', 'published')->orderBy('label_pt_mz')->get(['id', 'label_pt_mz'])]);
}
@@ -72,6 +78,7 @@ class PublicBusinessOpportunityController extends Controller
'modality' => ['nullable', Rule::in(ExistingBusinessDrafts::MODALITIES)],
'sector' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:50'],
+ 'near_business' => ['nullable', 'required_with:radius_km', 'uuid'], 'radius_km' => ['nullable', 'required_with:near_business', 'numeric', 'min:0.1', 'max:2000'],
'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'],
'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid'],
...app(ExistingBusinessClassification::class)->filterRules(),
@@ -93,6 +100,7 @@ class PublicBusinessOpportunityController extends Controller
}
return Inertia::render('investment/business-opportunity', ['record' => $resource->resolve($request),
+ 'similarRadiusAvailable' => app(BusinessProximitySearch::class)->available($record->id),
'similarCatalogueUrl' => '/negocios?'.http_build_query(array_filter([
'modality' => $record->modality,
'sector' => $record->sector_id,
@@ -119,14 +127,14 @@ class PublicBusinessOpportunityController extends Controller
/** @return Builder */
private function publishedQuery(): Builder
{
- $publicLocations = DB::table('existing_business_locations as locations')
- ->leftJoin('geo_locations as province', 'province.id', '=', 'locations.province_id')
- ->leftJoin('geo_locations as district', 'district.id', '=', 'locations.district_id')
- ->leftJoin('geo_locations as locality', 'locality.id', '=', 'locations.locality_id')
- ->where('locations.is_public', true)->where('locations.is_primary', true)
+ $publicLocations = app(PublicBusinessLocations::class)->primary()
+ ->leftJoin('geo_locations as province', 'province.id', '=', 'l.province_id')
+ ->leftJoin('geo_locations as district', 'district.id', '=', 'l.district_id')
+ ->leftJoin('geo_locations as locality', 'locality.id', '=', 'l.locality_id')
->whereNull('province.deleted_at')->whereNull('district.deleted_at')->whereNull('locality.deleted_at')
- ->select('locations.existing_business_id', 'province.name as province', 'province.id as similar_province_id')
- ->selectRaw("CASE WHEN locations.precision_level IN ('district','admin_post','locality','exact') THEN district.name ELSE NULL END AS district")
+ ->select('l.existing_business_id', 'l.updated_at as location_recorded_at', 'province.name as province', 'province.id as similar_province_id')
+ ->selectRaw(app(PublicBusinessLocations::class)->sourceProjection())
+ ->selectRaw("CASE WHEN l.precision_level IN ('district','admin_post','locality','exact') THEN district.name ELSE NULL END AS district")
->selectRaw('NULL::text AS locality');
return ExistingBusiness::query()->published()->with('sector:id,name,slug')
@@ -136,6 +144,7 @@ class PublicBusinessOpportunityController extends Controller
'existing_businesses.currency', 'existing_businesses.amount_min', 'existing_businesses.amount_max',
'existing_businesses.available_percentage', 'existing_businesses.published_at', 'existing_businesses.sector_id',
'existing_businesses.owner_user_id', 'existing_businesses.organization_id', 'existing_businesses.version_no', 'existing_businesses.expires_at', 'existing_businesses.status', 'existing_businesses.modality',
- 'public_location.province', 'public_location.district', 'public_location.locality', 'public_location.similar_province_id']);
+ 'public_location.province', 'public_location.district', 'public_location.locality', 'public_location.similar_province_id',
+ 'public_location.location_recorded_at', 'public_location.location_source_reference', 'public_location.location_source_date']);
}
}
diff --git a/app/Http/Controllers/TechnicalSupportController.php b/app/Http/Controllers/TechnicalSupportController.php
new file mode 100644
index 00000000..d87338dc
--- /dev/null
+++ b/app/Http/Controllers/TechnicalSupportController.php
@@ -0,0 +1,45 @@
+validate(['page' => ['nullable', 'integer', 'min:1'], 'status' => ['nullable', 'in:all,open,in_progress,resolved'], 'unread' => ['nullable', 'boolean']]);
+ $status = $filters['status'] ?? 'all';
+ $unread = $request->boolean('unread');
+ $incidents = $support->queue($request->user(), $status, $unread);
+ Inertia::encryptHistory();
+
+ return tap(Inertia::render('profiles/technical-support', ['actorId' => $request->user()->id, 'incidents' => $incidents, 'filters' => ['status' => $status, 'unread' => $unread]])->toResponse($request), static fn (Response $response) => $response->headers->set('Cache-Control', 'private, no-store'));
+ }
+
+ public function show(Request $request, string $reference, TechnicalIncidentHandling $handling, OpportunityTechnicalSupport $support): Response
+ {
+ $filters = $request->validate(['history_page' => ['nullable', 'integer', 'min:1'], 'page' => ['nullable', 'integer', 'min:1'], 'status' => ['nullable', 'in:all,open,in_progress,resolved'], 'unread' => ['nullable', 'boolean']]);
+ $data = $handling->detail($request->user(), $reference);
+ Inertia::encryptHistory();
+
+ $query = array_filter(['page' => $request->integer('page') > 1 ? $request->integer('page') : null, 'status' => ($filters['status'] ?? 'all') !== 'all' ? $filters['status'] : null, 'unread' => $request->boolean('unread') ? 1 : null], fn ($v) => $v !== null);
+
+ return tap(Inertia::render('profiles/technical-incident', [...$data, 'notice' => $support->notice($request->user(), $reference), 'backUrl' => '/suporte-tecnico/incidentes'.($query !== [] ? '?'.http_build_query($query) : '')])->toResponse($request), static fn (Response $response) => $response->headers->set('Cache-Control', 'private, no-store'));
+ }
+
+ public function decide(Request $request, string $reference, TechnicalIncidentHandling $handling): JsonResponse
+ {
+ return response()->json($handling->decide($request->user(), $reference, $request->all()))->header('Cache-Control', 'private, no-store');
+ }
+
+ public function consulted(Request $request, string $reference, OpportunityTechnicalSupport $support): JsonResponse
+ {
+ return response()->json($support->markConsulted($request->user(), $reference))->header('Cache-Control', 'private, no-store');
+ }
+}
diff --git a/app/Http/Controllers/VirtualDeskController.php b/app/Http/Controllers/VirtualDeskController.php
index 46ad19a0..fecf0423 100644
--- a/app/Http/Controllers/VirtualDeskController.php
+++ b/app/Http/Controllers/VirtualDeskController.php
@@ -7,6 +7,9 @@ use App\Models\InvestmentSubmission;
use App\Models\User;
use App\Services\Ai\InvestorGuidance;
use App\Services\CountryCatalogue;
+use App\Services\DeskAttachments;
+use App\Services\DeskPaymentEvidence;
+use App\Services\DeskServiceAvailability;
use App\Services\InstitutionalLinkMonitor;
use App\Services\InvestmentGeography;
use App\Services\InvestorContextConsumers;
@@ -27,6 +30,7 @@ use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class VirtualDeskController extends Controller
{
@@ -34,7 +38,7 @@ class VirtualDeskController extends Controller
{
$filters = $request->validate(['q' => 'nullable|string|max:120', 'theme' => 'nullable|string|max:80', 'profile' => 'nullable|string|max:100']);
$installed = $desk->installed();
- $services = $installed ? DB::table('desk_service_versions')->where('status', 'published')->orderBy('code')->orderByDesc('version')->get()->unique('code')->map(fn ($s) => ['id' => $s->id, 'version' => $s->version, 'definition' => json_decode($s->definition, true), 'source' => json_decode($s->source, true)])->values() : collect();
+ $services = $installed ? app(DeskServiceAvailability::class)->current()->get()->map(fn ($s) => ['id' => $s->id, 'version' => $s->version, 'effective_from' => $s->effective_from ?? null, 'definition' => json_decode($s->definition, true), 'source' => json_decode($s->source, true)])->values() : collect();
$services = $services->filter(fn ($s) => (! ($filters['q'] ?? '') || str_contains(mb_strtolower(json_encode($s['definition'], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)), mb_strtolower($filters['q'])))
&& (! ($filters['theme'] ?? '') || $s['definition']['theme'] === $filters['theme']) && (! ($filters['profile'] ?? '') || $s['definition']['profile'] === $filters['profile']))->values();
$page = max(1, (int) $request->query('page', 1));
@@ -49,7 +53,7 @@ class VirtualDeskController extends Controller
$actor = $request->user();
$organizations = DB::table('memberships')->where('user_id', $actor->id)->whereNull('deleted_at')->pluck('organization_id');
$cases = DB::table('desk_cases')->where(fn ($q) => $q->where(fn ($p) => $p->where('user_id', $actor->id)->whereNull('organization_id'))->orWhereIn('organization_id', $organizations))->orderByDesc('updated_at')->get(['id', 'title', 'version', 'updated_at']);
- $queue = DB::table('desk_requests as r')->join('desk_cases as c', 'c.id', '=', 'r.case_id')->whereNotIn('r.status', ['draft', 'cancelled'])->when(! $actor->can('manage-portal'), fn ($q) => $q->where('r.analyst_id', $actor->id))
+ $queue = DB::table('desk_requests as r')->join('desk_cases as c', 'c.id', '=', 'r.case_id')->whereNull('c.closed_at')->whereNotIn('r.status', ['draft', 'cancelled', 'closed'])->when(! $actor->can('manage-portal'), fn ($q) => $q->where('r.analyst_id', $actor->id))
->orderByRaw('r.due_at ASC NULLS LAST')->get(['r.id', 'r.protocol', 'r.status', 'r.version', 'r.analyst_id', 'r.due_at', 'c.title']);
$data = ['cases' => $cases, 'queue' => $queue, 'notifications' => DB::table('desk_notifications')->where('user_id', $actor->id)->orderByDesc('id')->limit(100)->get(),
'legacyRequests' => DB::table('interest_requests')->where('metadata->portal_user_id', $actor->id)->whereNull('deleted_at')->orderByDesc('created_at')->get(['id', 'reference', 'status', 'created_at']),
@@ -86,9 +90,10 @@ class VirtualDeskController extends Controller
'legacyRequest' => ($case->interest_request_id ?? null) ? DB::table('interest_requests as r')->leftJoin('users as u', 'u.id', '=', 'r.assigned_to')->where('r.id', $case->interest_request_id)->whereNull('r.deleted_at')
->when(! $request->user()->can('manage-portal'), fn ($q) => $q->where('r.metadata->portal_user_id', $request->user()->id))
->first(['r.id', 'r.reference', 'r.status', 'r.next_action', 'r.next_action_due_at', 'u.name as responsible_name']) : null,
- 'owner' => $owner, 'canWrite' => $desk->owns($request->user(), $case), 'manager' => $request->user()->can('manage-portal'),
+ 'owner' => $owner, 'canWrite' => ! $case->closed_at && $desk->owns($request->user(), $case), 'manager' => $request->user()->can('manage-portal'),
+ 'canChangeState' => (int) $case->user_id === $request->user()->id && $desk->owns($request->user(), $case), 'activity' => $owner ? $desk->caseActivity($case) : null,
'requests' => DB::table('desk_requests')->where('case_id', $id)->when(! $owner && ! $request->user()->can('manage-portal'), fn ($q) => $q->where('analyst_id', $request->user()->id))->orderByDesc('updated_at')->get(['id', 'status', 'protocol', 'service_version_id', 'version']),
- 'services' => DB::table('desk_service_versions')->where('status', 'published')->orderByDesc('version')->get(['id', 'code', 'version', 'definition'])->unique('code')->values()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title'], 'version' => $s->version]),
+ 'services' => app(DeskServiceAvailability::class)->current()->get()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title'], 'version' => $s->version, 'effective_from' => $s->effective_from ?? null]),
'documents' => $this->documents($id, $request->user()), 'events' => $this->events($id, $desk, $request->user()), 'stepStates' => config('virtual-desk.step_states'), 'states' => config('virtual-desk.request_states'),
'links' => DB::table('desk_institutional_links')->get()->map(fn ($link) => [...(array) $link, 'monitor' => app(InstitutionalLinkMonitor::class)->status($link)]), 'source' => config('virtual-desk.source'), 'support' => config('portal.support'),
'guidance' => app(InvestorGuidance::class)->installed() ? app(InvestorGuidance::class)->view($request->user(), $id) : null];
@@ -101,7 +106,46 @@ class VirtualDeskController extends Controller
{
return DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $case)->whereNull('d.deleted_at')
->when(! app(VirtualDesk::class)->owns($actor, app(VirtualDesk::class)->case($actor, $case), false) && ! $actor->can('manage-portal'), fn ($q) => $q->where(fn ($p) => $p->whereNull('l.request_id')->orWhereIn('l.request_id', DB::table('desk_requests')->where('analyst_id', $actor->id)->select('id'))))
- ->get(['l.id', 'l.document_id', 'l.request_id', 'l.category', 'l.stage', 'l.source_reference', 'l.valid_until', 'd.file_name', 'd.status', 'd.malware_scan_status', 'd.sha256']);
+ ->get(['l.id', 'l.document_id', 'l.request_id', 'l.category', 'l.stage', 'l.source_reference', 'l.valid_until', 'd.file_name', 'd.status', 'd.malware_scan_status', 'd.sha256', 'd.media_type', 'd.size_bytes', 'd.version_no']);
+ }
+
+ public function availableDocuments(Request $request, string $id, VirtualDesk $desk): JsonResponse
+ {
+ $case = $desk->case($request->user(), $id, true);
+ abort_if($case->closed_at, 409, 'Dossier encerrado.');
+ $data = $request->validate(['q' => 'nullable|string|max:120', 'offset' => 'nullable|integer|min:0']);
+ $offset = (int) ($data['offset'] ?? 0);
+ $actor = $request->user();
+ // Match the existing reuse authority: this dossier, own personal dossiers, or own uploads.
+ // A document's uploader does not inherit another dossier's reference or private context.
+ $sources = DB::table('desk_documents as l')->join('desk_cases as c', 'c.id', '=', 'l.case_id')
+ ->where(fn ($q) => $q->where('c.id', $id)->orWhere(fn ($p) => $p->where('c.user_id', $actor->id)->whereNull('c.organization_id')))
+ ->select(['l.id', 'l.document_id', 'l.category', 'l.stage', 'l.source_reference', 'l.valid_until', 'c.title as origin_label']);
+ $query = DB::table('documents as d')->leftJoinSub($sources, 's', fn ($q) => $q->on('s.document_id', '=', 'd.id'))
+ ->whereNull('d.deleted_at')->where(fn ($q) => $q->where('d.uploaded_by', $actor->id)->orWhereNotNull('s.id'));
+ $search = trim($data['q'] ?? '');
+ if ($search !== '') {
+ $like = '%'.addcslashes($search, '\\%_').'%';
+ $query->where(fn ($q) => $q->where('d.file_name', 'ilike', $like)->orWhere('s.source_reference', 'ilike', $like)->orWhere('s.origin_label', 'ilike', $like));
+ }
+ $rows = $query->orderBy('d.file_name')->orderBy('d.id')->orderBy('s.id')->offset($offset)->limit(26)
+ ->get(['d.id as document_id', 'd.file_name', 'd.version_no', 'd.status', 'd.malware_scan_status', 'd.media_type', 'd.size_bytes', 'd.source_system', 's.id', 's.category', 's.stage', 's.source_reference', 's.valid_until', 's.origin_label']);
+ $items = $rows->take(25)->filter(function ($document) {
+ try {
+ app(VerifiedDocumentBinary::class)->authorizeOpportunityAttachment((object) [...(array) $document, 'id' => $document->document_id]);
+
+ return true;
+ } catch (HttpExceptionInterface $exception) {
+ if ($exception->getStatusCode() !== 403) {
+ throw $exception;
+ }
+
+ return false;
+ }
+ })->map(fn ($document) => Arr::except((array) $document, ['source_system']))->values();
+ $this->auditRead($request, 'desk_cases', $id);
+
+ return response()->json(['documents' => $items, 'next_offset' => $rows->count() > 25 ? $offset + 25 : null], 200, ['Cache-Control' => 'private, no-store']);
}
/** @return Collection}> */
@@ -112,6 +156,13 @@ class VirtualDeskController extends Controller
->orderBy('e.event_order')->get(['e.id', 'e.request_id', 'e.action', 'e.payload', 'e.version', 'e.created_at', 'u.name'])->map(fn ($e) => ['id' => $e->id, 'request_id' => $e->request_id, 'action' => $e->action, 'version' => $e->version, 'created_at' => $e->created_at, 'name' => $e->name, 'payload' => $desk->decode($e->payload)]);
}
+ public function caseState(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
+ {
+ $result = $desk->changeCaseState($request->user(), $id, $request->all());
+
+ return $request->expectsJson() ? response()->json($result) : back()->with('success', $result['replayed'] ? 'Operação já registada; o estado actual do dossier é apresentado.' : ($result['closed_at'] ? 'Dossier encerrado pelo dono. Os registos continuam disponíveis para consulta.' : 'Dossier reaberto pelo dono. Mantêm-se os estados próprios dos pedidos e das tarefas.'));
+ }
+
public function stage(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
$case = $desk->stage($request->user(), $id, $request->all());
@@ -147,17 +198,21 @@ class VirtualDeskController extends Controller
}
}
$this->auditRead($request, 'desk_requests', $id);
+ $caseDocuments = $this->documents($case->id, $request->user());
+ $paymentEvidence = app(DeskPaymentEvidence::class)->forRequest($id);
$data = ['boundContextRevision' => app(InvestorContextConsumers::class)->requestRevision($row), 'countries' => app(CountryCatalogue::class)->all(), 'toolPrefill' => $desk->requestToolPrefill($request->user(), $row), 'request' => [...(array) $row, 'payload' => $payload, 'submitted_snapshot' => $desk->decode($row->submitted_snapshot), 'editable_fields' => json_decode($row->editable_fields ?? '[]', true)],
'case' => ['id' => $case->id, 'title' => $case->title], 'caseVersion' => $case->version, 'definition' => $definition, 'territoryPaths' => $territoryPaths,
'serviceSource' => json_decode(DB::table('desk_service_versions')->where('id', $row->service_version_id)->value('source'), true),
+ 'serviceEffectiveFrom' => DB::table('desk_service_versions')->where('id', $row->service_version_id)->selectRaw(app(DeskServiceAvailability::class)->dateProjection())->first()->effective_from,
'owner' => $desk->owns($request->user(), $case), 'manager' => app(ScopedPortalAdministration::class)->deskDecision($request->user(), $row), 'analyst' => (int) $row->analyst_id === $request->user()->id,
- 'fieldsEditable' => in_array($row->status, ['draft', 'returned'], true), 'states' => config('virtual-desk.request_states'), 'transitions' => config('virtual-desk.transitions.'.$row->status, []),
- 'findings' => $desk->findings($payload, $definition), 'ai' => config('virtual-desk.ai'), 'documents' => $this->documents($case->id, $request->user())->filter(fn ($d) => ! $d->request_id || $d->request_id === $id)->values(),
+ 'operationsEditable' => ! $case->closed_at && ! in_array($row->status, ['closed', 'cancelled'], true), 'fieldsEditable' => ! $case->closed_at && in_array($row->status, ['draft', 'returned'], true), 'states' => config('virtual-desk.request_states'), 'transitions' => $case->closed_at ? [] : config('virtual-desk.transitions.'.$row->status, []), 'returnReasons' => config('product-metrics.return_reasons'),
+ 'findings' => $desk->findings($payload, $definition), 'ai' => config('virtual-desk.ai'), 'documents' => $caseDocuments->filter(fn ($d) => ! $d->request_id || $d->request_id === $id)->values(),
+ 'reusableDocuments' => $desk->owns($request->user(), $case) && ! $case->closed_at ? $caseDocuments->values() : [],
'messages' => DB::table('desk_messages as m')->join('users as u', 'u.id', '=', 'm.actor_id')->where('request_id', $id)->orderBy('m.created_at')->get(['m.id', 'm.actor_id', 'm.body', 'm.created_at', 'u.name'])->map(fn ($m) => [...(array) $m, 'body' => Crypt::decryptString($m->body),
'kind' => $messageKinds[$m->id] ?? 'historical_unclassified']),
'events' => $this->events($case->id, $desk, $request->user())->filter(fn ($e) => $e['request_id'] === $id)->values(),
'revisions' => DB::table('desk_revisions')->where('request_id', $id)->orderByDesc('version')->get(['version', 'snapshot', 'created_at'])->map(fn ($r) => [...(array) $r, 'snapshot' => $desk->decode($r->snapshot)]),
- 'payments' => DB::table('desk_payments')->where('request_id', $id)->get(),
+ 'payments' => DB::table('desk_payments')->where('request_id', $id)->get()->map(fn ($payment) => [...(array) $payment, 'document_evidence' => $paymentEvidence[$payment->id] ?? null]),
'analysts' => $request->user()->can('manage-portal') ? User::orderBy('name')->get(['id', 'name']) : [],
'territories' => app(InvestmentGeography::class)->publicReferences()->orderBy('name')->get(['id', 'name', 'location_type'])];
@@ -182,7 +237,9 @@ class VirtualDeskController extends Controller
{
abort_unless(app(ScopedPortalAdministration::class)->administrative($request->user()), 403);
// Triage projection deliberately excludes payloads, documents, investor identity and case titles.
- $data = ['requests' => DB::table('desk_requests')->whereNotIn('status', ['draft', 'cancelled', 'closed'])->orderBy('created_at')->get(['id', 'protocol', 'status', 'version', 'analyst_id', 'due_at']),
+ $data = ['requests' => DB::table('desk_requests')->whereNotIn('status', ['draft', 'cancelled', 'closed'])
+ ->whereExists(fn ($q) => $q->selectRaw('1')->from('desk_cases')->whereColumn('desk_cases.id', 'desk_requests.case_id')->whereNull('desk_cases.closed_at'))
+ ->orderBy('created_at')->get(['id', 'protocol', 'status', 'version', 'analyst_id', 'due_at']),
'analysts' => User::whereNotNull('email_verified_at')->orderBy('name')->get(['id', 'name'])];
return $request->expectsJson() ? response()->json($data) : Inertia::render('management/desk-assignments', $data);
@@ -195,8 +252,9 @@ class VirtualDeskController extends Controller
DB::transaction(function () use ($request, $id, $desk, $data) {
$row = DB::table('desk_requests')->where('id', $id)->lockForUpdate()->first();
abort_unless($row !== null, 404);
- $case = DB::table('desk_cases')->where('id', $row->case_id)->first();
+ $case = DB::table('desk_cases')->where('id', $row->case_id)->lockForUpdate()->first();
abort_unless($case !== null, 404);
+ $desk->assertOpen($case);
if ((int) $row->version !== (int) $data['version']) {
throw ValidationException::withMessages(['version' => 'Este pedido foi actualizado. Recupere a lista e tente novamente.']);
}
@@ -218,7 +276,8 @@ class VirtualDeskController extends Controller
$data = $request->validate(['body' => 'required|string|min:1|max:10000', 'client_key' => 'required|uuid']);
DB::transaction(function () use ($request, $id, $desk, $data) {
$row = $desk->request($request->user(), $id, false, true);
- $case = $desk->case($request->user(), $row->case_id);
+ $case = $desk->case($request->user(), $row->case_id, false, true);
+ $desk->assertOpen($case);
abort_if(in_array($row->status, ['closed', 'cancelled'], true), 409, 'Pedido encerrado.');
abort_unless($desk->owns($request->user(), $case) || $request->user()->can('manage-portal') || (int) $row->analyst_id === $request->user()->id, 403);
$existing = DB::table('desk_messages')->where('request_id', $id)->where('actor_id', $request->user()->id)->where('client_key', $data['client_key'])->first();
@@ -260,49 +319,90 @@ class VirtualDeskController extends Controller
public function attach(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
$data = $request->validate(['version' => 'required|integer', 'file' => 'nullable|required_without:document_id|file|mimetypes:application/pdf,image/png,image/jpeg,text/plain|max:10240',
- 'document_id' => 'nullable|required_without:file|uuid', 'category' => 'required|string|max:80', 'stage' => 'nullable|string|max:3', 'request_id' => 'nullable|uuid', 'valid_until' => 'nullable|date_format:Y-m-d', 'source_reference' => 'required|string|max:3000', 'consent' => 'accepted']);
+ 'document_id' => 'nullable|required_without:file|required_with:reuse_link_id|prohibits:file|uuid', 'reuse_link_id' => 'nullable|uuid|prohibits:file', 'category' => 'nullable|required_without:field_key|string|max:80', 'field_key' => 'nullable|string|max:64',
+ 'stage' => 'nullable|string|max:3', 'request_id' => 'nullable|required_with:field_key|uuid', 'valid_until' => 'nullable|date_format:Y-m-d', 'source_reference' => 'nullable|required_without:document_id|string|max:3000', 'consent' => 'accepted']);
$key = null;
$newId = null;
+ $linkId = null;
+ $reusedLink = false;
try {
- DB::transaction(function () use ($request, $id, $desk, $data, &$key, &$newId) {
+ DB::transaction(function () use ($request, $id, $desk, $data, &$key, &$newId, &$linkId, &$reusedLink) {
+ $row = ($data['request_id'] ?? null) ? $desk->request($request->user(), $data['request_id'], true, true) : null;
$case = $desk->case($request->user(), $id, true, true);
abort_if($case->closed_at, 409, 'Dossier encerrado.');
abort_unless((int) $case->version === (int) $data['version'], 409);
if ($data['stage'] ?? null) {
abort_unless(array_key_exists($data['stage'], config('virtual-desk.steps')), 422);
}
- if ($data['request_id'] ?? null) {
- $row = $desk->request($request->user(), $data['request_id'], true, true);
+ if ($row) {
abort_unless($row->case_id === $id && in_array($row->status, ['draft', 'returned'], true), 409, 'Anexos de pedidos submetidos são imutáveis; use a devolução para corrigir.');
}
- abort_if(DB::table('desk_documents')->where('case_id', $id)->count() >= 100, 422, 'Limite de anexos do dossier atingido.');
- if ($request->hasFile('file')) {
- $file = $request->file('file');
- $hash = hash_file('sha256', $file->getRealPath());
- $duplicate = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->where('d.sha256', $hash)->first();
- if ($duplicate) {
- return;
+ $definition = $row ? $desk->definition($row) : [];
+ $field = ($data['field_key'] ?? null) ? app(DeskAttachments::class)->field($definition, $data['field_key']) : null;
+ if ($field) {
+ if (isset($data['stage']) && $data['stage'] !== $definition['stage']) {
+ throw ValidationException::withMessages(['stage' => 'A utilização nesta pergunta pertence à etapa do pedido; a origem do documento é conservada separadamente.']);
}
- $newId = (string) Str::uuid();
- $key = $file->storeAs('virtual-desk/'.$id, $newId, 'local');
- abort_unless(is_string($key) && $key !== '', 500);
- DB::table('documents')->insert(['id' => $newId, 'source_system' => 'virtual-desk', 'file_name' => basename($file->getClientOriginalName()), 'media_type' => $file->getMimeType(), 'storage_key' => $key,
- 'sha256' => $hash, 'size_bytes' => $file->getSize(), 'uploaded_by' => $request->user()->id, 'status' => 'quarantined', 'data_classification' => 'confidential']);
- $documentId = $newId;
- } else {
- $documentId = $data['document_id'];
- $document = DB::table('documents')->where('id', $documentId)->whereNull('deleted_at')->first();
- abort_unless($document !== null, 404);
- $owned = (int) $document->uploaded_by === $request->user()->id || DB::table('desk_documents as l')->join('desk_cases as c', 'c.id', '=', 'l.case_id')->where('l.document_id', $documentId)->where('c.user_id', $request->user()->id)->whereNull('c.organization_id')->exists();
- abort_unless($owned, 403, 'Não há autorização para reutilizar este documento.');
- if (DB::table('desk_documents')->where('case_id', $id)->where('document_id', $documentId)->exists()) {
- return;
+ abort_unless(app(DeskAttachments::class)->scopedLinksInstalled(), 409, 'Instale a actualização dos vínculos documentais para este formulário.');
+ if ($row->status === 'returned' && ! in_array($data['field_key'], json_decode($row->editable_fields ?? '[]', true), true)) {
+ throw ValidationException::withMessages(['field_key' => 'Esta pergunta não está autorizada para correcção.']);
}
}
- DB::table('desk_documents')->insert(['id' => (string) Str::uuid(), 'case_id' => $id, 'document_id' => $documentId, 'request_id' => $data['request_id'] ?? null,
- 'category' => $data['category'], 'stage' => $data['stage'] ?? null, 'valid_until' => $data['valid_until'] ?? null, 'source_reference' => $data['source_reference'], 'linked_by' => $request->user()->id]);
+ $document = null;
+ if ($request->hasFile('file')) {
+ $file = $request->file('file');
+ if ($field) {
+ app(DeskAttachments::class)->checkMetadata((object) ['media_type' => $file->getMimeType(), 'size_bytes' => $file->getSize()], $field, 'file');
+ }
+ $hash = hash_file('sha256', $file->getRealPath());
+ $document = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->whereNull('d.deleted_at')->where('d.sha256', $hash)->first(['d.*']);
+ if (! $document) {
+ abort_if(DB::table('desk_documents')->where('case_id', $id)->distinct()->count('document_id') >= 100, 422, 'Limite de ficheiros distintos do dossier atingido.');
+ $newId = (string) Str::uuid();
+ $key = $file->storeAs('virtual-desk/'.$id, $newId, 'local');
+ abort_unless(is_string($key) && $key !== '', 500);
+ DB::table('documents')->insert(['id' => $newId, 'source_system' => 'virtual-desk', 'file_name' => basename($file->getClientOriginalName()), 'media_type' => $file->getMimeType(), 'storage_key' => $key,
+ 'sha256' => $hash, 'size_bytes' => $file->getSize(), 'uploaded_by' => $request->user()->id, 'status' => 'quarantined', 'data_classification' => 'confidential']);
+ $document = DB::table('documents')->where('id', $newId)->firstOrFail();
+ }
+ } else {
+ $document = DB::table('documents')->where('id', $data['document_id'])->whereNull('deleted_at')->first();
+ abort_unless($document !== null, 404);
+ $owned = (int) $document->uploaded_by === $request->user()->id || DB::table('desk_documents')->where('case_id', $id)->where('document_id', $document->id)->exists()
+ || DB::table('desk_documents as l')->join('desk_cases as c', 'c.id', '=', 'l.case_id')->where('l.document_id', $document->id)->where('c.user_id', $request->user()->id)->whereNull('c.organization_id')->exists();
+ abort_unless($owned, 403, 'Não há autorização para reutilizar este documento.');
+ }
+ if ($field) {
+ app(DeskAttachments::class)->checkMetadata($document, $field, 'document_id', true);
+ }
+ app(VerifiedDocumentBinary::class)->authorizeOpportunityAttachment($document);
+ $existing = DB::table('desk_documents')->where('case_id', $id)->where('document_id', $document->id)
+ ->where(fn ($q) => ($data['request_id'] ?? null) ? $q->whereNull('request_id')->orWhere('request_id', $data['request_id']) : $q->whereNull('request_id'))->orderByRaw('request_id IS NULL DESC')->first();
+ if ($existing) {
+ $linkId = $existing->id;
+ $reusedLink = true;
+
+ return;
+ }
+ if (! app(DeskAttachments::class)->scopedLinksInstalled() && DB::table('desk_documents')->where('case_id', $id)->where('document_id', $document->id)->exists()) {
+ throw ValidationException::withMessages(['document_id' => 'Instale a actualização dos vínculos para reutilizar o ficheiro noutro pedido, preservando o âmbito anterior.']);
+ }
+ $inCase = DB::table('desk_documents')->where('case_id', $id)->where('document_id', $document->id)->exists();
+ abort_if(! $inCase && DB::table('desk_documents')->where('case_id', $id)->distinct()->count('document_id') >= 100, 422, 'Limite de ficheiros distintos do dossier atingido.');
+ $sourceLink = DB::table('desk_documents as l')->join('desk_cases as c', 'c.id', '=', 'l.case_id')->where('l.document_id', $document->id)
+ ->where(fn ($q) => $q->where('l.case_id', $id)->orWhere(fn ($p) => $p->where('c.user_id', $request->user()->id)->whereNull('c.organization_id')))
+ ->when($data['reuse_link_id'] ?? null, fn ($q, $sourceId) => $q->where('l.id', $sourceId))->orderBy('l.created_at')->orderBy('l.id')->first(['l.*']);
+ abort_if(($data['reuse_link_id'] ?? null) && ! $sourceLink, 403, 'Não há autorização para reutilizar esta referência documental.');
+ $source = $data['source_reference'] ?? $sourceLink?->source_reference;
+ if (! is_string($source) || trim($source) === '') {
+ throw ValidationException::withMessages(['source_reference' => 'Indique a proveniência deste documento; não existe uma referência autorizada para reutilizar.']);
+ }
+ $linkId = (string) Str::uuid();
+ DB::table('desk_documents')->insert(['id' => $linkId, 'case_id' => $id, 'document_id' => $document->id, 'request_id' => $data['request_id'] ?? null,
+ 'category' => $field ? Str::limit($field['label'], 80, '') : $data['category'], 'stage' => $data['stage'] ?? ($field ? $definition['stage'] : $sourceLink?->stage), 'valid_until' => array_key_exists('valid_until', $data) ? $data['valid_until'] : $sourceLink?->valid_until, 'source_reference' => $source, 'linked_by' => $request->user()->id]);
DB::table('desk_cases')->where('id', $id)->update(['version' => $case->version + 1, 'updated_at' => now()]);
- $desk->event(DB::table('desk_cases')->where('id', $id)->first(), $request->user(), 'document_linked', ['document_id' => $documentId, 'source' => $data['source_reference'], 'consent' => true]);
+ $desk->event(DB::table('desk_cases')->where('id', $id)->first(), $request->user(), 'document_linked', ['document_id' => $document->id, 'link_id' => $linkId, 'source' => $source, 'consent' => true, 'field_key' => $data['field_key'] ?? null, 'source_link_id' => $sourceLink?->id,
+ 'reused_source' => $sourceLink ? ['source_reference' => $sourceLink->source_reference, 'category' => $sourceLink->category, 'stage' => $sourceLink->stage, 'valid_until' => $sourceLink->valid_until, 'document_id' => $document->id, 'version_no' => $document->version_no, 'sha256' => trim($document->sha256)] : null], $row);
});
} catch (\Throwable $e) {
if ($key) {
@@ -313,7 +413,10 @@ class VirtualDeskController extends Controller
ScanDocumentForMalware::dispatch($newId)->afterCommit();
}
- return $request->expectsJson() ? response()->json(['ok' => true]) : back()->with('success', 'Documento privado associado; consulte o estado da análise.');
+ $available = $this->documents($id, $request->user());
+
+ return $request->expectsJson() ? response()->json(['ok' => true, 'link_id' => $linkId, 'reused_link' => $reusedLink, 'case_version' => (int) DB::table('desk_cases')->where('id', $id)->value('version'),
+ 'documents' => $available->filter(fn ($d) => ! ($data['request_id'] ?? null) || ! $d->request_id || $d->request_id === $data['request_id'])->values(), 'reusable_documents' => $desk->owns($request->user(), $desk->case($request->user(), $id)) ? $available->values() : []]) : back()->with('success', $reusedLink ? 'Este documento já estava associado; conservou-se a referência registada.' : 'Documento privado associado; consulte o estado da análise.');
}
public function download(Request $request, string $id, string $document, VirtualDesk $desk): BinaryFileResponse|\Illuminate\Http\Response
diff --git a/app/Http/Controllers/VirtualDeskInstallationController.php b/app/Http/Controllers/VirtualDeskInstallationController.php
index e1ca7058..f4046b68 100644
--- a/app/Http/Controllers/VirtualDeskInstallationController.php
+++ b/app/Http/Controllers/VirtualDeskInstallationController.php
@@ -2,6 +2,8 @@
namespace App\Http\Controllers;
+use App\Services\DeskServiceAvailability;
+use App\Services\DeskServiceEditor;
use App\Services\VirtualDeskInstallation;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -79,19 +81,22 @@ class VirtualDeskInstallationController extends Controller
DB::select('select pg_advisory_xact_lock(261008, 2)');
$definition = config('virtual-desk.services.'.$data['code']);
$existing = DB::table('desk_service_versions')->where('code', $data['code'])->orderByDesc('version')->first();
- if ($existing && $existing->status === 'published' && json_decode($existing->definition, true) === $definition) {
+ if ($existing && $existing->status === 'published' && app(DeskServiceEditor::class)->sameDefinition(json_decode($existing->definition, true, 512, JSON_THROW_ON_ERROR), $definition)) {
return $existing;
}
$id = (string) Str::uuid();
+ $effective = app(DeskServiceAvailability::class)->scheduled() ? now()->toDateString() : null;
DB::table('desk_service_versions')->insert(['id' => $id, 'code' => $data['code'], 'version' => ($existing->version ?? 0) + 1, 'status' => 'published',
+ ...($effective ? ['effective_from' => $effective] : []),
'definition' => json_encode($definition), 'source' => json_encode(config('virtual-desk.source')), 'author_id' => $request->user()->id,
'published_by' => $request->user()->id, 'published_at' => now(), 'created_at' => now(), 'updated_at' => now()]);
DB::table('audit_events')->insert(['source_system' => 'virtual-desk', 'entity_type' => 'desk_service_versions', 'entity_id' => $id, 'actor_user_id' => $request->user()->id,
- 'action' => 'internal_service_published', 'after_data' => json_encode(['code' => $data['code'], 'nature' => 'digital_preparation_not_official_form'])]);
+ 'action' => 'internal_service_published', 'after_data' => json_encode(['code' => $data['code'], 'nature' => 'digital_preparation_not_official_form', 'effective_from' => $effective])]);
return DB::table('desk_service_versions')->where('id', $id)->first();
});
- return $request->expectsJson() ? response()->json(['id' => $row->id], 201) : back()->with('success', 'Serviço de preparação interna publicado.');
+ return $request->expectsJson() ? response()->json(['id' => $row->id, 'effective_from' => $row->effective_from ?? null], 201)
+ : back()->with('success', 'Serviço de preparação interna publicado'.(($row->effective_from ?? null) ? ' com entrada em vigor em '.$row->effective_from : '').'.');
}
}
diff --git a/app/Http/Controllers/VirtualDeskOperationsController.php b/app/Http/Controllers/VirtualDeskOperationsController.php
index 7a8f58cf..667f938a 100644
--- a/app/Http/Controllers/VirtualDeskOperationsController.php
+++ b/app/Http/Controllers/VirtualDeskOperationsController.php
@@ -3,14 +3,16 @@
namespace App\Http\Controllers;
use App\Services\Ai\InvestorGuidanceEvidence;
+use App\Services\DeskPaymentEvidence;
+use App\Services\VerifiedDocumentBinary;
use App\Services\VirtualDesk;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
/** Manual operations use the same requests, documents and encrypted audit history. */
class VirtualDeskOperationsController extends Controller
@@ -25,16 +27,19 @@ class VirtualDeskOperationsController extends Controller
abort_unless(! $desk->owns($request->user(), $case, false) && ($request->user()->can('manage-portal') || ($row && (int) $row->analyst_id === $request->user()->id)), 403);
}
- private function cleanDocument(string $caseId, string $documentId, ?string $requestId): \stdClass
+ private function cleanDocument(string $caseId, string $documentId, ?string $requestId, ?string $linkId = null): \stdClass
{
$doc = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')
->where('l.case_id', $caseId)->where('d.id', $documentId)->whereNull('d.deleted_at')
+ ->when($linkId, fn ($q) => $q->where('l.id', $linkId))
->where(fn ($q) => $q->whereNull('l.request_id')->when($requestId, fn ($p) => $p->orWhere('l.request_id', $requestId)))
->first(['d.*', 'l.id as link_id']);
abort_unless($doc !== null && $doc->status === 'active' && $doc->malware_scan_status === 'clean' && trim($doc->sha256) === $doc->malware_scanned_sha256, 422, 'Documento indisponível para conferência: verifique autorização, integridade e análise antimalware.');
- $path = realpath(Storage::disk('local')->path($doc->storage_key));
- $root = realpath(Storage::disk('local')->path(''));
- abort_unless($path && $root && str_starts_with($path, $root.DIRECTORY_SEPARATOR) && is_file($path) && is_string($hash = hash_file('sha256', $path)) && hash_equals(trim($doc->sha256), $hash), 422, 'O ficheiro original ou a sua integridade não pôde ser confirmado.');
+ try {
+ app(VerifiedDocumentBinary::class)->respond($doc);
+ } catch (HttpExceptionInterface) {
+ abort(422, 'O original, a sua autorização ou integridade não pôde ser confirmado.');
+ }
return $doc;
}
@@ -43,15 +48,16 @@ class VirtualDeskOperationsController extends Controller
{
$data = $request->validate(['version' => 'required|integer|min:1', 'request_id' => 'nullable|uuid', 'outcome' => 'required|in:internal_verified,internal_issue,contradiction_identified', 'what_checked' => 'required|string|min:3|max:3000', 'evidence' => 'required|string|min:3|max:5000', 'supports' => 'nullable|array|max:4', 'supports.*' => ['string', Rule::in(InvestorGuidanceEvidence::FIELDS)]]);
DB::transaction(function () use ($request, $id, $document, $desk, $data) {
- $case = $desk->case($request->user(), $id, false, true);
- abort_unless(! $case->closed_at && (int) $case->version === (int) $data['version'], 409);
+ $desk->case($request->user(), $id);
$link = DB::table('desk_documents')->where('case_id', $id)->where('id', $document)->first();
abort_unless($link !== null, 404);
$requestId = $link->request_id ?: ($data['request_id'] ?? null);
$row = $requestId ? $desk->request($request->user(), $requestId, false, true) : null;
+ $case = $desk->case($request->user(), $id, false, true);
+ abort_unless(! $case->closed_at && (int) $case->version === (int) $data['version'], 409);
abort_if($row && $row->case_id !== $id, 422);
$this->reviewer($request, $desk, $case, $row);
- $doc = $this->cleanDocument($id, $link->document_id, $requestId);
+ $doc = $this->cleanDocument($id, $link->document_id, $requestId, $link->id);
DB::table('desk_cases')->where('id', $id)->update(['version' => $case->version + 1, 'updated_at' => now()]);
$desk->event(DB::table('desk_cases')->where('id', $id)->firstOrFail(), $request->user(), 'document_reviewed', [
...$data, 'document_id' => $doc->id, 'link_id' => $link->id, 'sha256' => trim($doc->sha256), 'document_version' => (int) $doc->version_no, 'reviewer_id' => $request->user()->id,
@@ -64,26 +70,58 @@ class VirtualDeskOperationsController extends Controller
public function payment(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
- $data = $request->validate(['reference' => 'required|string|max:255', 'amount' => ['required', 'regex:/^\d{1,12}(\.\d{1,2})?$/', 'numeric', 'gt:0'], 'currency' => 'required|in:MZN,USD,EUR', 'source_reference' => 'required|string|min:3|max:3000', 'document_id' => 'nullable|uuid', 'consent' => 'accepted']);
+ $data = $request->validate(['reference' => 'required|string|max:255', 'amount' => ['required', 'regex:/^\d{1,12}(\.\d{1,2})?$/', 'numeric', 'gt:0'], 'currency' => 'required|in:MZN,USD,EUR', 'source_reference' => 'required|string|min:3|max:3000', 'document_id' => 'nullable|uuid', 'document_link_id' => 'nullable|uuid', 'consent' => 'accepted']);
DB::transaction(function () use ($request, $id, $desk, $data) {
$row = $desk->request($request->user(), $id, true, true);
- $case = $desk->case($request->user(), $row->case_id);
- abort_if(in_array($row->status, ['closed', 'cancelled'], true), 409);
- if ($data['document_id'] ?? null) {
- abort_unless(DB::table('desk_documents')->where('case_id', $case->id)->where('document_id', $data['document_id'])->where(fn ($q) => $q->whereNull('request_id')->orWhere('request_id', $id))->exists(), 422);
- }
+ $case = $desk->case($request->user(), $row->case_id, true, true);
+ abort_if($case->closed_at || in_array($row->status, ['closed', 'cancelled'], true), 409);
+ $evidence = app(DeskPaymentEvidence::class)->snapshot($case->id, $id, $data);
// References are supplied by the investor; no bank reference or fee is generated.
+ DB::select('SELECT pg_advisory_xact_lock(hashtext(?))', ['virtual-desk-payment:'.$data['reference']]);
$existing = DB::table('desk_payments')->where('reference', $data['reference'])->first();
if ($existing) {
$parts = explode('.', (string) $data['amount']);
$amount = (ltrim($parts[0], '0') ?: '0').'.'.str_pad($parts[1] ?? '', 2, '0');
- abort_unless($existing->request_id === $id && (string) $existing->amount === $amount && $existing->currency === $data['currency'] && $existing->source_reference === $data['source_reference'] && $existing->document_id === ($data['document_id'] ?? null), 409);
+ $saved = app(DeskPaymentEvidence::class)->forRequest($id)[$existing->id] ?? null;
+ abort_unless($existing->request_id === $id && (string) $existing->amount === $amount && $existing->currency === $data['currency'] && $existing->source_reference === $data['source_reference'] && $existing->document_id === ($evidence['document_id'] ?? null)
+ && (! ($data['document_link_id'] ?? null) || ($saved['link_id'] ?? null) === $data['document_link_id']), 409);
return;
}
$payment = (string) Str::uuid();
- DB::table('desk_payments')->insert(['id' => $payment, 'request_id' => $id, 'reference' => $data['reference'], 'amount' => $data['amount'], 'currency' => $data['currency'], 'source_reference' => $data['source_reference'], 'document_id' => $data['document_id'] ?? null, 'status' => 'pending', 'created_at' => now(), 'updated_at' => now()]);
- $desk->event($case, $request->user(), 'payment_declared', ['payment_id' => $payment, 'consent' => true, 'scope' => 'manual_declaration_no_bank_confirmation'], $row);
+ DB::table('desk_payments')->insert(['id' => $payment, 'request_id' => $id, 'reference' => $data['reference'], 'amount' => $data['amount'], 'currency' => $data['currency'], 'source_reference' => $data['source_reference'], 'document_id' => $evidence['document_id'] ?? null, 'status' => 'pending', 'created_at' => now(), 'updated_at' => now()]);
+ $desk->event($case, $request->user(), 'payment_declared', ['payment_id' => $payment, 'payment_version' => 1, 'document_evidence' => $evidence, 'consent' => true, 'scope' => 'manual_declaration_no_bank_confirmation'], $row);
+ });
+
+ return $this->result($request);
+ }
+
+ public function paymentDocument(Request $request, string $id, string $payment, VirtualDesk $desk): JsonResponse|RedirectResponse
+ {
+ $data = $request->validate(['version' => 'required|integer|min:1', 'document_link_id' => 'required|uuid', 'reason' => 'required|string|min:3|max:3000', 'consent' => 'accepted', 'client_key' => 'required|uuid']);
+ $data['version'] = (int) $data['version'];
+ $data['consent'] = true;
+ DB::transaction(function () use ($request, $id, $payment, $desk, $data) {
+ $row = $desk->request($request->user(), $id, true, true);
+ $case = $desk->case($request->user(), $row->case_id, true, true);
+ abort_if($case->closed_at || in_array($row->status, ['closed', 'cancelled'], true), 409);
+ $record = DB::table('desk_payments')->where('id', $payment)->where('request_id', $id)->lockForUpdate()->first();
+ abort_unless($record !== null, 404);
+ foreach (DB::table('desk_events')->where('request_id', $id)->where('actor_id', $request->user()->id)->where('action', 'payment_document_linked')->get(['payload']) as $event) {
+ $saved = $desk->decode($event->payload);
+ if (($saved['client_key'] ?? null) === $data['client_key']) {
+ abort_unless(($saved['payment_id'] ?? null) === $payment && ($saved['operation'] ?? null) === $data, 409, 'A operação já foi utilizada com outros dados. Inicie uma nova associação.');
+
+ return;
+ }
+ }
+ abort_unless((int) $record->version === (int) $data['version'] && in_array($record->status, ['pending', 'internal_issue'], true), 409, 'O registo mudou ou já está conferido. Actualize antes de associar outro comprovativo.');
+ $evidence = app(DeskPaymentEvidence::class)->snapshot($case->id, $id, $data);
+ abort_unless($evidence !== null, 422);
+ $previous = app(DeskPaymentEvidence::class)->forRequest($id)[$payment] ?? null;
+ DB::table('desk_payments')->where('id', $payment)->update(['document_id' => $evidence['document_id'], 'status' => 'pending', 'reason' => null, 'verified_by' => null, 'version' => $record->version + 1, 'updated_at' => now()]);
+ $desk->event($case, $request->user(), 'payment_document_linked', ['payment_id' => $payment, 'payment_version' => $record->version + 1, 'previous_document_id' => $record->document_id, 'previous_document_evidence' => $previous,
+ 'document_evidence' => $evidence, 'client_key' => $data['client_key'], 'operation' => $data, 'reason' => $data['reason'], 'consent' => true, 'scope' => 'documentary_correction_no_amount_change_or_payment_confirmation'], $row);
});
return $this->result($request);
@@ -94,19 +132,21 @@ class VirtualDeskOperationsController extends Controller
$data = $request->validate(['version' => 'required|integer|min:1', 'status' => 'required|in:internal_verified,internal_issue', 'reason' => 'required|string|min:3|max:3000', 'evidence' => 'required|string|min:3|max:5000']);
DB::transaction(function () use ($request, $id, $payment, $desk, $data) {
$row = $desk->request($request->user(), $id, false, true);
- $case = $desk->case($request->user(), $row->case_id);
+ $case = $desk->case($request->user(), $row->case_id, false, true);
$this->reviewer($request, $desk, $case, $row);
- abort_if(in_array($row->status, ['closed', 'cancelled'], true), 409);
+ abort_if($case->closed_at || in_array($row->status, ['closed', 'cancelled'], true), 409);
$record = DB::table('desk_payments')->where('request_id', $id)->where('id', $payment)->lockForUpdate()->first();
abort_unless($record !== null, 404);
abort_unless((int) $record->version === (int) $data['version'], 409);
+ $evidence = app(DeskPaymentEvidence::class)->forRequest($id)[$payment] ?? null;
$doc = null;
if ($data['status'] === 'internal_verified') {
abort_unless($record->document_id, 422, 'A conferência exige um comprovativo autorizado.');
- $doc = $this->cleanDocument($case->id, $record->document_id, $id);
+ $doc = $this->cleanDocument($case->id, $record->document_id, $id, $evidence['link_id'] ?? null);
+ abort_if($evidence && ($evidence['document_id'] !== $doc->id || $evidence['document_version'] !== (int) $doc->version_no || ! hash_equals($evidence['sha256'], trim($doc->sha256))), 422, 'O original já não corresponde ao comprovativo associado. Registe a correcção antes de conferir.');
}
DB::table('desk_payments')->where('id', $payment)->update(['status' => $data['status'], 'reason' => $data['reason'], 'verified_by' => $request->user()->id, 'version' => $record->version + 1, 'updated_at' => now()]);
- $desk->event($case, $request->user(), 'payment_reviewed', [...$data, 'payment_id' => $payment, 'document_id' => $doc?->id, 'sha256' => $doc ? trim($doc->sha256) : null, 'reviewer_id' => $request->user()->id, 'scope' => 'internal_proof_check_no_bank_confirmation'], $row);
+ $desk->event($case, $request->user(), 'payment_reviewed', [...$data, 'payment_id' => $payment, 'payment_version' => $record->version + 1, 'document_id' => $record->document_id, 'document_evidence' => $evidence, 'sha256' => $doc ? trim($doc->sha256) : null, 'reviewer_id' => $request->user()->id, 'scope' => 'internal_proof_check_no_bank_confirmation'], $row);
});
return $this->result($request);
@@ -117,9 +157,9 @@ class VirtualDeskOperationsController extends Controller
$data = $request->validate(['channel' => 'required|in:phone,email,sms,whatsapp,in_person', 'direction' => 'required|in:received,sent', 'occurred_at' => 'required|date|before_or_equal:now', 'summary' => 'required|string|min:3|max:5000', 'evidence' => 'required|string|min:3|max:3000', 'client_key' => 'required|uuid']);
DB::transaction(function () use ($request, $id, $desk, $data) {
$row = $desk->request($request->user(), $id, false, true);
- $case = $desk->case($request->user(), $row->case_id);
+ $case = $desk->case($request->user(), $row->case_id, false, true);
abort_unless($desk->owns($request->user(), $case) || $request->user()->can('manage-portal') || (int) $row->analyst_id === $request->user()->id, 403);
- abort_if(in_array($row->status, ['closed', 'cancelled'], true), 409);
+ abort_if($case->closed_at || in_array($row->status, ['closed', 'cancelled'], true), 409);
foreach (DB::table('desk_events')->where('request_id', $id)->where('actor_id', $request->user()->id)->where('action', 'manual_communication_recorded')->get(['payload']) as $event) {
$saved = $desk->decode($event->payload);
if (($saved['client_key'] ?? null) === $data['client_key']) {
diff --git a/app/Http/Middleware/CollectPublicSearchMetrics.php b/app/Http/Middleware/CollectPublicSearchMetrics.php
new file mode 100644
index 00000000..813b2781
--- /dev/null
+++ b/app/Http/Middleware/CollectPublicSearchMetrics.php
@@ -0,0 +1,25 @@
+attributes->get(PublicSearchMetrics::ATTRIBUTE);
+ $request->attributes->remove(PublicSearchMetrics::ATTRIBUTE);
+ $prefetch = str_contains(strtolower($request->header('Purpose', '').' '.$request->header('Sec-Purpose', '')), 'prefetch') || $request->header('X-Inertia-Prefetch') === 'true';
+ $privacySignal = $request->header('DNT') === '1' || $request->header('Sec-GPC') === '1';
+ if ($request->isMethod('GET') && $response->getStatusCode() === 200 && ! $prefetch && ! $privacySignal && is_array($candidate) && isset($candidate['channel'], $candidate['empty']) && is_string($candidate['channel']) && is_bool($candidate['empty'])) {
+ app(PublicSearchMetrics::class)->record($candidate['channel'], $candidate['empty']);
+ }
+
+ return $response;
+ }
+}
diff --git a/app/Http/Resources/PublicBusinessOpportunityResource.php b/app/Http/Resources/PublicBusinessOpportunityResource.php
index 7b5c57bd..d583070a 100644
--- a/app/Http/Resources/PublicBusinessOpportunityResource.php
+++ b/app/Http/Resources/PublicBusinessOpportunityResource.php
@@ -3,6 +3,7 @@
namespace App\Http\Resources;
use App\Services\ExistingBusinessClassification;
+use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -24,6 +25,10 @@ class PublicBusinessOpportunityResource extends JsonResource
'amount_max' => data_get($this->resource, 'amount_max'),
'available_percentage' => data_get($this->resource, 'available_percentage'),
'published_at' => data_get($this->resource, 'published_at'),
+ 'distance_km' => $this->resource->getAttribute('distance_km') !== null ? round((float) $this->resource->getAttribute('distance_km'), 1) : null,
+ 'location_recorded_at' => $this->resource->getAttribute('location_recorded_at') ? CarbonImmutable::parse($this->resource->getAttribute('location_recorded_at'))->toIso8601String() : null,
+ 'location_source_reference' => $this->resource->getAttribute('location_source_reference'),
+ 'location_source_date' => $this->resource->getAttribute('location_source_date'),
'sector' => $this->whenLoaded('sector', fn () => data_get($this->resource, 'sector')?->only(['name', 'slug'])),
'province' => $this->resource->getAttribute('province'),
'district' => $this->resource->getAttribute('district'),
diff --git a/app/Jobs/ScanDocumentForMalware.php b/app/Jobs/ScanDocumentForMalware.php
index 38eee396..bcc70581 100644
--- a/app/Jobs/ScanDocumentForMalware.php
+++ b/app/Jobs/ScanDocumentForMalware.php
@@ -2,7 +2,9 @@
namespace App\Jobs;
+use App\Services\Malware\DocumentScanAttempts;
use App\Services\Malware\MalwareScanner;
+use App\Services\OpportunityTechnicalIncidents;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -11,6 +13,7 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Throwable;
@@ -25,7 +28,28 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
public int $uniqueFor = 600;
- public function __construct(public readonly string $documentId) {}
+ public ?string $executionId = null;
+
+ /** @var array|null */
+ public ?array $opportunityContext = null;
+
+ /** @param array|null $opportunityContext */
+ public function __construct(public readonly string $documentId, ?array $opportunityContext = null)
+ {
+ $this->executionId = (string) Str::uuid();
+ $this->opportunityContext = $opportunityContext;
+ }
+
+ /** Queue UUID also supports payloads serialized before executionId existed. */
+ public function runIdentifier(): string
+ {
+ if ($this->executionId !== null) {
+ return $this->executionId;
+ }
+ $queued = $this->job?->uuid();
+
+ return is_string($queued) && Str::isUuid($queued) ? $queued : ($this->executionId = (string) Str::uuid());
+ }
public function uniqueId(): string
{
@@ -51,11 +75,20 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
if ($row->malware_scan_status === 'infected') {
return null;
}
+ $attempts = app(DocumentScanAttempts::class);
+ if ($attempts->completed($row->id, $this->runIdentifier())) {
+ return null;
+ }
+ if ($row->malware_scan_status === 'scanning' && $attempts->owns($row, $this->runIdentifier(), (int) $this->attempts())) {
+ return null;
+ }
+ $attempt = $attempts->start($row, $this->runIdentifier(), (int) $this->attempts());
DB::table('documents')->where('id', $this->documentId)->update([
'status' => 'quarantined', 'malware_scan_status' => 'scanning', 'malware_failure_reason' => null,
- 'malware_scan_attempts' => DB::raw('malware_scan_attempts + 1'), 'updated_at' => now(),
+ 'malware_scan_attempts' => $attempt, 'updated_at' => now(),
]);
+ $row->malware_scan_attempts = $attempt;
return $row;
});
@@ -69,22 +102,32 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
$root = $disk->path('');
$path = $disk->path($document->storage_key);
$temporary = null;
+ $operationFailed = false;
try {
if (($document->storage_encryption ?? null) === 'laravel') {
$temporary = tempnam($root, 'scan-private-');
if ($temporary === false) {
throw new \RuntimeException('Private scan workspace unavailable');
}
- chmod($temporary, 0600);
- file_put_contents($temporary, Crypt::decryptString($disk->get($document->storage_key)));
+ if (! @chmod($temporary, 0600)) {
+ throw new \RuntimeException('Private scan workspace permissions unavailable');
+ }
+ $plain = Crypt::decryptString($disk->get($document->storage_key));
+ if (file_put_contents($temporary, $plain) !== strlen($plain)) {
+ throw new \RuntimeException('Private scan workspace write incomplete');
+ }
+ unset($plain);
$path = $temporary;
}
$beforeHash = $this->fileHash($path);
if ($beforeHash === null || ! hash_equals(trim($document->sha256), $beforeHash)) {
- $this->record($document, [
- 'result' => 'inconclusive', 'reason_code' => 'file_hash_mismatch', 'engine' => 'ClamAV',
+ $applied = $this->record($document, [
+ 'result' => 'inconclusive', 'reason_code' => 'file_hash_mismatch', 'engine' => 'not_run',
'engine_version' => 'unknown', 'signatures_at' => null, 'duration_ms' => 0, 'detail' => null,
], $startedAt, 'inconclusive');
+ if ($applied) {
+ $this->notify('scan_inconclusive');
+ }
return;
}
@@ -99,10 +142,29 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
}
$result['file_sha256'] = $afterHash;
- $this->record($document, $result, $startedAt, $result['result']);
+ $applied = $this->record($document, $result, $startedAt, $result['result']);
+ if (in_array($applied, ['inconclusive', 'failed'], true)) {
+ $this->notify($applied === 'failed' ? 'scan_worker_failed' : 'scan_inconclusive');
+ }
+ } catch (Throwable $error) {
+ $operationFailed = true;
+ throw $error;
} finally {
if (is_string($temporary) && is_file($temporary)) {
- unlink($temporary);
+ try {
+ $removed = @unlink($temporary);
+ } catch (Throwable) {
+ $removed = false;
+ }
+ if (! $removed) {
+ try {
+ Log::warning('Private scan workspace cleanup requires verification.', ['reference' => $this->runIdentifier(), 'error_code' => 'scan_cleanup_unconfirmed']);
+ } catch (Throwable) {
+ }
+ if (! $operationFailed) {
+ $this->notify('scan_cleanup_unconfirmed');
+ }
+ }
}
}
}
@@ -113,11 +175,38 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
if (! $document || $document->status === 'deleted' || $document->deleted_at !== null) {
return;
}
+ if ($document->malware_scan_status === 'pending') {
+ // A failure before claiming the row cannot overwrite another scan result.
+ $this->notify('scan_worker_failed');
- $this->record($document, [
- 'result' => 'failed', 'reason_code' => 'scanner_unavailable_after_retries', 'engine' => 'ClamAV',
+ return;
+ }
+ if ($document->malware_scan_status !== 'scanning' || ! app(DocumentScanAttempts::class)->owns($document, $this->runIdentifier(), (int) $this->attempts())) {
+ return;
+ }
+ $descriptor = app(DocumentScanAttempts::class)->descriptor($document, $this->runIdentifier(), (int) $this->attempts());
+ if ($descriptor === null) {
+ $this->notify('scan_worker_failed');
+
+ return;
+ }
+ $document->sha256 = $descriptor['sha256'];
+ $document->size_bytes = $descriptor['size_bytes'];
+
+ $applied = $this->record($document, [
+ 'result' => 'failed', 'reason_code' => 'scan_failed_after_retries', 'engine' => 'unknown',
'engine_version' => 'unknown', 'signatures_at' => null, 'duration_ms' => null, 'detail' => null,
], now(), 'failed');
+ if ($applied) {
+ $this->notify('scan_worker_failed');
+ }
+ }
+
+ private function notify(string $errorCode): void
+ {
+ if ($this->opportunityContext !== null) {
+ app(OpportunityTechnicalIncidents::class)->recordScan($this->opportunityContext, $this->runIdentifier(), $errorCode);
+ }
}
private function fileHash(string $path): ?string
@@ -130,12 +219,17 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
}
/** @param array $result */
- private function record(\stdClass $document, array $result, \DateTimeInterface $startedAt, string $state): void
+ private function record(\stdClass $document, array $result, \DateTimeInterface $startedAt, string $state): ?string
{
- DB::transaction(function () use ($document, $result, $startedAt, $state): void {
+ return DB::transaction(function () use ($document, $result, $startedAt, $state): ?string {
$locked = DB::table('documents')->where('id', $this->documentId)->lockForUpdate()->first();
if (! $locked || $locked->status === 'deleted' || $locked->deleted_at !== null) {
- return;
+ return null;
+ }
+ if ($locked->malware_scan_status !== 'scanning' || ! app(DocumentScanAttempts::class)->owns($locked, $this->runIdentifier(), (int) $this->attempts(), (int) $document->malware_scan_attempts)) {
+ app(DocumentScanAttempts::class)->discarded($locked, $this->runIdentifier(), (int) $this->attempts(), (int) $document->malware_scan_attempts);
+
+ return null;
}
$sameBytes = hash_equals(trim($document->sha256), trim((string) $locked->sha256));
@@ -160,13 +254,16 @@ class ScanDocumentForMalware implements ShouldBeUnique, ShouldQueue
'updated_at' => $finishedAt,
]);
DB::table('document_malware_scans')->insert([
- 'id' => $scanId, 'document_id' => $this->documentId, 'file_sha256' => trim($locked->sha256),
+ 'id' => $scanId, 'document_id' => $this->documentId, 'file_sha256' => trim($document->sha256),
'result' => $finalState, 'reason_code' => $reason,
'engine' => $result['engine'] ?? 'ClamAV', 'engine_version' => $result['engine_version'] ?? 'unknown',
'signatures_at' => $result['signatures_at'] ?? null, 'started_at' => $startedAt,
'finished_at' => $finishedAt, 'duration_ms' => $result['duration_ms'] ?? null,
- 'file_size_bytes' => $locked->size_bytes ?? null, 'created_at' => $finishedAt, 'updated_at' => $finishedAt,
+ 'file_size_bytes' => $document->size_bytes ?? null, 'created_at' => $finishedAt, 'updated_at' => $finishedAt,
]);
+ app(DocumentScanAttempts::class)->finish($document, $this->runIdentifier(), (int) $this->attempts(), $scanId, $state === 'failed');
+
+ return $finalState;
});
}
}
diff --git a/app/Models/CrmTask.php b/app/Models/CrmTask.php
index 1be7895b..cefdee9c 100644
--- a/app/Models/CrmTask.php
+++ b/app/Models/CrmTask.php
@@ -3,6 +3,8 @@
namespace App\Models;
use Carbon\CarbonImmutable;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\Schema;
/**
* @property string|null $lead_id
@@ -13,4 +15,23 @@ class CrmTask extends CrmRecord
protected $table = 'tasks';
protected $casts = ['due_at' => 'immutable_datetime'];
+
+ /**
+ * @param Builder $query
+ * @return Builder
+ */
+ public function scopeAvailableForWork(Builder $query): Builder
+ {
+ $query->whereNull('tasks.deleted_at')->whereIn('tasks.status', ['open', 'in_progress']);
+ if (Schema::hasColumn('tasks', 'desk_case_id')) {
+ if (Schema::hasColumn('desk_cases', 'closed_at')) {
+ $query->where(fn ($q) => $q->whereNull('tasks.desk_case_id')->orWhereExists(fn ($desk) => $desk->selectRaw('1')->from('desk_cases')
+ ->whereColumn('desk_cases.id', 'tasks.desk_case_id')->whereNull('desk_cases.closed_at')));
+ } else {
+ $query->whereNull('tasks.desk_case_id');
+ }
+ }
+
+ return $query;
+ }
}
diff --git a/app/Services/Ai/AssistiveRules.php b/app/Services/Ai/AssistiveRules.php
index 737ca9e3..c61c35a9 100644
--- a/app/Services/Ai/AssistiveRules.php
+++ b/app/Services/Ai/AssistiveRules.php
@@ -69,7 +69,8 @@ final class AssistiveRules
foreach (Lead::whereIn('data_classification', ['public', 'internal'])->whereNull('owner_user_id')->orderBy('id')->limit(20)->get(['id']) as $lead) {
$alerts[] = ['record_type' => 'lead', 'record_id' => $lead->id, 'rule' => 'missing_owner', 'source_url' => '/management/crm/leads/'.$lead->id];
}
- foreach (Lead::whereIn('data_classification', ['public', 'internal'])->whereIn('status', ['new', 'qualified'])->whereDoesntHave('tasks', fn ($q) => $q->whereIn('status', ['open', 'in_progress']))
+ foreach (Lead::whereIn('data_classification', ['public', 'internal'])->whereIn('status', ['new', 'qualified'])
+ ->whereNotExists(CrmTask::availableForWork()->whereColumn('tasks.lead_id', 'leads.id')->selectRaw('1')->toBase())
->orderBy('id')->limit(20)->get(['id']) as $lead) {
$alerts[] = ['record_type' => 'lead', 'record_id' => $lead->id, 'rule' => 'missing_next_action', 'source_url' => '/management/crm/leads/'.$lead->id];
}
@@ -91,7 +92,7 @@ final class AssistiveRules
/** @return list> */
public function sla(): array
{
- return array_values(CrmTask::whereIn('data_classification', ['public', 'internal'])->whereIn('status', ['open', 'in_progress'])->where('due_at', '<', now())->orderBy('due_at')->limit(50)
+ return array_values(CrmTask::whereIn('data_classification', ['public', 'internal'])->availableForWork()->where('due_at', '<', now())->orderBy('due_at')->limit(50)
->get()->map(fn ($task) => [
'record_type' => 'task', 'record_id' => $task->id, 'rule' => 'overdue_open_task',
'due_at' => $task->getAttribute('due_at')?->toIso8601String(), 'lead_id' => $task->lead_id,
diff --git a/app/Services/Ai/InvestorGuidance.php b/app/Services/Ai/InvestorGuidance.php
index eea74a1c..4e1fcabc 100644
--- a/app/Services/Ai/InvestorGuidance.php
+++ b/app/Services/Ai/InvestorGuidance.php
@@ -4,8 +4,10 @@ namespace App\Services\Ai;
use App\Models\CrmTask;
use App\Models\InvestmentSubmission;
+use App\Models\Lead;
use App\Models\SimulationFormDraft;
use App\Models\User;
+use App\Services\CrmNextAction;
use App\Services\InvestmentGeography;
use App\Services\VirtualDesk;
use Illuminate\Support\Arr;
@@ -152,7 +154,7 @@ class InvestorGuidance
->get(['t.id', 't.title', 't.status', 't.due_at', 't.version_no', 't.desk_request_id', 't.accepted_by', 't.accepted_at', 't.assignee_user_id', 'u.name as assignee_name', 't.external_sync_status']);
return ['version' => $case->version, 'rules_version' => InvestorGuidanceRules::VERSION, 'computed_at' => now()->toIso8601String(),
- ...$context, 'phases' => $phases, 'tasks' => $tasks, 'actions' => $actions, 'can_write' => $this->desk->owns($actor, $case),
+ ...$context, 'phases' => $phases, 'tasks' => $tasks, 'actions' => $actions, 'can_write' => ! $case->closed_at && $this->desk->owns($actor, $case), 'can_update_tasks' => ! $case->closed_at,
'external_ai' => ['status' => 'not_configured', 'model' => null, 'consulted' => []],
'calculator_versions' => ['business_financial_plan' => hash_file('sha256', resource_path('js/lib/business-financial-plan.ts')), 'financial_calculators' => hash_file('sha256', resource_path('js/lib/financial-calculators.ts')), 'project_dossier' => hash_file('sha256', resource_path('js/lib/project-dossier.ts'))],
'crm' => ['internal' => 'available', 'external' => 'out_of_scope', 'reason' => 'O acompanhamento usa o CRM interno existente. A sincronização externa está fora desta fase; nenhum contacto, mensagem ou documento é transmitido.']];
@@ -235,10 +237,16 @@ class InvestorGuidance
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'status' => ['required', Rule::in(['open', 'in_progress', 'done', 'cancelled'])],
'reason' => 'required|string|min:3|max:3000', 'assignee_user_id' => 'nullable|integer|exists:users,id', 'due_at' => 'nullable|date|after:now'])->validate();
DB::transaction(function () use ($actor, $id, $taskId, $data) {
- $case = $this->desk->case($actor, $id);
+ $case = $this->desk->case($actor, $id, false, true);
+ $this->desk->assertOpen($case);
+ $candidate = CrmTask::where('desk_case_id', $id)->whereKey($taskId)->firstOrFail();
+ // Match CRM lock order, so two response channels cannot finish each other's only replacement.
+ $lead = $candidate->lead_id === null ? null : Lead::withTrashed()->whereKey($candidate->lead_id)->lockForUpdate()->firstOrFail();
$task = CrmTask::where('desk_case_id', $id)->whereKey($taskId)->lockForUpdate()->firstOrFail();
+ abort_unless($task->lead_id === $candidate->lead_id, 409, 'O acompanhamento associado mudou. Recupere a tarefa actual.');
abort_unless($actor->can('manage-portal') || (int) $task->getAttribute('assignee_user_id') === $actor->id, 403);
abort_unless((int) $task->getAttribute('version_no') === (int) $data['version'], 409);
+ app(CrmNextAction::class)->assertMayFinish($lead, $task, $data['status']);
$updates = ['status' => $data['status'], 'version_no' => $data['version'] + 1];
if ($data['assignee_user_id'] ?? null) {
abort_unless($actor->can('manage-portal'), 403);
diff --git a/app/Services/BusinessFormSchema.php b/app/Services/BusinessFormSchema.php
index 216823b8..3955630b 100644
--- a/app/Services/BusinessFormSchema.php
+++ b/app/Services/BusinessFormSchema.php
@@ -64,6 +64,7 @@ final class BusinessFormSchema
'location_notes' => ['step' => 5, 'pt' => 'Endereço ou referência (interno)', 'en' => 'Address or reference (internal)', 'type' => 'textarea', 'max' => 2000],
'location_unknown' => ['step' => 5, 'pt' => 'Não conheço a localização exacta', 'en' => 'I do not know the exact location', 'type' => 'select', 'max' => 3, 'options' => ['yes' => 'Sim', 'no' => 'Não'], 'when' => ['geography_scope' => ['specific', 'multiple']]],
'disclosure_precision' => ['step' => 5, 'pt' => 'Precisão de divulgação', 'en' => 'Disclosure precision', 'type' => 'select', 'max' => 30, 'options' => ['exact' => 'Localização exacta (sujeita a aprovação)', 'approximate' => 'Localização aproximada', 'administrative' => 'Apenas território administrativo'], 'when' => ['geography_scope' => ['specific', 'multiple']]],
+ ...self::pointFields(),
'asset_notes' => ['step' => 6, 'pt' => 'Resumo dos activos e direitos declarados', 'en' => 'Declared assets and rights summary', 'type' => 'textarea', 'max' => 2000],
'source_reference' => ['step' => 7, 'pt' => 'Referência da fonte', 'en' => 'Source reference', 'type' => 'textarea', 'max' => 2000],
'source_provider' => ['step' => 7, 'pt' => 'Quem forneceu os dados?', 'en' => 'Who supplied the information?', 'type' => 'text', 'max' => 500],
@@ -79,8 +80,27 @@ final class BusinessFormSchema
];
}
- /** @return array> */
- public static function rules(): array
+ /** @return array,when?:array>}> */
+ private static function pointFields(): array
+ {
+ $when = ['geography_scope' => ['specific', 'multiple'], 'disclosure_precision' => ['exact'], 'location_unknown' => ['no']];
+ $active = [...$when, 'location_point_enabled' => ['yes']];
+
+ return [
+ 'location_point_enabled' => ['step' => 5, 'pt' => 'Preparar um ponto exacto para publicação e pesquisa por raio?', 'en' => 'Prepare an exact point for publication and radius searches?', 'type' => 'select', 'max' => 3, 'options' => ['yes' => 'Sim — o ponto substituirá a localização primária na publicação aprovada', 'no' => 'Não — conservar o cadastro de localizações existente'], 'when' => $when],
+ 'location_point_territory' => ['step' => 5, 'pt' => 'Localização já declarada a que pertence o ponto primário', 'en' => 'Previously declared location for the primary point', 'type' => 'point_territory', 'max' => 150, 'when' => [...$active, 'geography_scope' => ['multiple']]],
+ 'location_latitude' => ['step' => 5, 'pt' => 'Latitude WGS84 (graus decimais, -90 a 90)', 'en' => 'WGS84 latitude (decimal degrees, -90 to 90)', 'type' => 'decimal', 'max' => 16, 'when' => $active],
+ 'location_longitude' => ['step' => 5, 'pt' => 'Longitude WGS84 (graus decimais, -180 a 180)', 'en' => 'WGS84 longitude (decimal degrees, -180 to 180)', 'type' => 'decimal', 'max' => 16, 'when' => $active],
+ 'location_point_source_mode' => ['step' => 5, 'pt' => 'Fonte das coordenadas', 'en' => 'Coordinate source', 'type' => 'select', 'max' => 20, 'options' => ['listing' => 'Reutilizar referência e data da etapa Fontes, se também sustentam este ponto', 'custom' => 'Indicar uma fonte diferente para o ponto'], 'when' => $active],
+ 'location_point_source_reference' => ['step' => 5, 'pt' => 'Referência da fonte específica do ponto', 'en' => 'Point-specific source reference', 'type' => 'textarea', 'max' => 2000, 'when' => [...$active, 'location_point_source_mode' => ['custom']]],
+ 'location_point_source_date' => ['step' => 5, 'pt' => 'Data dessa fonte (deixe vazio se desconhecida)', 'en' => 'Source date (leave blank if unknown)', 'type' => 'date', 'max' => 10, 'when' => [...$active, 'location_point_source_mode' => ['custom']]],
+ 'location_point_share_source' => ['step' => 5, 'pt' => 'Divulgar também a referência da fonte do ponto?', 'en' => 'Also disclose the point source reference?', 'type' => 'select', 'max' => 3, 'options' => ['yes' => 'Sim — referência sem contactos ou informação reservada, sujeita à publicação aprovada', 'no' => 'Não — manter a referência apenas no processo reservado'], 'when' => $active],
+ ];
+ }
+
+ /** @param array $payload
+ * @return array> */
+ public static function rules(array $payload = []): array
{
$rules = [];
foreach (self::fields() as $key => $field) {
@@ -99,6 +119,23 @@ final class BusinessFormSchema
$rules['payload.investment_total'][] = 'regex:/^\d{1,15}(\.\d{1,4})?$/';
$rules['payload.amount_sought'][] = 'regex:/^\d{1,15}(\.\d{1,4})?$/';
$rules['payload.source_date'][] = 'date_format:Y-m-d';
+ foreach (['location_latitude', 'location_longitude'] as $coordinate) {
+ // Numeric rules make Laravel interpret max:16 as a numeric ceiling, not a text limit.
+ $rules['payload.'.$coordinate] = ['nullable', 'string', function ($attribute, $value, $fail) {
+ if (strlen((string) $value) > 16) {
+ $fail('Indique a coordenada com até 16 caracteres.');
+ }
+ }];
+ }
+ if (app(BusinessPointPublication::class)->applicable($payload)) {
+ if (($payload['location_point_source_mode'] ?? null) === 'custom') {
+ $rules['payload.location_point_source_date'][] = 'date_format:Y-m-d';
+ }
+ $rules['payload.location_latitude'][] = 'numeric';
+ $rules['payload.location_latitude'][] = 'between:-90,90';
+ $rules['payload.location_longitude'][] = 'numeric';
+ $rules['payload.location_longitude'][] = 'between:-180,180';
+ }
$rules['payload.official_source_url'][] = 'url';
// The field limit is a text length, not an 8% ceiling.
$rules['payload.equity_percentage'] = ['nullable', 'numeric', 'between:0,100',
diff --git a/app/Services/BusinessPointPublication.php b/app/Services/BusinessPointPublication.php
new file mode 100644
index 00000000..d42f2fdc
--- /dev/null
+++ b/app/Services/BusinessPointPublication.php
@@ -0,0 +1,125 @@
+ $payload */
+ public function applicable(array $payload): bool
+ {
+ return ($payload['location_point_enabled'] ?? null) === 'yes'
+ && in_array($payload['geography_scope'] ?? null, ['specific', 'multiple'], true)
+ && ($payload['disclosure_precision'] ?? null) === 'exact'
+ && ($payload['location_unknown'] ?? null) === 'no';
+ }
+
+ /** @param array $payload
+ * @return list> */
+ public function paths(array $payload): array
+ {
+ if (($payload['geography_scope'] ?? null) === 'specific') {
+ return [array_intersect_key($payload, InvestmentGeography::FIELDS)];
+ }
+ if (($payload['geography_scope'] ?? null) !== 'multiple') {
+ return [];
+ }
+ $rows = json_decode((string) ($payload['locations_json'] ?? ''), true);
+
+ return is_array($rows) && array_is_list($rows) ? array_values(array_filter($rows, 'is_array')) : [];
+ }
+
+ /** @param array $path */
+ public function pathKey(array $path): string
+ {
+ return implode('|', array_map(fn ($field) => (string) ($path[$field] ?? ''), array_keys(InvestmentGeography::FIELDS)));
+ }
+
+ /** @param array $payload
+ * @return array|null */
+ public function candidate(array $payload): ?array
+ {
+ if (! $this->applicable($payload)) {
+ return null;
+ }
+ abort_unless($this->available(), 409, 'O suplemento de localização ainda não está instalado neste destino. O ponto não será publicado.');
+ $rules = [
+ 'location_unknown' => ['required', 'in:no'],
+ 'location_latitude' => ['required', 'numeric', 'between:-90,90'],
+ 'location_longitude' => ['required', 'numeric', 'between:-180,180'],
+ 'location_point_source_mode' => ['required', 'in:listing,custom'],
+ 'location_point_share_source' => ['nullable', 'in:yes,no'],
+ 'location_point_source_reference' => ['required_if:location_point_source_mode,custom', 'nullable', 'string', 'max:2000'],
+ 'location_point_source_date' => ($payload['location_point_source_mode'] ?? null) === 'custom' ? ['nullable', 'date_format:Y-m-d'] : ['nullable'],
+ 'location_point_territory' => ['required_if:geography_scope,multiple', 'nullable', 'string', 'max:150'],
+ ];
+ Validator::make($payload, $rules)->validate();
+ $paths = $this->paths($payload);
+ $path = ($payload['geography_scope'] ?? null) === 'specific' ? ($paths[0] ?? null)
+ : collect($paths)->first(fn ($row) => $this->pathKey($row) === $payload['location_point_territory']);
+ if (! $path || empty($path['province_id'])) {
+ throw ValidationException::withMessages(['location_point_territory' => 'Seleccione uma das localizações já declaradas para o ponto primário. Não é atribuída uma localização por ordem ou por nome.']);
+ }
+ $nodes = app(InvestmentGeography::class)->selection($path);
+ $listingSource = $payload['location_point_source_mode'] === 'listing';
+ $source = $listingSource ? ($payload['source_reference'] ?? null) : ($payload['location_point_source_reference'] ?? null);
+ $date = $listingSource ? ($payload['source_date'] ?? null) : ($payload['location_point_source_date'] ?? null);
+ Validator::make(['location_point_source_reference' => $source, 'location_point_source_date' => $date], [
+ 'location_point_source_reference' => ['required', 'string', 'max:2000'], 'location_point_source_date' => ['nullable', 'date_format:Y-m-d'],
+ ])->validate();
+
+ return ['path' => array_combine(array_keys(InvestmentGeography::FIELDS), array_map(fn ($field) => ($path[$field] ?? null) ?: null, array_keys(InvestmentGeography::FIELDS))),
+ 'reference_snapshot' => array_map(fn ($node) => (array) $node, $nodes),
+ 'latitude' => (float) $payload['location_latitude'], 'longitude' => (float) $payload['location_longitude'],
+ 'source_reference' => $source, 'source_date' => $date ?: null,
+ 'public_source_reference' => ($payload['location_point_share_source'] ?? null) === 'yes' ? $source : null];
+ }
+
+ /** Called only within the existing authorized, locked publication transaction.
+ * @return array */
+ public function publish(ExistingBusiness $business): array
+ {
+ $point = $this->candidate($business->payload);
+ if ($point === null) {
+ return [];
+ }
+ $previous = DB::table('existing_business_locations')->where('existing_business_id', $business->id)->where('is_primary', true)
+ ->select('*')->selectRaw('ST_AsEWKT(geom) AS geometry_snapshot')->first();
+ $geometry = DB::selectOne('SELECT ST_AsEWKT(ST_SetSRID(ST_MakePoint(?::float8, ?::float8),4326)) AS value', [$point['longitude'], $point['latitude']])->value;
+ $values = [...$point['path'], 'precision_level' => 'exact', 'is_public' => true,
+ 'geom' => $geometry,
+ 'public_source_reference' => $point['public_source_reference'], 'source_date' => $point['source_date'],
+ 'source_system' => 'portal-business-form', 'source_payload_version' => $business->version_no + 1, 'updated_at' => now()];
+ if ($previous) {
+ DB::table('existing_business_locations')->where('id', $previous->id)->update($values);
+ } else {
+ DB::table('existing_business_locations')->insert([...$values, 'id' => (string) Str::uuid(), 'existing_business_id' => $business->id, 'is_primary' => true, 'created_at' => now()]);
+ }
+
+ return ['point_publication' => ['previous' => $previous ? (array) $previous : null, 'used' => $point,
+ 'business_version' => $business->version_no + 1, 'source' => 'explicit_listing_point_supplement']];
+ }
+
+ /** Private view, only after the listing's normal view authorization.
+ * @return array|null */
+ public function registered(ExistingBusiness $business): ?array
+ {
+ $row = DB::table('existing_business_locations')->where('existing_business_id', $business->id)->where('is_primary', true)
+ ->select('id', 'precision_level', 'is_public', 'province_id', 'district_id', 'admin_post_id', 'locality_id')
+ ->selectRaw("geom IS NOT NULL AS has_geometry, CASE WHEN GeometryType(geom)='POINT' THEN ST_Y(geom) END AS latitude, CASE WHEN GeometryType(geom)='POINT' THEN ST_X(geom) END AS longitude")->first();
+
+ return $row ? (array) $row : null;
+ }
+}
diff --git a/app/Services/BusinessProximitySearch.php b/app/Services/BusinessProximitySearch.php
new file mode 100644
index 00000000..852dbd68
--- /dev/null
+++ b/app/Services/BusinessProximitySearch.php
@@ -0,0 +1,53 @@
+ */
+ public function origin(string $id): array
+ {
+ $row = DB::query()->fromSub(app(PublicBusinessLocations::class)->points(), 'origin_point')
+ ->joinSub(ExistingBusiness::published()->select('id', 'public_title'), 'origin_business', 'origin_business.id', '=', 'origin_point.existing_business_id')
+ ->where('origin_point.existing_business_id', $id)->whereNotNull('origin_point.point')
+ ->select('origin_point.location_recorded_at', 'origin_point.location_source_reference', 'origin_point.location_source_date', 'origin_business.public_title')->selectRaw('ST_AsEWKT(origin_point.point) AS ewkt')->first();
+ if (! $row) {
+ throw ValidationException::withMessages(['near_business' => 'A ficha de referência não tem um ponto primário público exacto utilizável. Escolha outra referência ou pesquise por área.']);
+ }
+
+ return ['id' => $id, 'title' => $row->public_title, 'ewkt' => $row->ewkt, 'source_reference' => $row->location_source_reference, 'source_date' => $row->location_source_date, 'location_recorded_at' => $row->location_recorded_at ? CarbonImmutable::parse($row->location_recorded_at)->toIso8601String() : null];
+ }
+
+ public function available(string $id): bool
+ {
+ return DB::query()->fromSub(app(PublicBusinessLocations::class)->points(), 'point')
+ ->whereIn('existing_business_id', ExistingBusiness::published()->select('id'))
+ ->where('existing_business_id', $id)->whereNotNull('point')->exists();
+ }
+
+ /** @param Builder $query
+ * @param array $origin
+ * @return array */
+ public function constrain(Builder $query, array $origin, float $radius): array
+ {
+ $query->leftJoinSub(app(PublicBusinessLocations::class)->points(), 'public_point', 'public_point.existing_business_id', '=', 'existing_businesses.id');
+ $withPoint = (clone $query)->whereNotNull('public_point.point')->count();
+ $withoutPoint = (clone $query)->whereNull('public_point.point')->count();
+ $query->whereNotNull('public_point.point')->whereRaw('ST_DWithin(public_point.point::geography, ST_GeomFromEWKT(?)::geography, ?)', [$origin['ewkt'], $radius * 1000])
+ ->addSelect('public_point.location_recorded_at')
+ ->selectRaw('ST_Distance(public_point.point::geography, ST_GeomFromEWKT(?)::geography) / 1000.0 AS distance_km', [$origin['ewkt']])
+ ->orderBy('distance_km')->orderBy('existing_businesses.id');
+
+ return ['origin_id' => $origin['id'], 'origin_title' => $origin['title'], 'radius_km' => $radius, 'origin_recorded_at' => $origin['location_recorded_at'],
+ 'origin_source_reference' => $origin['source_reference'], 'origin_source_date' => $origin['source_date'],
+ 'with_public_point' => $withPoint, 'without_public_point' => $withoutPoint,
+ 'source' => 'Localizações primárias públicas do cadastro de negócios do portal',
+ 'method' => 'Distância geodésica em linha recta entre pontos publicados; não é distância por estrada nem validação da localização real.'];
+ }
+}
diff --git a/app/Services/CompanyComparison.php b/app/Services/CompanyComparison.php
new file mode 100644
index 00000000..a1d508a8
--- /dev/null
+++ b/app/Services/CompanyComparison.php
@@ -0,0 +1,208 @@
+ */
+ public function definition(): array
+ {
+ return config('company-comparison');
+ }
+
+ /** @param array $questions
+ * @return list */
+ private function questionKeys(array $questions): array
+ {
+ $keys = [];
+ foreach (array_keys($questions) as $key) {
+ if (! is_string($key)) {
+ throw new \LogicException('Comparison question identifiers must be strings.');
+ }
+ $keys[] = $key;
+ }
+
+ return $keys;
+ }
+
+ /** @param array $input
+ * @return array */
+ public function answers(array $input): array
+ {
+ return $this->normalize($input, $this->definition()['questions']);
+ }
+
+ /** @param array $input
+ * @param array $questions
+ * @return array */
+ private function normalize(array $input, array $questions): array
+ {
+ $keys = $this->questionKeys($questions);
+ $rules = ['answers' => ['sometimes', 'array:'.implode(',', $keys)]];
+ foreach ($keys as $key) {
+ $rules['answers.'.$key] = ['nullable', 'string', Rule::in(array_keys($questions[$key]['options']))];
+ }
+ $values = Validator::make($input, $rules)->validate()['answers'] ?? [];
+
+ $answers = [];
+ foreach ($keys as $key) {
+ $answers[$key] = is_string($values[$key] ?? null) ? $values[$key] : 'unknown';
+ }
+
+ return $answers;
+ }
+
+ /** @param array $answers
+ * @return list */
+ public function active(array $answers): array
+ {
+ return in_array($answers['purpose'], ['representation', 'cooperation'], true) ? ['purpose', 'regulated'] : $this->questionKeys($this->definition()['questions']);
+ }
+
+ /** @param array $answers
+ * @return array */
+ public function evaluate(array $answers): array
+ {
+ $definition = $this->definition();
+ $active = $this->active($answers);
+ $pending = array_values(array_filter($active, fn ($key) => $key !== 'preferred' && $answers[$key] === 'unknown'));
+ $tasks = ['Definir contribuições, gestão, direitos e obrigações no acto a preparar.', 'Conferir os actos e o registo aplicáveis à alternativa escolhida.'];
+ if (in_array('capital', $active, true)) {
+ $tasks[] = $answers['capital'] === 'defined' ? 'Conferir os valores e o modo de realização das contribuições definidas.' : 'Definir o capital e as contribuições ainda em falta.';
+ if (in_array($answers['management'], ['participants', 'both'], true)) {
+ $tasks[] = 'Definir poderes de gestão e regras de deliberação dos participantes.';
+ }
+ if (in_array($answers['management'], ['appointed', 'both'], true)) {
+ $tasks[] = 'Definir a nomeação, o mandato e a prestação de contas da administração.';
+ }
+ if ($answers['responsibility'] !== 'unknown') {
+ $tasks[] = 'Conferir no registo e no contrato o regime de responsabilidade e as excepções aplicáveis.';
+ }
+ if ($answers['listing'] === 'yes') {
+ $tasks[] = 'Conferir os requisitos específicos da emissão e do mercado pretendido.';
+ }
+ }
+ if ($answers['regulated'] !== 'no') {
+ $tasks[] = 'Conferir as regras e habilitações específicas da actividade.';
+ }
+ $route = match ($answers['purpose']) {
+ 'representation' => 'Compare a representação da sociedade existente; não é uma nova forma societária (artigo 69).',
+ 'cooperation' => 'Prepare o acordo de cooperação; consórcio não é apresentado como uma forma societária autónoma.',
+ default => 'Compare alternativas para discutir a constituição; não existe uma forma universalmente preferível.',
+ };
+ $forms = [];
+ if (! in_array($answers['purpose'], ['representation', 'cooperation'], true)) {
+ foreach ($definition['forms'] as $code => $form) {
+ $constraints = [];
+ $notes = [];
+ if ($code === 'individual' && $answers['participants'] === 'several') {
+ $constraints[] = 'A titularidade individual não corresponde a vários titulares (artigo 3).';
+ }
+ if ($code === 'collective' && $answers['participants'] === 'one') {
+ $constraints[] = 'São necessários pelo menos dois sócios (artigo 264).';
+ }
+ if ($code === 'simplified' && $answers['listing'] === 'yes') {
+ $constraints[] = 'As acções desta forma não podem ser negociadas em Bolsa (artigo 444).';
+ }
+ if ($answers['participants'] === 'one' && in_array($code, ['quotas', 'anonymous', 'simplified'], true)) {
+ $notes[] = 'Comparar a modalidade unipessoal (artigo 257).';
+ }
+ if (($answers['participation'] === 'shares' && $code === 'quotas') || ($answers['participation'] === 'quotas' && in_array($code, ['anonymous', 'simplified'], true))) {
+ $notes[] = 'A estrutura de participação difere da preferência indicada.';
+ }
+ if ($answers['participation'] === 'work') {
+ $notes[] = $code === 'collective' ? 'Conferir a contribuição em trabalho (artigos 264–266).' : 'Conferir como realizar as contribuições pretendidas.';
+ }
+ $forms[] = ['code' => $code, ...$form, 'constraints' => $constraints, 'notes' => $notes,
+ 'selected' => $answers['preferred'] === $code, 'source_href' => $definition['source']['url'].'#page='.$form['page']];
+ }
+ }
+
+ return ['engine_version' => $definition['version'], 'source' => $definition['source'], 'questions' => $definition['questions'], 'active' => $active,
+ 'pending' => $pending, 'route' => $route, 'forms' => $forms, 'preparation' => $tasks,
+ 'scope' => 'Comparação informativa da edição indicada; a actividade, o contrato e as regras especiais continuam a exigir conferência própria.'];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function view(User $actor, string $id, array $input): array
+ {
+ $case = $this->desk->case($actor, $id);
+ $saved = $this->desk->decode($case->payload)['company_comparison'] ?? null;
+ $v = Validator::make($input, ['revision' => 'nullable|uuid', 'history_before' => 'nullable|integer|min:1'])->validate();
+ if (! empty($v['revision'])) {
+ if (array_key_exists('answers', $input)) {
+ throw ValidationException::withMessages(['answers' => 'Abra a preparação actual para comparar outras respostas; a revisão histórica conserva os dados guardados.']);
+ }
+ $row = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->where('id', $v['revision'])->first();
+ abort_unless($row !== null, 404);
+ $saved = $this->desk->decode($row->payload)['snapshot'];
+ }
+ $answers = array_key_exists('answers', $input) ? $this->answers($input) : ($saved['answers'] ?? $this->answers([]));
+ $result = array_key_exists('answers', $input) || ! $saved ? $this->evaluate($answers) : $saved['result'];
+ $events = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)
+ ->when(! empty($v['history_before']), fn ($q) => $q->where('event_order', '<', $v['history_before']))
+ ->orderByDesc('event_order')->limit(26)->get(['id', 'payload', 'event_order']);
+ $history = $events->take(25)->map(function ($row) {
+ $snapshot = $this->desk->decode($row->payload)['snapshot'];
+
+ return ['id' => $row->id, 'revision' => $snapshot['revision'], 'at' => $snapshot['at'], 'engine_version' => $snapshot['result']['engine_version']];
+ })->all();
+
+ return ['case' => ['id' => $id, 'title' => $case->title, 'version' => (int) $case->version],
+ 'canWrite' => ! $case->closed_at && $this->desk->owns($actor, $case), 'answers' => $answers, 'result' => $result,
+ 'saved' => $saved, 'history' => $history, 'historyNext' => $events->count() > 25 ? $events[24]->event_order : null,
+ 'historical' => ! empty($v['revision']), 'workingCopy' => array_key_exists('answers', $input)];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, string $id, array $input): array
+ {
+ $this->desk->case($actor, $id, true);
+ $v = Validator::make($input, ['version' => 'required|integer|min:1', 'operation_key' => 'required|uuid'])->validate();
+ $v['version'] = (int) $v['version'];
+
+ return DB::transaction(function () use ($actor, $id, $v, $input) {
+ $case = $this->desk->case($actor, $id, true, true);
+ foreach (DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->orderByDesc('event_order')->cursor() as $event) {
+ $data = $this->desk->decode($event->payload);
+ if ($data['operation_key'] === $v['operation_key']) {
+ $answers = $this->normalize($input, $data['snapshot']['result']['questions']);
+ $hash = hash('sha256', json_encode([$v['version'], $answers], JSON_THROW_ON_ERROR));
+ abort_unless(hash_equals($data['request_hash'], $hash), 409, 'Esta operação já guardou respostas diferentes. Reabra a comparação.');
+
+ return ['saved' => true, 'replayed' => true, 'revision' => $data['snapshot']['revision']];
+ }
+ }
+ $answers = $this->answers($input);
+ $hash = hash('sha256', json_encode([$v['version'], $answers], JSON_THROW_ON_ERROR));
+ abort_if($case->closed_at || (int) $case->version !== (int) $v['version'], 409, 'O dossier mudou ou foi fechado. Conserve as respostas e recupere a versão actual antes de guardar.');
+ $payload = $this->desk->decode($case->payload);
+ $result = $this->evaluate($answers);
+ $previous = $payload['company_comparison'] ?? null;
+ if ($previous !== null && $previous['answers'] === $answers && $previous['result'] === $result) {
+ return ['saved' => true, 'replayed' => false, 'unchanged' => true, 'revision' => $previous['revision']];
+ }
+ $snapshot = ['revision' => (int) ($payload['company_comparison']['revision'] ?? 0) + 1, 'answers' => $answers,
+ 'result' => $result, 'at' => now()->toIso8601String(), 'actor_id' => $actor->id];
+ $payload['company_comparison'] = $snapshot;
+ $case->version++;
+ DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'version' => $case->version, 'updated_at' => now()]);
+ $this->desk->event($case, $actor, self::EVENT, ['operation_key' => $v['operation_key'], 'request_hash' => $hash, 'snapshot' => $snapshot]);
+
+ return ['saved' => true, 'replayed' => false, 'revision' => $snapshot['revision']];
+ });
+ }
+}
diff --git a/app/Services/CompanyPreparation.php b/app/Services/CompanyPreparation.php
new file mode 100644
index 00000000..4a21d138
--- /dev/null
+++ b/app/Services/CompanyPreparation.php
@@ -0,0 +1,285 @@
+ */
+ public function definition(): array
+ {
+ return ['version' => self::VERSION, 'forms' => config('company-comparison.forms'),
+ 'roles' => ['subscriber' => 'Titular, sócio ou accionista', 'administrator' => 'Administrador ou gerente', 'representative' => 'Representante', 'beneficial_owner' => 'Beneficiário efectivo declarado'],
+ 'source' => config('company-comparison.source'),
+ 'template_status' => 'source_pending', 'template_notice' => 'Os sete exemplares referidos no complemento ainda não foram fornecidos. Esta ficha prepara dados para revisão; não é uma minuta contratual, assinatura, registo ou licença.'];
+ }
+
+ /** Reuse only the already-authorized, frozen dossier values, never a fresh master lookup.
+ * @return array> */
+ private function sources(\stdClass $case): array
+ {
+ $payload = $this->desk->decode($case->payload);
+ $sources = [];
+ if (! empty($payload['name'])) {
+ $sources['case_proponent'] = ['name' => $payload['name'], 'kind' => 'person', 'reference' => $case->id,
+ 'version' => $payload['reuse_consent']['date'] ?? 'creation', 'origin' => 'Proponente conservado na criação do dossier'];
+ }
+ if ($case->company_id && ! empty($payload['company']['name'])) {
+ $sources['case_company'] = ['name' => $payload['company']['name'], 'kind' => 'entity', 'reference' => $case->company_id,
+ 'version' => $payload['company_version'] ?? null, 'origin' => 'Declaração de empresa conservada no dossier'];
+ }
+
+ return $sources;
+ }
+
+ /** @param array $input
+ * @param array|null $definition
+ * @return array */
+ public function facts(array $input, ?array $definition = null): array
+ {
+ $definition ??= $this->definition();
+ $text = ['nullable', 'string', 'max:2000'];
+ $number = ['nullable', 'string', 'regex:/^\d{1,18}(?:[.,]\d{1,6})?$/D'];
+ $rules = ['facts' => ['present', 'array:form,proposed_name,seat,activities,regulated,currency,capital,nominal_value,management,binding,notes,parties'],
+ 'facts.form' => ['nullable', Rule::in(array_keys($definition['forms']))],
+ 'facts.proposed_name' => ['nullable', 'string', 'max:250'], 'facts.seat' => $text, 'facts.activities' => $text,
+ 'facts.regulated' => ['nullable', Rule::in(['unknown', 'yes', 'no'])],
+ 'facts.currency' => ['nullable', 'string', 'regex:/^[A-Z]{3}$/D'], 'facts.capital' => $number, 'facts.nominal_value' => $number,
+ 'facts.management' => $text, 'facts.binding' => $text, 'facts.notes' => $text,
+ 'facts.parties' => ['sometimes', 'array', 'list', 'max:100'],
+ 'facts.parties.*' => ['array:id,name,kind,source,roles,represented_id,cash,in_kind,paid,share_count,work,commitment'],
+ 'facts.parties.*.id' => ['required', 'uuid', 'distinct'], 'facts.parties.*.name' => ['nullable', 'string', 'max:250'],
+ 'facts.parties.*.kind' => ['required', Rule::in(['person', 'entity'])],
+ 'facts.parties.*.source' => ['nullable', Rule::in(['case_proponent', 'case_company'])],
+ 'facts.parties.*.roles' => ['present', 'array', 'list', 'max:4'],
+ 'facts.parties.*.roles.*' => ['string', Rule::in(array_keys($definition['roles']))],
+ 'facts.parties.*.represented_id' => ['nullable', 'uuid'],
+ 'facts.parties.*.cash' => $number, 'facts.parties.*.in_kind' => $number, 'facts.parties.*.paid' => $number,
+ 'facts.parties.*.share_count' => ['nullable', 'string', 'regex:/^\d{1,18}$/D'],
+ 'facts.parties.*.work' => $text, 'facts.parties.*.commitment' => $text];
+ $v = Validator::make($input, $rules)->validate()['facts'];
+ $facts = [];
+ foreach (['form', 'proposed_name', 'seat', 'activities', 'currency', 'management', 'binding', 'notes'] as $key) {
+ $facts[$key] = $v[$key] ?? null;
+ }
+ $facts['regulated'] = $v['regulated'] ?? 'unknown';
+ foreach (['capital', 'nominal_value'] as $key) {
+ $facts[$key] = $this->decimal($v[$key] ?? null);
+ }
+ $facts['parties'] = [];
+ foreach ($v['parties'] ?? [] as $party) {
+ $p = [];
+ foreach (['id', 'name', 'kind', 'source', 'represented_id', 'work', 'commitment'] as $key) {
+ $p[$key] = $party[$key] ?? null;
+ }
+ $p['roles'] = array_values(array_unique($party['roles']));
+ sort($p['roles']);
+ foreach (['cash', 'in_kind', 'paid', 'share_count'] as $key) {
+ $p[$key] = $this->decimal($party[$key] ?? null);
+ }
+ $facts['parties'][] = $p;
+ }
+
+ return $facts;
+ }
+
+ private function decimal(?string $value): ?string
+ {
+ return $value === null ? null : (string) BigDecimal::of(str_replace(',', '.', $value))->strippedOfTrailingZeros();
+ }
+
+ /** @param array $facts
+ * @param array> $sources
+ * @param array|null $previous
+ * @return array */
+ private function resolve(array $facts, array $sources, ?array $previous): array
+ {
+ foreach ($facts['parties'] as &$party) {
+ if ($party['source'] !== null) {
+ $old = null;
+ foreach ($previous['facts']['parties'] ?? [] as $candidate) {
+ if ($candidate['id'] === $party['id'] && $candidate['source'] === $party['source']) {
+ $old = $candidate;
+ break;
+ }
+ }
+ $source = $old['source_snapshot'] ?? $sources[$party['source']] ?? null;
+ abort_unless($source !== null, 422, 'A origem seleccionada não existe neste dossier.');
+ $party['name'] = $source['name'];
+ $party['kind'] = $source['kind'];
+ $party['source_snapshot'] = $source;
+ }
+ }
+
+ return $facts;
+ }
+
+ /** @param array $facts
+ * @return array */
+ public function review(array $facts): array
+ {
+ $issues = [];
+ foreach (['form' => 'Definir a forma a preparar.', 'proposed_name' => 'Indicar a denominação proposta.', 'seat' => 'Indicar a sede proposta.', 'activities' => 'Descrever as actividades.', 'management' => 'Descrever a administração pretendida.', 'binding' => 'Indicar a forma de obrigar pretendida.'] as $key => $message) {
+ if (! $facts[$key]) {
+ $issues[] = $message;
+ }
+ }
+ $subscribers = array_values(array_filter($facts['parties'], fn ($p) => in_array('subscriber', $p['roles'], true)));
+ if ($subscribers === []) {
+ $issues[] = 'Identificar os titulares, sócios ou accionistas.';
+ }
+ if ($facts['form'] === 'collective' && count($subscribers) < 2) {
+ $issues[] = 'A forma colectiva exige pelo menos dois sócios (artigo 264).';
+ }
+ if ($facts['form'] === 'individual' && count($subscribers) > 1) {
+ $issues[] = 'A titularidade individual não corresponde a vários titulares.';
+ }
+ $corporate = $facts['form'] !== null && $facts['form'] !== 'individual';
+ $shares = in_array($facts['form'], ['anonymous', 'simplified'], true);
+ $total = BigDecimal::zero();
+ $paid = BigDecimal::zero();
+ $units = BigDecimal::zero();
+ $complete = $subscribers !== [];
+ $paymentsComplete = $complete;
+ $unitsComplete = $complete;
+ $ids = array_column($facts['parties'], 'id');
+ $usedSources = [];
+ foreach ($facts['parties'] as $party) {
+ if ($party['source'] && in_array($party['source'], $usedSources, true)) {
+ $issues[] = 'A mesma origem foi seleccionada em mais de uma linha; conferir duplicação sem fundir pessoas por nome.';
+ }
+ $usedSources[] = $party['source'];
+ if (! $party['name'] || $party['roles'] === []) {
+ $issues[] = 'Completar o nome e os papéis de cada interveniente.';
+ }
+ if (in_array('representative', $party['roles'], true) && (! $party['represented_id'] || $party['represented_id'] === $party['id'] || ! in_array($party['represented_id'], $ids, true))) {
+ $issues[] = 'Identificar quem cada representante representa, numa linha distinta.';
+ }
+ if (! in_array('subscriber', $party['roles'], true) || ! $corporate) {
+ continue;
+ }
+ $complete = $complete && $party['cash'] !== null && $party['in_kind'] !== null;
+ $subscription = BigDecimal::of($party['cash'] ?? '0')->plus($party['in_kind'] ?? '0');
+ $total = $total->plus($subscription);
+ $paymentsComplete = $paymentsComplete && $party['paid'] !== null;
+ $paid = $paid->plus($party['paid'] ?? '0');
+ if ($party['paid'] !== null && $party['cash'] !== null && $party['in_kind'] !== null && BigDecimal::of($party['paid'])->compareTo($subscription) > 0) {
+ $issues[] = 'Uma realização declarada excede a subscrição desse participante.';
+ }
+ $unitsComplete = $unitsComplete && $party['share_count'] !== null;
+ $units = $units->plus($party['share_count'] ?? '0');
+ if ($shares && $party['share_count'] !== null && $facts['nominal_value'] !== null && $party['cash'] !== null && $party['in_kind'] !== null && BigDecimal::of($party['share_count'])->multipliedBy($facts['nominal_value'])->compareTo($subscription) !== 0) {
+ $issues[] = 'O valor nominal das acções de um participante difere da sua subscrição.';
+ }
+ if ($party['work'] && $facts['form'] !== 'collective') {
+ $issues[] = 'Conferir a admissibilidade da contribuição em trabalho para a forma escolhida.';
+ }
+ }
+ $totals = null;
+ if ($corporate) {
+ if (! $facts['currency'] || $facts['capital'] === null || ! $complete) {
+ $issues[] = 'Completar moeda, capital e entradas em dinheiro/espécie; valores desconhecidos não são zero.';
+ }
+ if ($complete && $facts['capital'] !== null && $total->compareTo($facts['capital']) !== 0) {
+ $issues[] = 'A soma das subscrições difere do capital declarado.';
+ }
+ if (! $paymentsComplete) {
+ $issues[] = 'Completar a realização declarada de cada subscrição; não equivale a prova de pagamento.';
+ }
+ if ($shares && ($facts['nominal_value'] === null || ! $unitsComplete)) {
+ $issues[] = 'Completar o número de acções e o valor nominal para reconciliar as participações.';
+ }
+ $totals = ['currency' => $facts['currency'], 'subscribed' => $complete && $facts['currency'] ? (string) $total : null,
+ 'paid' => $paymentsComplete && $facts['currency'] ? (string) $paid : null,
+ 'unpaid' => $complete && $paymentsComplete && $facts['currency'] ? (string) $total->minus($paid) : null,
+ 'shares_nominal' => $shares && $unitsComplete && $facts['nominal_value'] !== null && $facts['currency'] ? (string) $units->multipliedBy($facts['nominal_value']) : null];
+ }
+ if ($facts['regulated'] !== 'no') {
+ $issues[] = 'Conferir os requisitos sectoriais ou profissionais da actividade; o objecto não concede licença.';
+ }
+
+ return ['issues' => array_values(array_unique($issues)), 'totals' => $totals, 'status' => 'preparation',
+ 'note' => $facts['form'] === 'collective' ? 'As contribuições em trabalho são conservadas separadamente e não integram o capital (artigo 266).' : 'Valores declarados para preparação; não comprovam entradas, poderes ou registo.'];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function view(User $actor, string $id, array $input): array
+ {
+ $case = $this->desk->case($actor, $id);
+ $payload = $this->desk->decode($case->payload);
+ $v = Validator::make($input, ['revision' => 'nullable|uuid', 'history_before' => 'nullable|integer|min:1'])->validate();
+ $saved = $payload['company_preparation'] ?? null;
+ if (! empty($v['revision'])) {
+ $event = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->where('id', $v['revision'])->first();
+ abort_unless($event !== null, 404);
+ $saved = $this->desk->decode($event->payload)['snapshot'];
+ }
+ $facts = $saved['facts'] ?? $this->facts(['facts' => []]);
+ $events = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)
+ ->when(! empty($v['history_before']), fn ($q) => $q->where('event_order', '<', $v['history_before']))
+ ->orderByDesc('event_order')->limit(26)->get(['id', 'payload', 'event_order']);
+
+ return ['case' => ['id' => $id, 'title' => $case->title, 'version' => (int) $case->version],
+ 'canWrite' => ! $case->closed_at && $this->desk->owns($actor, $case), 'historical' => ! empty($v['revision']),
+ 'definition' => $saved['definition'] ?? $this->definition(), 'facts' => $facts, 'review' => $saved['review'] ?? $this->review($facts), 'saved' => $saved,
+ 'sources' => $this->sources($case), 'history' => $events->take(25)->map(function ($e) {
+ $s = $this->desk->decode($e->payload)['snapshot'];
+
+ return ['id' => $e->id, 'revision' => $s['revision'], 'at' => $s['at']];
+ })->all(), 'historyNext' => $events->count() > 25 ? $events[24]->event_order : null];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, string $id, array $input): array
+ {
+ $this->desk->case($actor, $id, true);
+ $v = Validator::make($input, ['version' => 'required|integer|min:1', 'operation_key' => 'required|uuid'])->validate();
+
+ return DB::transaction(function () use ($actor, $id, $v, $input) {
+ $case = $this->desk->case($actor, $id, true, true);
+ foreach (DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->orderByDesc('event_order')->cursor() as $event) {
+ $data = $this->desk->decode($event->payload);
+ if ($data['operation_key'] === $v['operation_key']) {
+ $facts = $this->facts($input, $data['snapshot']['definition']);
+ $hash = hash('sha256', json_encode([(int) $v['version'], $facts], JSON_THROW_ON_ERROR));
+ abort_unless(hash_equals($data['request_hash'], $hash), 409, 'A operação já guardou outros dados.');
+
+ return ['saved' => true, 'replayed' => true, 'revision' => $data['snapshot']['revision']];
+ }
+ }
+ $facts = $this->facts($input);
+ $hash = hash('sha256', json_encode([(int) $v['version'], $facts], JSON_THROW_ON_ERROR));
+ abort_if($case->closed_at || (int) $case->version !== (int) $v['version'], 409, 'O dossier mudou ou foi fechado. Os dados continuam no formulário; recupere a versão antes de guardar.');
+ $payload = $this->desk->decode($case->payload);
+ $previous = $payload['company_preparation'] ?? null;
+ $resolved = $this->resolve($facts, $this->sources($case), $previous);
+ $definition = $this->definition();
+ $review = $this->review($resolved);
+ if ($previous && $previous['facts'] === $resolved && $previous['definition'] === $definition && $previous['review'] === $review) {
+ return ['saved' => true, 'unchanged' => true, 'revision' => $previous['revision']];
+ }
+ $snapshot = ['revision' => (int) ($previous['revision'] ?? 0) + 1, 'at' => now()->toIso8601String(), 'actor_id' => $actor->id,
+ 'facts' => $resolved, 'definition' => $definition, 'review' => $review];
+ $payload['company_preparation'] = $snapshot;
+ $case->version++;
+ DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'version' => $case->version, 'updated_at' => now()]);
+ $this->desk->event($case, $actor, self::EVENT, ['operation_key' => $v['operation_key'], 'request_hash' => $hash, 'snapshot' => $snapshot]);
+
+ return ['saved' => true, 'replayed' => false, 'revision' => $snapshot['revision']];
+ });
+ }
+}
diff --git a/app/Services/CrmNextAction.php b/app/Services/CrmNextAction.php
new file mode 100644
index 00000000..4035e64f
--- /dev/null
+++ b/app/Services/CrmNextAction.php
@@ -0,0 +1,27 @@
+ */
+ public function future(Lead $lead, ?string $exceptTask = null): Builder
+ {
+ return CrmTask::availableForWork()->where('tasks.lead_id', $lead->id)->where('tasks.due_at', '>', now())
+ ->when($exceptTask !== null, fn ($query) => $query->where('tasks.id', '!=', $exceptTask));
+ }
+
+ /** Both write paths lock the dossier (when linked), lead, then task before checking. */
+ public function assertMayFinish(?Lead $lead, CrmTask $task, string $status): void
+ {
+ if ($lead !== null && ! $lead->trashed() && in_array($lead->status, ['new', 'qualified'], true)
+ && in_array($status, ['done', 'cancelled'], true) && ! $this->future($lead, $task->id)->exists()) {
+ throw ValidationException::withMessages(['status' => 'Crie a próxima acção com prazo futuro antes de encerrar a última tarefa de um acompanhamento activo. Tarefas num dossier encerrado não estão disponíveis.']);
+ }
+ }
+}
diff --git a/app/Services/CrmTaskCreation.php b/app/Services/CrmTaskCreation.php
new file mode 100644
index 00000000..d9b87217
--- /dev/null
+++ b/app/Services/CrmTaskCreation.php
@@ -0,0 +1,76 @@
+ $input
+ * @param array $assignees
+ * @return array{task_id:string,version:int,replayed:bool}
+ */
+ public function create(User $actor, Lead $lead, array $input, array $assignees): array
+ {
+ abort_unless(Gate::forUser($actor)->allows('manage-portal'), 403);
+ $data = Validator::make($input, ['client_key' => 'nullable|uuid', 'title' => 'required|string|max:200', 'due_at' => 'required|date', 'assignee_user_id' => 'required|integer'])->validate();
+ $key = is_string($data['client_key'] ?? null) ? strtolower($data['client_key']) : null;
+ $values = ['title' => trim($data['title']), 'due_at' => CarbonImmutable::parse($data['due_at'])->utc()->format('Y-m-d\TH:i:s.u\Z'), 'assignee_user_id' => (int) $data['assignee_user_id']];
+ $hash = hash('sha256', json_encode($values, JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $lead, $values, $key, $hash, $assignees) {
+ $lead = Lead::lockForUpdate()->findOrFail($lead->id);
+ if ($key !== null) {
+ $event = $this->query($actor, $lead)->whereRaw("after_data->'task_creation'->>'key' = ?", [$key])->selectRaw("entity_id,after_data->'task_creation'->>'hash' AS hash,after_data->'task_creation'->'version' AS version")->first();
+ if ($event) {
+ abort_unless($event->hash === $hash, 409, 'Esta tentativa já foi usada com outros dados. Compare as tarefas antes de continuar.');
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ abort_unless(is_string($event->entity_id) && Str::isUuid($event->entity_id) && is_int($version) && $version > 0, 409, 'A criação anterior não foi identificada com segurança.');
+
+ return ['task_id' => $event->entity_id, 'version' => $version, 'replayed' => true];
+ }
+ }
+ Validator::make($values, ['title' => 'required|string|max:200', 'due_at' => 'required|date|after:now', 'assignee_user_id' => ['required', 'integer', Rule::in($assignees)]])->validate();
+ $task = new CrmTask;
+ PortalAudit::save($task, [...$values, 'lead_id' => $lead->id, 'status' => 'open'], $actor->id);
+ if ($key !== null) {
+ DB::table('audit_events')->insert(['source_system' => self::SOURCE, 'actor_user_id' => $actor->id, 'entity_type' => 'tasks', 'entity_id' => $task->id, 'action' => 'created', 'data_classification' => 'internal',
+ 'after_data' => json_encode(['task_creation' => ['lead_id' => $lead->id, 'key' => $key, 'hash' => $hash, 'version' => (int) $task->getAttribute('version_no')]], JSON_THROW_ON_ERROR)]);
+ }
+
+ return ['task_id' => $task->id, 'version' => (int) $task->getAttribute('version_no'), 'replayed' => false];
+ });
+ }
+
+ /** @return array{lead_id:string,actor_id:int,commands:list,preparation:array} */
+ public function context(User $actor, Lead $lead): array
+ {
+ abort_unless(Gate::forUser($actor)->allows('manage-portal'), 403);
+ $commands = [];
+ foreach ($this->query($actor, $lead)->orderBy('occurred_at')->selectRaw("entity_id,after_data->'task_creation'->>'key' AS key,after_data->'task_creation'->'version' AS version")->get() as $event) {
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ if (is_string($event->key) && Str::isUuid($event->key) && is_string($event->entity_id) && Str::isUuid($event->entity_id) && is_int($version) && $version > 0) {
+ $commands[] = ['key' => $event->key, 'task_id' => $event->entity_id, 'version' => $version];
+ }
+ }
+
+ return ['lead_id' => $lead->id, 'actor_id' => $actor->id, 'commands' => $commands, 'preparation' => app(CrmTaskPreparations::class)->view($actor, $lead)];
+ }
+
+ private function query(User $actor, Lead $lead): Builder
+ {
+ return DB::table('audit_events')->where('source_system', self::SOURCE)->where('actor_user_id', $actor->id)->where('entity_type', 'tasks')->where('action', 'created')
+ ->whereRaw("after_data->'task_creation'->>'lead_id' = ?", [$lead->id]);
+ }
+}
diff --git a/app/Services/CrmTaskPreparations.php b/app/Services/CrmTaskPreparations.php
new file mode 100644
index 00000000..f3c84b1e
--- /dev/null
+++ b/app/Services/CrmTaskPreparations.php
@@ -0,0 +1,117 @@
+ */
+ public function view(User $actor, Lead $lead): array
+ {
+ abort_unless(Gate::forUser($actor)->allows('manage-portal'), 403);
+ $row = $this->installed() ? DB::table('crm_task_preparations')->where('actor_id', $actor->id)->where('lead_id', $lead->id)->first() : null;
+ $snapshot = null;
+ $unavailable = false;
+ if ($row) {
+ try {
+ $decoded = json_decode(Crypt::decryptString($row->snapshot), true);
+ $validator = Validator::make(['snapshot' => $decoded], $this->rules());
+ if ($validator->fails()) {
+ $unavailable = true;
+ } else {
+ $snapshot = $this->normalize($validator->validated()['snapshot']);
+ }
+ } catch (DecryptException) {
+ $unavailable = true;
+ }
+ }
+
+ return ['installed' => $this->installed(), 'version' => (int) ($row->version ?? 0), 'snapshot' => $snapshot, 'operation_key' => $row->operation_key ?? null,
+ 'updated_at' => $row->updated_at ?? null, 'unavailable' => $unavailable];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, Lead $lead, array $input): array
+ {
+ abort_unless(Gate::forUser($actor)->allows('manage-portal'), 403);
+ abort_unless($this->installed(), 409, 'A recuperação persistente ainda não está instalada. A criação manual continua disponível.');
+ $data = Validator::make($input, [...$this->rules(), 'version' => 'required|integer|min:0', 'operation_key' => 'required|uuid'])->validate();
+ $data['snapshot'] = $this->normalize($data['snapshot']);
+ $key = strtolower($data['operation_key']);
+ $hash = hash('sha256', json_encode(Arr::sortRecursive(['version' => (int) $data['version'], 'snapshot' => $data['snapshot']]), JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $lead, $data, $key, $hash): array {
+ $lead = Lead::lockForUpdate()->findOrFail($lead->id);
+ $row = DB::table('crm_task_preparations')->where('actor_id', $actor->id)->where('lead_id', $lead->id)->lockForUpdate()->first();
+ if ($row && $row->operation_key === $key) {
+ abort_unless(hash_equals($row->operation_sha256, $hash), 409, 'Esta tentativa de guardar já foi usada com outros dados.');
+
+ return app(CrmTaskCreation::class)->context($actor, $lead);
+ }
+ abort_unless((int) ($row->version ?? 0) === (int) $data['version'], 409, 'A preparação mudou noutro separador. Compare antes de substituir.');
+ if ($row) {
+ abort_if($this->view($actor, $lead)['unavailable'], 409, 'A preparação guardada não pôde ser recuperada. Os dados anteriores foram preservados.');
+ }
+ $version = (int) ($row->version ?? 0) + 1;
+ DB::table('crm_task_preparations')->updateOrInsert(['actor_id' => $actor->id, 'lead_id' => $lead->id], [
+ 'version' => $version, 'operation_key' => $key, 'operation_sha256' => $hash,
+ 'snapshot' => Crypt::encryptString(json_encode($data['snapshot'], JSON_THROW_ON_ERROR)),
+ 'created_at' => $row->created_at ?? now(), 'updated_at' => now(),
+ ]);
+ DB::table('audit_events')->insert(['source_system' => 'portal-crm-task-preparation', 'entity_type' => 'crm_task_preparations', 'entity_id' => $lead->id,
+ 'actor_user_id' => $actor->id, 'action' => 'draft_checkpoint_saved', 'data_classification' => 'restricted', 'after_data' => json_encode(['version' => $version], JSON_THROW_ON_ERROR)]);
+
+ return app(CrmTaskCreation::class)->context($actor, $lead);
+ });
+ }
+
+ /** @param array $snapshot
+ * @return array */
+ private function normalize(array $snapshot): array
+ {
+ foreach (['title', 'due_at', 'assignee_user_id'] as $field) {
+ $snapshot['generation'][$field] = (int) $snapshot['generation'][$field];
+ if (is_array($snapshot['pending'])) {
+ $snapshot['pending']['generation'][$field] = (int) $snapshot['pending']['generation'][$field];
+ }
+ }
+ if (is_array($snapshot['pending'])) {
+ $snapshot['pending']['values']['client_key'] = strtolower($snapshot['pending']['values']['client_key']);
+ }
+
+ return $snapshot;
+ }
+
+ /** @return array */
+ private function rules(): array
+ {
+ $rules = ['snapshot' => 'required|array:values,generation,pending', 'snapshot.values' => 'required|array:title,due_at,assignee_user_id',
+ 'snapshot.generation' => 'required|array:title,due_at,assignee_user_id', 'snapshot.pending' => 'present|nullable|array:values,generation',
+ 'snapshot.pending.values' => 'required_with:snapshot.pending|array:title,due_at,assignee_user_id,client_key',
+ 'snapshot.pending.generation' => 'required_with:snapshot.pending|array:title,due_at,assignee_user_id',
+ 'snapshot.pending.values.client_key' => 'required_with:snapshot.pending|uuid'];
+ foreach (['title' => 200, 'due_at' => 100, 'assignee_user_id' => 20] as $field => $limit) {
+ $rules['snapshot.values.'.$field] = 'present|string|max:'.$limit;
+ $rules['snapshot.generation.'.$field] = 'present|integer|min:0|max:1000000000';
+ $rules['snapshot.pending.values.'.$field] = 'exclude_without:snapshot.pending|present|string|max:'.$limit;
+ $rules['snapshot.pending.generation.'.$field] = 'exclude_without:snapshot.pending|present|integer|min:0|max:1000000000';
+ }
+
+ return $rules;
+ }
+}
diff --git a/app/Services/DashboardWorkQueue.php b/app/Services/DashboardWorkQueue.php
new file mode 100644
index 00000000..822865ff
--- /dev/null
+++ b/app/Services/DashboardWorkQueue.php
@@ -0,0 +1,88 @@
+ $pages
+ * @return array|null
+ */
+ public function forActor(User $actor, array $pages): ?array
+ {
+ $now = CarbonImmutable::now()->startOfSecond();
+ $access = app(PortalProfileAccess::class);
+ $manager = $actor->can('manage-portal') && ! $access->has($actor, 'auditor');
+ $groups = [];
+ if (app(ScopedPortalAdministration::class)->interestOperator($actor)) {
+ $query = DB::table('interest_requests')->where('assigned_to', $actor->id)->whereNull('deleted_at')
+ ->whereNotIn('status', ['closed', 'cancelled', 'refused', 'converted'])
+ ->select(['id', 'reference', 'next_action as title', 'status', 'next_action_due_at as due_at']);
+ $groups['interests'] = $this->group($query, 'interests', $pages, $now);
+ }
+ if (app(VirtualDesk::class)->installed()) {
+ $assigned = DB::table('desk_requests')->where('analyst_id', $actor->id);
+ // Direct request consultation already permits the assigned analyst, independently of decision authority.
+ if ($manager || $assigned->exists()) {
+ $query = DB::table('desk_requests as r')->join('desk_cases as c', 'c.id', '=', 'r.case_id')
+ ->where('r.analyst_id', $actor->id)->whereNull('c.closed_at')
+ ->whereNotIn('r.status', ['draft', 'cancelled', 'closed'])
+ ->select(['r.id', 'r.protocol as reference', 'c.title', 'r.status', 'r.due_at']);
+ $groups['desk'] = $this->group($query, 'desk', $pages, $now);
+ }
+ }
+ if ($manager && Schema::hasTable('tasks') && Schema::hasTable('leads')) {
+ $query = CrmTask::availableForWork()->join('leads as l', 'l.id', '=', 'tasks.lead_id')
+ ->where('tasks.assignee_user_id', $actor->id)->whereNull('l.deleted_at')
+ ->select(['tasks.id', 'tasks.title', 'tasks.status', 'tasks.due_at', 'l.id as parent_id', 'l.title as reference']);
+ $groups['crm_tasks'] = $this->group($query->toBase(), 'crm_tasks', $pages, $now);
+ }
+
+ return $groups === [] ? null : ['as_of' => $now->toISOString(), 'groups' => $groups, 'desk_states' => config('virtual-desk.request_states')];
+ }
+
+ /**
+ * @param 'interests'|'desk'|'crm_tasks' $kind
+ * @param array $pages
+ * @return array
+ */
+ private function group(Builder $query, string $kind, array $pages, CarbonImmutable $now): array
+ {
+ [$deadline, $order, $idColumn] = match ($kind) {
+ 'interests' => ['next_action_due_at', 'next_action_due_at ASC NULLS LAST', 'id'],
+ 'desk' => ['r.due_at', 'r.due_at ASC NULLS LAST', 'r.id'],
+ 'crm_tasks' => ['tasks.due_at', 'tasks.due_at ASC NULLS LAST', 'tasks.id'],
+ };
+ $pageName = $kind.'_page';
+ $page = $pages[$pageName] ?? 1;
+ $total = (clone $query)->count();
+ $overdue = (clone $query)->where($deadline, '<', $now)->count();
+ $lastPage = max(1, (int) ceil($total / 5));
+ // An assignment may disappear between visits. Recover to an existing page instead of trapping a stale URL.
+ $page = min($page, $lastPage);
+ $items = (clone $query)->orderByRaw($order)->orderBy($idColumn)
+ ->offset(($page - 1) * 5)->limit(5)->get()->map(function (\stdClass $row) use ($kind, $now): array {
+ $due = $row->due_at === null ? null : CarbonImmutable::parse($row->due_at);
+
+ return ['id' => (string) $row->id, 'title' => $row->title ?: 'Acompanhar manifestação', 'reference' => $row->reference,
+ 'status' => $row->status, 'due_at' => $due?->toISOString(), 'overdue' => $due?->lessThan($now) ?? false,
+ 'href' => match ($kind) {
+ 'interests' => '/management/interests/'.$row->id,
+ 'desk' => '/balcao-virtual/pedidos/'.$row->id,
+ 'crm_tasks' => '/management/crm/leads/'.$row->parent_id.'#crm-task-'.$row->id,
+ }];
+ })->all();
+
+ return ['total' => $total, 'overdue' => $overdue, 'items' => $items, 'page' => $page, 'last_page' => $lastPage,
+ 'previous' => $page > 1 ? route('dashboard', [...$pages, $pageName => $page - 1], absolute: false) : null,
+ 'next' => $page < $lastPage ? route('dashboard', [...$pages, $pageName => $page + 1], absolute: false) : null];
+ }
+}
diff --git a/app/Services/DeskAttachments.php b/app/Services/DeskAttachments.php
new file mode 100644
index 00000000..9e102a01
--- /dev/null
+++ b/app/Services/DeskAttachments.php
@@ -0,0 +1,116 @@
+scope !== null && $indexes->dossier !== null;
+ }
+
+ /** @param array $definition
+ * @return array */
+ public function field(array $definition, string $key): array
+ {
+ $field = $definition['fields'][$key] ?? null;
+ if (! $field || $field['type'] !== 'attachment') {
+ throw ValidationException::withMessages(['field_key' => 'Seleccione uma pergunta de anexo da versão deste pedido.']);
+ }
+
+ return $field;
+ }
+
+ /** @param array $field */
+ public function checkMetadata(\stdClass $document, array $field, string $path, bool $allowUnknown = false): void
+ {
+ $mime = strtolower(trim(explode(';', (string) ($document->media_type ?? ''), 2)[0]));
+ if (($mime === '' && ! $allowUnknown) || ($mime !== '' && ! in_array($mime, $field['mime_types'], true)) || ($document->size_bytes === null && ! $allowUnknown) || ($document->size_bytes !== null && ($document->size_bytes === false || $document->size_bytes < 0 || $document->size_bytes > $field['max_size_kb'] * 1024))) {
+ throw ValidationException::withMessages([$path => 'O ficheiro não corresponde aos formatos ou ao tamanho máximo desta pergunta. Escolha outro suporte; o original é conservado.']);
+ }
+ }
+
+ /** Validate references through the existing case/request boundary; no parallel document store.
+ * @param array $payload
+ * @param array $definition
+ * @return array */
+ public function snapshot(\stdClass $request, array $payload, array $definition, bool $submitting): array
+ {
+ $applicable = app(VirtualDesk::class)->applicableFields($payload, $definition);
+ $snapshot = [];
+ $verified = [];
+ foreach ($definition['fields'] as $key => $field) {
+ if ($field['type'] !== 'attachment') {
+ continue;
+ }
+ $files = [];
+ $seen = [];
+ foreach ($payload[$key] ?? [] as $linkId) {
+ $document = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')
+ ->where('l.id', $linkId)->where('l.case_id', $request->case_id)->whereNull('d.deleted_at')
+ ->where(fn ($q) => $q->whereNull('l.request_id')->orWhere('l.request_id', $request->id))
+ ->first(['d.*', 'l.id as link_id', 'l.source_reference', 'l.category', 'l.valid_until as declared_valid_until', 'l.stage as linked_stage']);
+ if (! $document) {
+ throw ValidationException::withMessages(['payload.'.$key => 'Seleccione documentos associados a este dossier e disponíveis neste pedido.']);
+ }
+ if (isset($seen[$document->id])) {
+ throw ValidationException::withMessages(['payload.'.$key => 'Seleccione cada ficheiro apenas uma vez nesta pergunta. Pode reutilizá-lo noutras perguntas aplicáveis.']);
+ }
+ $seen[$document->id] = true;
+ $active = isset($applicable[$key]);
+ // Hidden answers are preserved; they are not accepted as applicable evidence.
+ if ($active) {
+ $this->checkMetadata($document, $field, 'payload.'.$key, true);
+ }
+ $usable = $document->status === 'active' && $document->malware_scan_status === 'clean'
+ && hash_equals(trim($document->sha256), trim((string) $document->malware_scanned_sha256));
+ if ($submitting && $active) {
+ if (! $usable) {
+ throw ValidationException::withMessages(['payload.'.$key => 'O suporte seleccionado ainda não está disponível com análise de segurança válida. Actualize o estado dos documentos antes de submeter.']);
+ }
+ if (! isset($verified[$document->id])) {
+ try {
+ $verificationDocument = clone $document;
+ $verificationDocument->media_type = $verificationDocument->media_type ?: 'application/octet-stream';
+ $response = app(VerifiedDocumentBinary::class)->respond($verificationDocument);
+ if ($response instanceof BinaryFileResponse) {
+ $verified[$document->id] = ['size_bytes' => $response->getFile()->getSize(), 'media_type' => (new \finfo(FILEINFO_MIME_TYPE))->file($response->getFile()->getPathname())];
+ } else {
+ $content = $response->getContent();
+ if (! is_string($content)) {
+ throw ValidationException::withMessages(['payload.'.$key => 'Não foi possível conferir o original deste suporte.']);
+ }
+ $verified[$document->id] = ['size_bytes' => strlen($content), 'media_type' => (new \finfo(FILEINFO_MIME_TYPE))->buffer($content)];
+ }
+ } catch (HttpExceptionInterface $error) {
+ throw ValidationException::withMessages(['payload.'.$key => 'O suporte não está disponível com a autorização e integridade exigidas. Recupere ou seleccione outro documento.']);
+ }
+ }
+ $this->checkMetadata((object) $verified[$document->id], $field, 'payload.'.$key);
+ $recordedMime = strtolower(trim(explode(';', (string) ($document->media_type ?? ''), 2)[0]));
+ if (($document->size_bytes !== null && $verified[$document->id]['size_bytes'] !== (int) $document->size_bytes) || ($recordedMime !== '' && $verified[$document->id]['media_type'] !== $recordedMime)) {
+ throw ValidationException::withMessages(['payload.'.$key => 'O formato ou tamanho do original diverge dos dados registados. Recupere ou seleccione outro documento.']);
+ }
+ }
+ $measured = $submitting && $active ? $verified[$document->id] : null;
+ $files[] = ['link_id' => $document->link_id, 'document_id' => $document->id, 'file_name' => $document->file_name,
+ 'sha256' => trim($document->sha256), 'version_no' => $document->version_no, 'media_type' => $measured['media_type'] ?? $document->media_type,
+ 'size_bytes' => $measured['size_bytes'] ?? $document->size_bytes, 'recorded_media_type' => $document->media_type, 'recorded_size_bytes' => $document->size_bytes, 'metadata_measured' => $measured !== null, 'source_reference' => $document->source_reference,
+ 'valid_until' => $document->declared_valid_until, 'stage' => $document->linked_stage, 'status' => $document->status, 'malware_scan_status' => $document->malware_scan_status, 'usable_at_submission' => $submitting && $active && $usable];
+ }
+ $snapshot[$key] = ['label' => $field['label'], 'applicable' => isset($applicable[$key]), 'service_version_id' => $request->service_version_id,
+ 'limits' => ['mime_types' => $field['mime_types'], 'max_size_kb' => $field['max_size_kb'], 'max_files' => $field['max_files']], 'files' => $files];
+ }
+
+ return $snapshot;
+ }
+}
diff --git a/app/Services/DeskPaymentEvidence.php b/app/Services/DeskPaymentEvidence.php
new file mode 100644
index 00000000..3d82ac50
--- /dev/null
+++ b/app/Services/DeskPaymentEvidence.php
@@ -0,0 +1,46 @@
+ $input
+ * @return array|null
+ */
+ public function snapshot(string $caseId, string $requestId, array $input): ?array
+ {
+ if (! ($input['document_link_id'] ?? null) && ! ($input['document_id'] ?? null)) {
+ return null;
+ }
+ $document = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')
+ ->where('l.case_id', $caseId)->whereNull('d.deleted_at')
+ ->where(fn ($q) => $q->whereNull('l.request_id')->orWhere('l.request_id', $requestId))
+ ->when($input['document_link_id'] ?? null, fn ($q, $id) => $q->where('l.id', $id))
+ ->when($input['document_id'] ?? null, fn ($q, $id) => $q->where('d.id', $id))
+ ->orderBy('l.created_at')->orderBy('l.id')->first(['d.*', 'l.id as link_id', 'l.source_reference', 'l.category', 'l.stage', 'l.valid_until as declared_valid_until']);
+ abort_unless($document !== null, 422, 'Seleccione um comprovativo associado a este pedido ou ao seu dossier.');
+ app(VerifiedDocumentBinary::class)->authorizeOpportunityAttachment($document);
+
+ return ['link_id' => $document->link_id, 'document_id' => $document->id, 'file_name' => $document->file_name, 'document_version' => (int) $document->version_no,
+ 'sha256' => trim($document->sha256), 'source_reference' => $document->source_reference, 'category' => $document->category, 'stage' => $document->stage,
+ 'valid_until' => $document->declared_valid_until, 'status_at_association' => $document->status, 'scan_at_association' => $document->malware_scan_status,
+ 'scope' => 'registered_document_metadata_not_binary_or_payment_confirmation'];
+ }
+
+ /** @return array> */
+ public function forRequest(string $requestId): array
+ {
+ $current = [];
+ foreach (DB::table('desk_events')->where('request_id', $requestId)->whereIn('action', ['payment_declared', 'payment_document_linked'])->orderBy('event_order')->get(['payload']) as $event) {
+ $payload = app(VirtualDesk::class)->decode($event->payload);
+ if (is_string($payload['payment_id'] ?? null) && is_array($payload['document_evidence'] ?? null)) {
+ $current[$payload['payment_id']] = $payload['document_evidence'];
+ }
+ }
+
+ return $current;
+ }
+}
diff --git a/app/Services/DeskRequestCheckpoints.php b/app/Services/DeskRequestCheckpoints.php
new file mode 100644
index 00000000..5c4d740f
--- /dev/null
+++ b/app/Services/DeskRequestCheckpoints.php
@@ -0,0 +1,88 @@
+ */
+ public function show(User $actor, string $id): array
+ {
+ $desk = app(VirtualDesk::class);
+ $request = $desk->request($actor, $id, true);
+ $case = $desk->case($actor, $request->case_id, true);
+ $row = $this->installed() ? DB::table('desk_request_checkpoints')->where('request_id', $id)->where('actor_id', $actor->id)->first() : null;
+
+ return ['installed' => $this->installed(), 'request' => ['id' => $id, 'version' => (int) $request->version, 'status' => $request->status,
+ 'protocol' => $request->protocol, 'analyst_id' => $request->analyst_id, 'due_at' => $request->due_at,
+ 'editable_fields' => json_decode($request->editable_fields ?? '[]', true), 'payload' => $desk->decode($request->payload),
+ 'can_edit' => ! $case->closed_at && in_array($request->status, ['draft', 'returned'], true)],
+ 'checkpoint' => $row ? ['version' => (int) $row->version, 'request_version' => (int) $row->request_version,
+ 'updated_at' => $row->updated_at, ...$desk->decode($row->snapshot)] : null];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, string $id, array $input): array
+ {
+ abort_unless($this->installed(), 409, 'A gravação automática requer a actualização de rascunhos. A gravação manual continua disponível.');
+ $data = Validator::make(['checkpoint' => $input], [
+ 'checkpoint' => 'required|array:version,request_version,operation_key,payload,edited_keys,reason',
+ 'checkpoint.version' => 'required|integer|min:0', 'checkpoint.request_version' => 'required|integer|min:1',
+ 'checkpoint.operation_key' => 'required|uuid', 'checkpoint.payload' => 'present|array',
+ 'checkpoint.edited_keys' => 'present|array|list|max:65', 'checkpoint.edited_keys.*' => 'required|string|distinct|max:100',
+ 'checkpoint.reason' => 'nullable|string|max:3000',
+ ])->validate()['checkpoint'];
+
+ return DB::transaction(function () use ($actor, $id, $data): array {
+ $desk = app(VirtualDesk::class);
+ $request = $desk->request($actor, $id, true, true);
+ $case = $desk->case($actor, $request->case_id, true, true);
+ abort_unless(! $case->closed_at && in_array($request->status, ['draft', 'returned'], true), 409, 'Este pedido já não permite alterar o rascunho.');
+ abort_unless((int) $request->version === (int) $data['request_version'], 409, 'O pedido mudou. Compare a versão actual antes de recuperar as suas alterações.');
+ $payload = $desk->checkpointFields($data['payload'], $desk->definition($request));
+ app(DeskAttachments::class)->snapshot($request, $payload, $desk->definition($request), false);
+ $allowed = [...array_keys($desk->definition($request)['fields']), 'country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'];
+ Validator::make($data, ['edited_keys.*' => [Rule::in($allowed)]])->validate();
+ $base = $desk->decode($request->payload);
+ $edited = array_values(array_unique([...$data['edited_keys'], ...array_filter(array_unique([...array_keys($base), ...array_keys($payload)]), fn ($key) => ($base[$key] ?? null) !== ($payload[$key] ?? null))]));
+ if ($request->status === 'returned') {
+ $editable = json_decode($request->editable_fields ?? '[]', true);
+ foreach (array_unique([...array_keys($base), ...array_keys($payload), ...$data['edited_keys']]) as $key) {
+ abort_if(! in_array($key, $editable, true) && ((($base[$key] ?? null) !== ($payload[$key] ?? null)) || in_array($key, $data['edited_keys'], true)), 422, 'O rascunho só pode corrigir os campos autorizados.');
+ }
+ }
+ $operationHash = hash('sha256', json_encode(Arr::sortRecursive(['version' => (int) $data['version'], 'request_version' => (int) $data['request_version'],
+ 'operation_key' => $data['operation_key'], 'payload' => $payload, 'edited_keys' => $data['edited_keys'], 'reason' => $data['reason'] ?? '']), JSON_THROW_ON_ERROR));
+ $row = DB::table('desk_request_checkpoints')->where('request_id', $id)->where('actor_id', $actor->id)->lockForUpdate()->first();
+ if ($row && $row->operation_key === $data['operation_key']) {
+ abort_unless(hash_equals($row->operation_sha256, $operationHash), 409, 'Esta tentativa já foi usada com outros dados.');
+
+ return $this->show($actor, $id);
+ }
+ abort_unless((int) ($row->version ?? 0) === (int) $data['version'], 409, 'O rascunho mudou noutro separador. Compare antes de substituir.');
+ $version = (int) ($row->version ?? 0) + 1;
+ DB::table('desk_request_checkpoints')->updateOrInsert(['request_id' => $id, 'actor_id' => $actor->id], [
+ 'version' => $version, 'request_version' => $request->version, 'operation_key' => $data['operation_key'], 'operation_sha256' => $operationHash,
+ 'snapshot' => $desk->encode(['payload' => $payload, 'base_payload' => $base, 'edited_keys' => $edited, 'reason' => $data['reason'] ?? '']),
+ 'created_at' => $row->created_at ?? now(), 'updated_at' => now(),
+ ]);
+ DB::table('audit_events')->insert(['source_system' => 'virtual-desk', 'entity_type' => 'desk_request_checkpoints', 'entity_id' => $id,
+ 'actor_user_id' => $actor->id, 'action' => 'draft_checkpoint_saved', 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['version' => $version, 'request_version' => (int) $request->version], JSON_THROW_ON_ERROR)]);
+
+ return $this->show($actor, $id);
+ });
+ }
+}
diff --git a/app/Services/DeskServiceAvailability.php b/app/Services/DeskServiceAvailability.php
new file mode 100644
index 00000000..e3cd24e1
--- /dev/null
+++ b/app/Services/DeskServiceAvailability.php
@@ -0,0 +1,47 @@
+where('status', 'published')
+ ->where(fn (Builder $date) => $date->whereNull('published_at')->orWhere('published_at', '<=', now()))
+ ->selectRaw('DISTINCT ON (code) *')->orderBy('code');
+ if ($this->scheduled()) {
+ $query->where(fn (Builder $date) => $date->whereNull('effective_from')->orWhere('effective_from', '<=', now()->toDateString()))
+ ->orderByRaw('effective_from DESC NULLS LAST');
+ }
+
+ return $query->orderByDesc('version');
+ }
+
+ public function upcoming(): Builder
+ {
+ $query = DB::table('desk_service_versions');
+ if (! $this->scheduled()) {
+ return $query->whereRaw('false')->select('code', 'version')->selectRaw('NULL::date AS effective_from');
+ }
+
+ return $query->where('status', 'published')->where('effective_from', '>', now()->toDateString())
+ ->where(fn (Builder $date) => $date->whereNull('published_at')->orWhere('published_at', '<=', now()))
+ ->selectRaw('DISTINCT ON (code,effective_from) code,version,effective_from')->orderBy('code')->orderBy('effective_from')->orderByDesc('version');
+ }
+
+ /** @return literal-string */
+ public function dateProjection(): string
+ {
+ return $this->scheduled() ? 'effective_from' : 'NULL::date AS effective_from';
+ }
+}
diff --git a/app/Services/DeskServiceEditor.php b/app/Services/DeskServiceEditor.php
index abc2a9bf..4ce0b593 100644
--- a/app/Services/DeskServiceEditor.php
+++ b/app/Services/DeskServiceEditor.php
@@ -15,18 +15,26 @@ final class DeskServiceEditor
/** @return list> */
public function listing(): array
{
+ $availability = app(DeskServiceAvailability::class);
+ $active = $availability->current()->get()->keyBy('code');
+ $upcoming = $availability->upcoming()->get()->groupBy('code')->map(fn ($rows) => $rows->map(fn ($row) => ['version' => (int) $row->version, 'effective_from' => $row->effective_from])->all());
$rows = DB::table('desk_service_versions')->selectRaw('DISTINCT ON (code) code, version, definition')
+ ->selectRaw($availability->dateProjection())
->orderBy('code')->orderByDesc('version')->get()->keyBy('code');
$services = [];
foreach (config('virtual-desk.services') as $code => $initial) {
$row = $rows->get($code);
$services[] = ['code' => $code, 'version' => (int) ($row->version ?? 0), 'editable' => true,
+ 'effective_from' => $row->effective_from ?? null, 'activeVersion' => (int) ($active->get($code)->version ?? 0),
+ 'upcoming' => $upcoming->get($code, []),
'fixedTypes' => array_map(fn (array $field) => $field['type'], $initial['fields']),
'definition' => $row ? json_decode($row->definition, true, 512, JSON_THROW_ON_ERROR) : $initial];
}
foreach ($rows as $code => $row) {
if (! array_key_exists($code, config('virtual-desk.services'))) {
$services[] = ['code' => $code, 'version' => (int) $row->version, 'editable' => false,
+ 'effective_from' => $row->effective_from ?? null, 'activeVersion' => (int) ($active->get($code)->version ?? 0),
+ 'upcoming' => $upcoming->get($code, []),
'definition' => json_decode($row->definition, true, 512, JSON_THROW_ON_ERROR)];
}
}
@@ -42,7 +50,8 @@ final class DeskServiceEditor
$total = (clone $query)->count();
$pages = max(1, (int) ceil($total / 10));
$page = min(max(1, $requestedPage), $pages);
- $rows = $query->orderByDesc('version')->forPage($page, 10)->get(['id', 'version', 'status', 'author_id', 'published_by', 'published_at', 'definition', 'source']);
+ $rows = $query->orderByDesc('version')->forPage($page, 10)->select(['id', 'version', 'status', 'author_id', 'published_by', 'published_at', 'definition', 'source'])
+ ->selectRaw(app(DeskServiceAvailability::class)->dateProjection())->get();
$events = DB::table('audit_events')->where('source_system', 'virtual-desk')->where('entity_type', 'desk_service_versions')
->where('action', 'service_definition_version_published')->whereIn('entity_id', $rows->pluck('id')->all())
->get(['entity_id', 'after_data'])->keyBy('entity_id');
@@ -54,6 +63,7 @@ final class DeskServiceEditor
return ['id' => $row->id, 'version' => (int) $row->version, 'status' => $row->status,
'author_id' => $row->author_id, 'published_by' => $row->published_by, 'published_at' => $row->published_at,
'definition' => json_decode($row->definition, true, 512, JSON_THROW_ON_ERROR),
+ 'effective_from' => $row->effective_from,
'source' => json_decode($row->source, true, 512, JSON_THROW_ON_ERROR), 'reason' => $audit['reason'] ?? null];
})->all()];
}
@@ -64,6 +74,7 @@ final class DeskServiceEditor
abort_unless(array_key_exists($code, config('virtual-desk.services')), 404);
$data = Validator::make($input, [
'base_version' => ['required', 'integer', 'min:0'], 'confirm' => ['accepted'],
+ 'effective_from' => ['nullable', 'date_format:Y-m-d'],
'reason' => ['required', 'string', 'min:20', 'max:2000'],
'definition' => ['required', 'array:title,theme,profile,stage,entity,result,fields'],
'definition.title' => ['required', 'string', 'max:200'],
@@ -73,14 +84,20 @@ final class DeskServiceEditor
'definition.entity' => ['required', 'string', 'max:300'],
'definition.result' => ['required', 'string', 'max:2000'],
'definition.fields' => ['required', 'array', 'min:1', 'max:60'],
- 'definition.fields.*' => ['required', 'array:label,type,required,min,options,when'],
+ 'definition.fields.*' => ['required', 'array:label,type,required,min,options,when,statement,mime_types,max_size_kb,max_files'],
'definition.fields.*.label' => ['required', 'string', 'max:300'],
- 'definition.fields.*.type' => ['required', Rule::in(['text', 'textarea', 'email', 'tel', 'url', 'number', 'date', 'select', 'territory'])],
+ 'definition.fields.*.type' => ['required', Rule::in(['text', 'textarea', 'email', 'tel', 'url', 'number', 'date', 'select', 'multiselect', 'consent', 'territory', 'attachment'])],
+ 'definition.fields.*.mime_types' => ['sometimes', 'array', 'list', 'min:1', 'max:4'],
+ 'definition.fields.*.mime_types.*' => ['required', 'string', Rule::in(DeskAttachments::MIME_TYPES)],
+ 'definition.fields.*.max_size_kb' => ['sometimes', 'integer', 'min:1', 'max:10240'],
+ 'definition.fields.*.max_files' => ['sometimes', 'integer', 'min:1', 'max:100'],
+ 'definition.fields.*.statement' => ['sometimes', 'string', 'min:3', 'max:5000'],
'definition.fields.*.required' => ['required', 'boolean'],
'definition.fields.*.min' => ['sometimes', 'numeric', 'min:0', 'max:999999999999'],
'definition.fields.*.options' => ['sometimes', 'array', 'min:1', 'max:100'],
'definition.fields.*.options.*' => ['required', 'string', 'max:300'],
- 'definition.fields.*.when' => ['sometimes', 'array:field,equals', 'required_array_keys:field,equals'],
+ 'definition.fields.*.when' => ['sometimes', 'array:field,equals,operator', 'required_array_keys:field,equals'],
+ 'definition.fields.*.when.operator' => ['sometimes', Rule::in(['equals', 'contains'])],
'definition.fields.*.when.field' => ['required_with:definition.fields.*.when', 'string', 'max:64'],
'definition.fields.*.when.equals' => ['required_with:definition.fields.*.when', 'string', 'max:1000'],
])->validate();
@@ -88,6 +105,10 @@ final class DeskServiceEditor
return DB::transaction(function () use ($actor, $code, $data): \stdClass {
DB::select('select pg_advisory_xact_lock(261008, 2)');
+ $scheduled = app(DeskServiceAvailability::class)->scheduled();
+ if (! $scheduled && ($data['effective_from'] ?? null) !== null) {
+ throw ValidationException::withMessages(['effective_from' => 'Instale a actualização das datas de entrada em vigor antes de agendar uma versão.']);
+ }
$latest = DB::table('desk_service_versions')->where('code', $code)->orderByDesc('version')->first();
$previous = $latest ? json_decode($latest->definition, true, 512, JSON_THROW_ON_ERROR) : config('virtual-desk.services.'.$code);
if ($data['definition']['stage'] !== $previous['stage']) {
@@ -100,16 +121,23 @@ final class DeskServiceEditor
}
// Retry of the same confirmed publication preserves the first version and authorship.
if ($latest && (int) $latest->version === (int) $data['base_version'] + 1 && $latest->status === 'published'
+ && $this->sameEffectiveRequest($latest, $data, $scheduled)
&& $this->definitionHash(json_decode($latest->definition, true, 512, JSON_THROW_ON_ERROR)) === $this->definitionHash($data['definition'])) {
return $latest;
}
abort_unless((int) ($latest->version ?? 0) === (int) $data['base_version'], 409, 'O formulário foi alterado. Recarregue e compare a versão actual antes de publicar.');
- if ($latest && $latest->status === 'published' && $this->definitionHash($previous) === $this->definitionHash($data['definition'])) {
- throw ValidationException::withMessages(['definition' => 'Não há alterações na definição para publicar uma nova versão.']);
+ if (($data['effective_from'] ?? null) !== null && $data['effective_from'] < now()->toDateString()) {
+ throw ValidationException::withMessages(['effective_from' => 'Uma nova publicação começa hoje ou numa data futura; não altera a vigência de pedidos anteriores.']);
+ }
+ $effective = ($data['effective_from'] ?? null) ?: now()->toDateString();
+ if ($latest && $latest->status === 'published' && $this->definitionHash($previous) === $this->definitionHash($data['definition'])
+ && (! $scheduled || ($latest->effective_from ?? null) === $effective || (! ($data['effective_from'] ?? null) && (! ($latest->effective_from ?? null) || $latest->effective_from <= now()->toDateString())))) {
+ throw ValidationException::withMessages(['definition' => 'Não há alterações na definição ou na data de início para publicar uma nova versão.']);
}
$id = (string) Str::uuid();
DB::table('desk_service_versions')->insert([
'id' => $id, 'code' => $code, 'version' => (int) $data['base_version'] + 1, 'status' => 'published',
+ ...($scheduled ? ['effective_from' => $effective] : []),
'definition' => json_encode($data['definition'], JSON_THROW_ON_ERROR),
'source' => $latest->source ?? json_encode(config('virtual-desk.source'), JSON_THROW_ON_ERROR),
'author_id' => $actor->id, 'published_by' => $actor->id, 'published_at' => now(), 'created_at' => now(), 'updated_at' => now(),
@@ -119,7 +147,10 @@ final class DeskServiceEditor
'action' => 'service_definition_version_published',
'before_data' => json_encode(['id' => $latest?->id, 'version' => (int) $data['base_version']], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['code' => $code, 'version' => (int) $data['base_version'] + 1, 'reason' => $data['reason'],
- 'effect' => 'new_requests_only', 'definition_sha256' => $this->definitionHash($data['definition'])], JSON_THROW_ON_ERROR),
+ 'effect' => 'new_requests_only', 'effective_from' => $scheduled ? $effective : null,
+ 'effective_request_mode' => ($data['effective_from'] ?? null) ? 'dated' : 'immediate',
+ 'selection' => 'latest_started_effective_date_then_version; undated_legacy_fallback',
+ 'definition_sha256' => $this->definitionHash($data['definition'])], JSON_THROW_ON_ERROR),
]);
return DB::table('desk_service_versions')->where('id', $id)->firstOrFail();
@@ -132,20 +163,59 @@ final class DeskServiceEditor
return hash('sha256', json_encode(Arr::sortRecursive($definition), JSON_THROW_ON_ERROR));
}
+ /** PostgreSQL JSONB does not retain object-key order.
+ * @param array $left
+ * @param array $right */
+ public function sameDefinition(array $left, array $right): bool
+ {
+ return $this->definitionHash($left) === $this->definitionHash($right);
+ }
+
+ /** @param array $data */
+ private function sameEffectiveRequest(\stdClass $latest, array $data, bool $scheduled): bool
+ {
+ if (! $scheduled || ($latest->effective_from ?? null) === null) {
+ return ! ($data['effective_from'] ?? null);
+ }
+ if ($data['effective_from'] ?? null) {
+ return $latest->effective_from === $data['effective_from'];
+ }
+ $event = DB::table('audit_events')->where('source_system', 'virtual-desk')->where('entity_type', 'desk_service_versions')
+ ->where('entity_id', $latest->id)->where('action', 'service_definition_version_published')->orderByDesc('id')->value('after_data');
+
+ return $event && (json_decode($event, true, 512, JSON_THROW_ON_ERROR)['effective_request_mode'] ?? null) === 'immediate';
+ }
+
/** @param array> $fields */
private function checkFields(array $fields): void
{
foreach ($fields as $key => $field) {
$path = 'definition.fields.'.$key;
+ if ($field['type'] === 'attachment') {
+ if (count(array_unique($field['mime_types'] ?? [])) !== count($field['mime_types'] ?? [])) {
+ throw ValidationException::withMessages([$path.'.mime_types' => 'Escolha cada formato apenas uma vez nesta pergunta.']);
+ }
+ if (! isset($field['mime_types'],$field['max_size_kb'],$field['max_files'])) {
+ throw ValidationException::withMessages([$path => 'Defina os formatos, tamanho por ficheiro e quantidade máxima desta pergunta.']);
+ }
+ if (! app(DeskAttachments::class)->scopedLinksInstalled()) {
+ throw ValidationException::withMessages([$path => 'Instale a actualização dos vínculos documentais antes de publicar perguntas de anexos. Os formulários existentes continuam disponíveis.']);
+ }
+ } elseif (array_intersect(['mime_types', 'max_size_kb', 'max_files'], array_keys($field))) {
+ throw ValidationException::withMessages([$path => 'Os limites de ficheiros pertencem apenas a perguntas de anexos.']);
+ }
if (! preg_match('/^[a-z][a-z0-9_]{0,63}$/D', (string) $key) || in_array($key, ['country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'], true)) {
throw ValidationException::withMessages(['definition.fields' => 'Use identificadores de campo distintos dos campos comuns de país e contexto, com letras minúsculas, números e sublinhado.']);
}
- if ($field['type'] === 'select' && empty($field['options'])) {
+ if (in_array($field['type'], ['select', 'multiselect'], true) && empty($field['options'])) {
throw ValidationException::withMessages([$path.'.options' => 'Indique as opções deste campo.']);
}
- if ((isset($field['min']) && $field['type'] !== 'number') || (isset($field['options']) && $field['type'] !== 'select')) {
+ if ((isset($field['min']) && $field['type'] !== 'number') || (isset($field['options']) && ! in_array($field['type'], ['select', 'multiselect'], true))) {
throw ValidationException::withMessages([$path => 'O mínimo aplica-se apenas a números e as opções apenas a listas de respostas.']);
}
+ if (($field['type'] === 'consent' && trim($field['statement'] ?? '') === '') || (isset($field['statement']) && $field['type'] !== 'consent')) {
+ throw ValidationException::withMessages([$path.'.statement' => 'Uma declaração de consentimento exige o texto exacto a apresentar; esse texto pertence apenas a campos de consentimento.']);
+ }
foreach (array_keys($field['options'] ?? []) as $option) {
if (! preg_match('/^[a-zA-Z0-9_-]{1,80}$/D', (string) $option)) {
throw ValidationException::withMessages([$path.'.options' => 'Use códigos de opção sem espaços ou pontuação especial.']);
@@ -158,12 +228,19 @@ final class DeskServiceEditor
if (! isset($fields[$parent]) || in_array($parent, $visited, true)) {
throw ValidationException::withMessages([$path.'.when' => 'A condição deve referir outro campo existente, sem dependências circulares.']);
}
- if ($fields[$parent]['type'] === 'number') {
- throw ValidationException::withMessages([$path.'.when' => 'As condições actuais comparam respostas exactas. Use uma lista de opções como origem da condição numérica.']);
+ if (in_array($fields[$parent]['type'], ['number', 'attachment'], true)) {
+ throw ValidationException::withMessages([$path.'.when' => 'Use uma resposta de texto, lista ou declaração como origem da condição; números e anexos não são respostas comparáveis por estas condições.']);
}
- if ($fields[$parent]['type'] === 'select' && ! array_key_exists($node['when']['equals'], $fields[$parent]['options'] ?? [])) {
+ $operator = $node['when']['operator'] ?? 'equals';
+ if (($fields[$parent]['type'] === 'multiselect') !== ($operator === 'contains')) {
+ throw ValidationException::withMessages([$path.'.when' => 'Use inclusão de uma opção para uma selecção múltipla e igualdade para respostas simples.']);
+ }
+ if (in_array($fields[$parent]['type'], ['select', 'multiselect'], true) && ! array_key_exists($node['when']['equals'], $fields[$parent]['options'] ?? [])) {
throw ValidationException::withMessages([$path.'.when' => 'O valor da condição deve corresponder a uma opção do campo escolhido.']);
}
+ if ($fields[$parent]['type'] === 'consent' && ! in_array($node['when']['equals'], ['accepted', 'declined'], true)) {
+ throw ValidationException::withMessages([$path.'.when' => 'Compare a declaração com accepted ou declined; uma resposta por preencher não é aceitação.']);
+ }
$visited[] = $parent;
$node = $fields[$parent];
}
@@ -188,7 +265,7 @@ final class DeskServiceEditor
$conditions = [];
while (isset($fields[$key]['when'])) {
$when = $fields[$key]['when'];
- $conditions[$when['field']] = $when['equals'];
+ $conditions[$when['field']] = ($when['operator'] ?? 'equals').':'.$when['equals'];
$key = $when['field'];
}
diff --git a/app/Services/EducationAccess.php b/app/Services/EducationAccess.php
new file mode 100644
index 00000000..d7bf1331
--- /dev/null
+++ b/app/Services/EducationAccess.php
@@ -0,0 +1,21 @@
+hasVerifiedEmail() && ! app(PortalProfileAccess::class)->has($actor, 'auditor')
+ && ($actor->can('manage-portal') || app(ScopedPortalAdministration::class)->administrative($actor));
+ }
+
+ public function authorize(User $actor): void
+ {
+ abort_unless(config('education.enabled'), 404);
+ abort_unless($this->allows($actor), 403);
+ }
+}
diff --git a/app/Services/EducationDeclarationDrafts.php b/app/Services/EducationDeclarationDrafts.php
new file mode 100644
index 00000000..cf85ec5a
--- /dev/null
+++ b/app/Services/EducationDeclarationDrafts.php
@@ -0,0 +1,142 @@
+installed() && in_array($kind, ['demands', 'capacities'], true), 404);
+ app(EducationAccess::class)->authorize($actor);
+ }
+
+ /** @return array */
+ public function show(User $actor, string $kind, string $id): array
+ {
+ $this->guard($actor, $kind);
+ $row = DB::table('education_declaration_drafts')->where('id', $id)->where('owner_user_id', $actor->id)->where('kind', $kind)->firstOrFail();
+
+ return ['id' => $id, 'kind' => $kind, 'version_no' => (int) $row->version_no, 'state' => $row->state,
+ 'payload' => $this->decode($row->payload),
+ 'references' => $row->reference_snapshot ? json_decode(Crypt::decryptString($row->reference_snapshot), true, 512, JSON_THROW_ON_ERROR) : null,
+ 'record_id' => $row->demand_id ?? $row->capacity_id, 'updated_at' => CarbonImmutable::parse($row->updated_at)->toIso8601String()];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, string $kind, ?string $id, array $input): array
+ {
+ $this->guard($actor, $kind);
+ $data = Validator::make($input, ['version_no' => 'required|integer|min:0', 'client_key' => $id ? 'sometimes|uuid' : 'required|uuid', 'payload' => 'present|array'])->validate();
+ $payload = $this->partial($kind, $data['payload']);
+
+ return DB::transaction(function () use ($actor, $kind, $id, $data, $payload): array {
+ DB::table('users')->where('id', $actor->id)->lock('FOR NO KEY UPDATE')->firstOrFail();
+ $query = DB::table('education_declaration_drafts')->where('owner_user_id', $actor->id);
+ $row = $id ? $query->where('id', $id)->where('kind', $kind)->lockForUpdate()->firstOrFail()
+ : $query->where('client_key', $data['client_key'])->lockForUpdate()->first();
+ abort_if($row && ($row->kind !== $kind || $row->state !== 'draft'), 409, 'Este rascunho já foi submetido ou pertence a outro tipo de declaração.');
+ if ($row && Arr::sortRecursive($this->decode($row->payload)) === Arr::sortRecursive($payload)
+ && in_array((int) $data['version_no'], [(int) $row->version_no, (int) $row->version_no - 1], true)) {
+ return $this->show($actor, $kind, $row->id);
+ }
+ abort_unless((int) ($row->version_no ?? 0) === (int) $data['version_no'], 409, 'O rascunho mudou. Recupere a versão actual antes de guardar.');
+ $id = $row->id ?? (string) Str::uuid();
+ DB::table('education_declaration_drafts')->updateOrInsert(['id' => $id], ['owner_user_id' => $actor->id, 'client_key' => $row->client_key ?? $data['client_key'],
+ 'kind' => $kind, 'version_no' => (int) ($row->version_no ?? 0) + 1, 'payload' => Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR)),
+ 'state' => 'draft', 'created_at' => $row->created_at ?? now(), 'updated_at' => now()]);
+ $this->audit($actor, $id, 'draft_saved', (int) ($row->version_no ?? 0) + 1, $kind);
+
+ return $this->show($actor, $kind, $id);
+ });
+ }
+
+ /** @param array $input
+ * @return array */
+ public function submit(User $actor, string $kind, string $id, array $input): array
+ {
+ $this->guard($actor, $kind);
+ $data = Validator::make($input, ['version_no' => 'required|integer|min:1', 'payload' => 'present|array'])->validate();
+ $payload = $this->partial($kind, $data['payload']);
+
+ return DB::transaction(function () use ($actor, $kind, $id, $data, $payload): array {
+ DB::table('users')->where('id', $actor->id)->lock('FOR NO KEY UPDATE')->firstOrFail();
+ $row = DB::table('education_declaration_drafts')->where('id', $id)->where('owner_user_id', $actor->id)->where('kind', $kind)->lockForUpdate()->firstOrFail();
+ if ($row->state === 'submitted') {
+ abort_unless(in_array((int) $data['version_no'], [(int) $row->version_no, (int) $row->version_no - 1], true)
+ && Arr::sortRecursive($this->decode($row->payload)) === Arr::sortRecursive($payload), 409);
+
+ return $this->show($actor, $kind, $id);
+ }
+ abort_unless((int) $row->version_no === (int) $data['version_no'], 409, 'O rascunho mudou. Recupere a versão actual antes de submeter.');
+ $validated = Validator::make($payload, EducationDeclarationRules::forKind($kind))->validate();
+ $references = [];
+ foreach (['occupation_id' => 'occupations', 'skill_id' => 'skills', $kind === 'demands' ? 'project_id' : 'course_id' => $kind === 'demands' ? 'projects' : 'courses'] as $field => $table) {
+ $source = DB::table($table)->where('id', $validated[$field])->firstOrFail();
+ $references[$field] = array_intersect_key((array) $source, array_flip(['id', 'name', 'title', 'code', 'provider_id', 'updated_at']));
+ }
+ $references['territory_path'] = array_map(fn ($node) => ['id' => $node->id, 'name' => $node->name, 'type' => $node->location_type], app(InvestmentGeography::class)->path($validated['geo_location_id'], true));
+ $record = $kind === 'demands' ? new LabourDemand : new TrainingCapacity;
+ PortalAudit::save($record, [...$validated, 'submitted_by' => $actor->id, 'status' => 'submitted'], $actor->id);
+ DB::table('education_declaration_drafts')->where('id', $id)->update(['payload' => Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR)),
+ 'reference_snapshot' => Crypt::encryptString(json_encode($references, JSON_THROW_ON_ERROR)),
+ 'state' => 'submitted', 'version_no' => (int) $row->version_no + 1, $kind === 'demands' ? 'demand_id' : 'capacity_id' => $record->id, 'updated_at' => now()]);
+ $this->audit($actor, $id, 'draft_submitted', (int) $row->version_no + 1, $kind);
+
+ return $this->show($actor, $kind, $id);
+ });
+ }
+
+ /** @param array $payload
+ * @return array */
+ private function partial(string $kind, array $payload): array
+ {
+ unset($payload[$kind === 'demands' ? 'course_id' : 'project_id']);
+ if ($kind === 'capacities') {
+ unset($payload['employer']);
+ }
+ $rules = ['occupation_id' => 'nullable|uuid', 'skill_id' => 'nullable|uuid', 'geo_location_id' => 'nullable|uuid',
+ $kind === 'demands' ? 'project_id' : 'course_id' => 'nullable|uuid', 'qualification' => 'nullable|string|max:150',
+ 'quantity' => 'nullable|integer|min:0|max:10000000', 'period_start' => 'nullable|date_format:Y-m-d', 'period_end' => 'nullable|date_format:Y-m-d',
+ 'source' => 'nullable|string|max:5000', 'reference_date' => 'nullable|date_format:Y-m-d', 'valid_until' => 'nullable|date_format:Y-m-d'];
+ if ($kind === 'demands') {
+ $rules['employer'] = 'nullable|string|max:200';
+ }
+ Validator::make(['payload' => $payload], ['payload' => 'array:'.implode(',', array_keys($rules))])->validate();
+
+ return Validator::make($payload, $rules)->validate();
+ }
+
+ private function audit(User $actor, string $id, string $action, int $version, string $kind): void
+ {
+ DB::table('audit_events')->insert(['source_system' => 'education-drafts', 'entity_type' => 'education_declaration_drafts', 'entity_id' => $id,
+ 'actor_user_id' => $actor->id, 'action' => $action, 'data_classification' => 'restricted', 'after_data' => json_encode(['version_no' => $version, 'kind' => $kind], JSON_THROW_ON_ERROR)]);
+ }
+
+ /** @return array */
+ private function decode(string $encrypted): array
+ {
+ $payload = json_decode(Crypt::decryptString($encrypted), true, 512, JSON_THROW_ON_ERROR);
+ if (! is_array($payload)) {
+ throw new \UnexpectedValueException('Invalid education draft payload.');
+ }
+
+ return $payload;
+ }
+}
diff --git a/app/Services/EducationDeclarationRules.php b/app/Services/EducationDeclarationRules.php
new file mode 100644
index 00000000..28c340b8
--- /dev/null
+++ b/app/Services/EducationDeclarationRules.php
@@ -0,0 +1,29 @@
+ */
+ public static function forKind(string $kind): array
+ {
+ abort_unless(in_array($kind, ['demands', 'capacities'], true), 404);
+ $demand = $kind === 'demands';
+
+ return [
+ 'occupation_id' => ['required', 'uuid', Rule::exists('occupations', 'id')->whereNull('deleted_at')],
+ 'skill_id' => ['required', 'uuid', Rule::exists('skills', 'id')->whereNull('deleted_at')],
+ 'geo_location_id' => ['required', 'uuid', Rule::exists('geo_locations', 'id')->whereNull('deleted_at')->whereIn('location_type', ['province', 'district', 'admin_post', 'locality'])],
+ $demand ? 'project_id' : 'course_id' => ['required', 'uuid', $demand ? Rule::exists('projects', 'id')->whereNull('deleted_at')
+ : Rule::exists('courses', 'id')->whereNull('deleted_at')->whereNot('status', 'retired')->where(fn ($query) => $query->whereIn('provider_id', TrainingProvider::where('status', '!=', 'inactive')->select('id')))],
+ 'employer' => [$demand ? 'required' : 'exclude', 'string', 'max:200'],
+ 'qualification' => ['required', 'string', 'max:150'], 'quantity' => ['required', 'integer', 'min:1', 'max:10000000'],
+ 'period_start' => ['required', 'date_format:Y-m-d'], 'period_end' => ['required', 'date_format:Y-m-d', 'after_or_equal:period_start'],
+ 'source' => ['required', 'string', 'min:10', 'max:5000'], 'reference_date' => ['required', 'date_format:Y-m-d', 'before_or_equal:today'],
+ 'valid_until' => ['required', 'date_format:Y-m-d', 'after_or_equal:reference_date'],
+ ];
+ }
+}
diff --git a/app/Services/EducationReviews.php b/app/Services/EducationReviews.php
new file mode 100644
index 00000000..b957eb73
--- /dev/null
+++ b/app/Services/EducationReviews.php
@@ -0,0 +1,101 @@
+ $input
+ * @return array{version:int,replayed:bool} */
+ public function decide(User $actor, string $kind, string $id, array $input): array
+ {
+ app(EducationAccess::class)->authorize($actor);
+ $data = Validator::make($input, ['client_key' => 'nullable|uuid', 'version_no' => 'required|integer|min:1', 'status' => 'required|in:reviewed,rejected', 'review_reason' => 'required|string|min:15|max:3000'])->validate();
+ $key = is_string($data['client_key'] ?? null) ? strtolower($data['client_key']) : null;
+ $hash = hash('sha256', json_encode(['version_no' => (int) $data['version_no'], 'status' => $data['status'], 'review_reason' => trim($data['review_reason'])], JSON_THROW_ON_ERROR));
+ $model = match ($kind) {
+ 'demands' => LabourDemand::class,'capacities' => TrainingCapacity::class,default => abort(404)
+ };
+
+ return DB::transaction(function () use ($actor, $model, $id, $data, $key, $hash) {
+ $record = $model::lockForUpdate()->findOrFail($id);
+ if ($key !== null) {
+ $event = DB::table('audit_events')->where('source_system', self::SOURCE)->where('actor_user_id', $actor->id)->where('entity_type', $record->getTable())->where('entity_id', $id)->where('action', 'review_committed')
+ ->whereRaw("after_data->'education_review'->>'key' = ?", [$key])->selectRaw("after_data->'education_review'->>'hash' AS hash,after_data->'education_review'->'version' AS version")->first();
+ if ($event) {
+ abort_unless($event->hash === $hash, 409, 'Esta tentativa de revisão já foi usada com outros dados. Compare antes de continuar.');
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ abort_unless(is_int($version) && $version > 0, 409, 'A revisão anterior não pôde ser identificada com segurança.');
+
+ return ['version' => $version, 'replayed' => true];
+ }
+ }
+ abort_if((int) $record->getAttribute('submitted_by') === $actor->id, 403, 'Outro gestor deve efectuar a revisão.');
+ abort_if((int) $record->getAttribute('version_no') !== (int) $data['version_no'], 409, 'A versão foi alterada. Compare os dados actuais antes de decidir.');
+ abort_if($record->getAttribute('valid_until') < now()->toDateString(), 422, 'A fonte expirou.');
+ $version = (int) $data['version_no'] + 1;
+ $before = ['version' => (int) $record->getAttribute('version_no'), 'status' => $record->getAttribute('status'), 'review_reason' => $record->getAttribute('review_reason'), 'reviewed_by' => $record->getAttribute('reviewed_by')];
+ $subject = Arr::only($record->getAttributes(), ['id', 'project_id', 'course_id', 'occupation_id', 'skill_id', 'geo_location_id', 'employer', 'qualification', 'quantity', 'period_start', 'period_end', 'source', 'reference_date', 'valid_until', 'submitted_by']);
+ PortalAudit::save($record, ['status' => $data['status'], 'review_reason' => trim($data['review_reason']), 'version_no' => $version, 'reviewed_by' => $actor->id], $actor->id);
+ $snapshot = ['subject' => $subject, 'before' => $before, 'after' => ['version' => $version, 'status' => $data['status'], 'review_reason' => $record->getAttribute('review_reason'), 'reviewed_by' => $actor->id]];
+ DB::table('audit_events')->insert(['source_system' => self::SOURCE, 'actor_user_id' => $actor->id, 'entity_type' => $record->getTable(), 'entity_id' => $id, 'action' => 'review_committed', 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['education_review' => ['key' => $key, 'hash' => $key !== null ? $hash : null, 'version' => $version, 'snapshot' => Crypt::encryptString(json_encode($snapshot, JSON_THROW_ON_ERROR))]], JSON_THROW_ON_ERROR)]);
+
+ return ['version' => $version, 'replayed' => false];
+ });
+ }
+
+ /** @return array{actor_id:int,commands:list} */
+ public function context(User $actor, LabourDemand|TrainingCapacity $record): array
+ {
+ app(EducationAccess::class)->authorize($actor);
+ $commands = [];
+ foreach (DB::table('audit_events')->where('source_system', self::SOURCE)->where('actor_user_id', $actor->id)->where('entity_type', $record->getTable())->where('entity_id', $record->id)->where('action', 'review_committed')
+ ->selectRaw("after_data->'education_review'->>'key' AS key,after_data->'education_review'->'version' AS version")->get() as $event) {
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ if (is_string($event->key) && is_int($version) && $version > 0) {
+ $commands[] = ['key' => $event->key, 'version' => $version];
+ }
+ }
+
+ return ['actor_id' => $actor->id, 'commands' => $commands];
+ }
+
+ /** Paginated private view data; no mutable paginator escapes the service.
+ * @return array */
+ public function history(User $actor, LabourDemand|TrainingCapacity $record): array
+ {
+ app(EducationAccess::class)->authorize($actor);
+
+ return DB::table('audit_events as event')->leftJoin('users', 'users.id', '=', 'event.actor_user_id')->where('event.source_system', self::SOURCE)
+ ->where('event.entity_type', $record->getTable())->where('event.entity_id', $record->id)->where('event.action', 'review_committed')
+ ->selectRaw("event.id,event.occurred_at,users.name AS actor,event.after_data->'education_review'->'version' AS version,event.after_data->'education_review'->>'snapshot' AS snapshot")
+ ->orderByRaw("CASE WHEN (event.after_data->'education_review'->>'version') ~ '^[0-9]{1,10}$' THEN (event.after_data->'education_review'->>'version')::bigint END DESC NULLS LAST")
+ ->orderByDesc('event.occurred_at')->orderByDesc('event.id')->paginate(10, ['*'], 'history_page')->withQueryString()->through(function ($event) {
+ $version = is_string($event->version) ? json_decode($event->version, true) : $event->version;
+ $content = null;
+ try {
+ if (is_string($event->snapshot)) {
+ $content = json_decode(Crypt::decryptString($event->snapshot), true);
+ }
+ } catch (DecryptException) {/* Retain metadata and encrypted original; do not invent a past reason. */
+ }
+ $available = is_array($content) && isset($content['after']) && is_array($content['after']) && ($content['after']['version'] ?? null) === $version && is_string($content['after']['review_reason'] ?? null)
+ && in_array($content['after']['status'] ?? null, ['reviewed', 'rejected'], true);
+
+ return ['id' => $event->id, 'version' => is_int($version) && $version > 0 ? $version : null, 'actor' => $event->actor, 'occurred_at' => $event->occurred_at, 'available' => $available,
+ 'status' => $available ? $content['after']['status'] : null, 'reason' => $available ? $content['after']['review_reason'] : null,
+ 'previous_reason' => $available && is_string($content['before']['review_reason'] ?? null) ? $content['before']['review_reason'] : null];
+ })->toArray();
+ }
+}
diff --git a/app/Services/EducationWorkQueue.php b/app/Services/EducationWorkQueue.php
new file mode 100644
index 00000000..e32e849c
--- /dev/null
+++ b/app/Services/EducationWorkQueue.php
@@ -0,0 +1,40 @@
+,capacities:array} */
+ public function summary(User $actor): array
+ {
+ app(EducationAccess::class)->authorize($actor);
+
+ return ['actor_id' => $actor->id, 'drafts' => app(EducationDeclarationDrafts::class)->installed() ? DB::table('education_declaration_drafts')->where('owner_user_id', $actor->id)->where('state', 'draft')->count() : null,
+ 'demands' => $this->counts('labour_demands', $actor), 'capacities' => $this->counts('training_capacities', $actor)];
+ }
+
+ /** @return array */
+ private function counts(string $table, User $actor): array
+ {
+ $today = now()->toDateString();
+ $id = $actor->id;
+ $row = DB::table($table)->whereNull('deleted_at')->selectRaw("count(*) FILTER(WHERE submitted_by=?) AS total,
+ count(*) FILTER(WHERE submitted_by=? AND valid_until>=? AND status='submitted') AS submitted,
+ count(*) FILTER(WHERE submitted_by=? AND valid_until>=? AND status='reviewed') AS reviewed,
+ count(*) FILTER(WHERE submitted_by=? AND valid_until>=? AND status='rejected') AS rejected,
+ count(*) FILTER(WHERE submitted_by=? AND valid_until) AS expired,
+ count(*) FILTER(WHERE submitted_by<>? AND valid_until>=? AND status='submitted') AS to_review", [$id, $id, $today, $id, $today, $id, $today, $id, $today, $id, $today])->first();
+ if ($row === null) {
+ throw new \LogicException('Education aggregate result missing.');
+ }
+ $result = [];
+ foreach (['total', 'submitted', 'reviewed', 'rejected', 'expired', 'to_review'] as $key) {
+ $result[$key] = (int) $row->$key;
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Services/ExistingBusinessDrafts.php b/app/Services/ExistingBusinessDrafts.php
index f80d2e67..db95d352 100644
--- a/app/Services/ExistingBusinessDrafts.php
+++ b/app/Services/ExistingBusinessDrafts.php
@@ -41,7 +41,7 @@ final class ExistingBusinessDrafts
'payload.declared_reason' => ['nullable', 'string', 'max:2000'],
'payload.source_reference' => ['nullable', 'string', 'max:2000'],
'payload.valid_until' => ['nullable', 'date_format:Y-m-d'],
- ...BusinessFormSchema::rules(),
+ ...BusinessFormSchema::rules(is_array($input['payload'] ?? null) ? $input['payload'] : []),
])->validate();
return DB::transaction(function () use ($actor, $id, $data) {
@@ -95,6 +95,7 @@ final class ExistingBusinessDrafts
public function snapshot(ExistingBusiness $business, User $actor, string $action, string $reason, array $context = []): void
{
$snapshot = json_encode(['context' => $context, 'record' => $business->attributesToArray(), 'payload' => $business->payload,
+ 'locations' => DB::table('existing_business_locations')->where('existing_business_id', $business->id)->orderBy('id')->select('*')->selectRaw('ST_AsEWKT(geom) AS geometry_snapshot')->get()->map(fn ($row) => (array) $row)->all(),
'objects' => ExistingBusinessObject::where('business_id', $business->id)->orderBy('id')->get()
->map(fn ($object) => [...$object->attributesToArray(), 'payload' => $object->payload])->all(),
], JSON_THROW_ON_ERROR);
diff --git a/app/Services/ExistingBusinessIntake.php b/app/Services/ExistingBusinessIntake.php
index 947e4300..1614469e 100644
--- a/app/Services/ExistingBusinessIntake.php
+++ b/app/Services/ExistingBusinessIntake.php
@@ -122,6 +122,7 @@ final class ExistingBusinessIntake
$submissionRules['valid_until'][0] = 'required';
}
Validator::make([...$business->payload, 'consent' => $consent], $submissionRules)->validate();
+ app(BusinessPointPublication::class)->candidate($business->payload);
}
if ($action === OpportunityStatus::Approved->value) {
$levelOneActor = DB::table('business_workflow_transitions')->where('existing_business_id', $business->id)
@@ -138,6 +139,7 @@ final class ExistingBusinessIntake
abort_unless(! in_array((int) $actor->id, $approvalActors, true), 403,
'A publicação deve ser executada por uma pessoa diferente dos aprovadores.');
}
+ $pointContext = $action === OpportunityStatus::Published->value ? app(BusinessPointPublication::class)->publish($business) : [];
$fromStatus = $business->status;
$business->status = $action;
if ($action === OpportunityStatus::Published->value) {
@@ -190,7 +192,7 @@ final class ExistingBusinessIntake
DB::table('existing_business_reviews')->insert(['id' => (string) Str::uuid(), 'business_id' => $id, 'actor_id' => $actor->id,
'version_no' => $business->version_no, 'action' => $action,
'note' => Crypt::encryptString(json_encode(['note' => $note, 'review_consent' => $action === 'submitted' ? $consent : null], JSON_THROW_ON_ERROR))]);
- app(ExistingBusinessDrafts::class)->snapshot($business, $actor, $action, $note);
+ app(ExistingBusinessDrafts::class)->snapshot($business, $actor, $action, $note, $pointContext);
return $business;
});
diff --git a/app/Services/InvestmentGuides.php b/app/Services/InvestmentGuides.php
new file mode 100644
index 00000000..58edd5aa
--- /dev/null
+++ b/app/Services/InvestmentGuides.php
@@ -0,0 +1,169 @@
+ */
+ public function guide(string $slug): array
+ {
+ $guide = config('investment-guides.'.$slug);
+ abort_unless(is_array($guide), 404);
+
+ return [...$guide, 'sha256' => hash('sha256', json_encode($guide, JSON_THROW_ON_ERROR))];
+ }
+
+ /** Only coded choices pass through public/authentication URLs.
+ * @param array $input
+ * @return array */
+ public function selection(array $input): array
+ {
+ $v = Validator::make($input, ['slug' => ['required', 'string', Rule::in(array_keys(config('investment-guides')))], 'sha256' => 'required|string|size:64'])->validate();
+ $guide = $this->guide($v['slug']);
+ abort_unless(hash_equals($guide['sha256'], $v['sha256']), 409, 'O guia mudou desde a consulta. Abra a edição actual antes de preparar uma nova referência.');
+
+ return ['slug' => $v['slug'], 'sha256' => $v['sha256'], 'instruments' => $this->choices($input, $guide)];
+ }
+
+ /** @param array $input
+ * @param array $guide
+ * @return list */
+ private function choices(array $input, array $guide): array
+ {
+ $v = Validator::make($input, ['instruments' => ['sometimes', 'array', 'list', 'max:20'], 'instruments.*' => ['string', Rule::in(array_keys($guide['instruments']))]])->validate();
+ $values = array_values(array_unique($v['instruments'] ?? []));
+ sort($values);
+
+ return $values;
+ }
+
+ /** @param array $input
+ * @return array */
+ public function publicView(string $slug, array $input): array
+ {
+ $guide = $this->guide($slug);
+
+ return ['guide' => $guide, 'instruments' => $this->choices($input, $guide), 'note' => '', 'case' => null, 'saved' => null,
+ 'canWrite' => false, 'historical' => false, 'olderEdition' => false, 'currentAvailable' => true, 'workingCopy' => false, 'history' => [], 'historyNext' => null, 'contextChanged' => false, 'unavailableInstruments' => []];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function view(User $actor, string $id, string $slug, array $input): array
+ {
+ $case = $this->desk->case($actor, $id);
+ $current = is_array(config('investment-guides.'.$slug)) ? $this->guide($slug) : null;
+ $v = Validator::make($input, ['revision' => 'nullable|uuid', 'history_before' => 'nullable|integer|min:1', 'current' => 'nullable|boolean', 'selection' => 'nullable|boolean'])->validate();
+ $saved = $this->desk->decode($case->payload)['investment_guides'][$slug] ?? null;
+ if (! empty($v['revision'])) {
+ abort_if(isset($input['instruments']) || ! empty($v['current']) || ! empty($v['selection']), 422, 'A revisão histórica conserva a referência original.');
+ $row = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->where('id', $v['revision'])->first();
+ abort_unless($row !== null, 404);
+ $saved = $this->desk->decode($row->payload)['snapshot'];
+ abort_unless($saved['guide']['slug'] === $slug, 404);
+ }
+ $working = array_key_exists('instruments', $input) || ! empty($v['current']) || ! empty($v['selection']);
+ abort_unless($current !== null || $saved !== null, 404);
+ abort_if($working && $current === null, 409, 'O guia foi retirado da consulta actual; as referências guardadas continuam disponíveis.');
+ if ($working && isset($input['sha256'])) {
+ $this->selection([...$input, 'slug' => $slug]);
+ }
+ $guide = $working || ! $saved ? $current : $saved['guide'];
+ $selected = array_key_exists('instruments', $input) || ! empty($v['selection']) ? $this->choices($input, $guide)
+ : ($working ? array_values(array_intersect($saved['instruments'] ?? [], array_keys($guide['instruments']))) : ($saved['instruments'] ?? []));
+ $events = DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)
+ ->when(! empty($v['history_before']), fn ($q) => $q->where('event_order', '<', $v['history_before']))
+ ->orderByDesc('event_order')->cursor();
+ $history = [];
+ foreach ($events as $event) {
+ $snapshot = $this->desk->decode($event->payload)['snapshot'];
+ if ($snapshot['guide']['slug'] !== $slug) {
+ continue;
+ }
+ $history[] = ['id' => $event->id, 'revision' => $snapshot['revision'], 'at' => $snapshot['at'], 'edition' => $snapshot['guide']['version'], 'order' => $event->event_order];
+ if (count($history) === 26) {
+ break;
+ }
+ }
+ $context = app(InvestorContext::class)->state($case);
+ $unavailable = [];
+ if ($working && $saved) {
+ foreach ($saved['instruments'] as $code) {
+ if (! isset($guide['instruments'][$code])) {
+ $unavailable[] = $saved['guide']['instruments'][$code]['title'];
+ }
+ }
+ }
+
+ return ['guide' => $guide, 'instruments' => $selected, 'note' => $saved['note'] ?? '', 'saved' => $saved,
+ 'case' => ['id' => $id, 'title' => $case->title, 'version' => (int) $case->version],
+ 'canWrite' => ! $case->closed_at && $this->desk->owns($actor, $case), 'historical' => ! empty($v['revision']),
+ 'olderEdition' => $current === null || $guide['sha256'] !== $current['sha256'], 'currentAvailable' => $current !== null, 'workingCopy' => $working,
+ 'contextChanged' => $saved && ($saved['context']['revision'] !== $context['revision'] || $saved['context']['dependency_hash'] !== ($context['dependency_hash'] ?? null)),
+ 'unavailableInstruments' => $unavailable,
+ 'history' => array_slice($history, 0, 25), 'historyNext' => count($history) > 25 ? $history[24]['order'] : null];
+ }
+
+ /** @param array $input
+ * @param array $guide
+ * @return array */
+ private function reference(array $input, array $guide): array
+ {
+ $v = Validator::make($input, ['sha256' => ['required', Rule::in([$guide['sha256']])], 'note' => 'nullable|string|max:3000'])->validate();
+
+ return ['sha256' => $v['sha256'], 'note' => $v['note'] ?? '', 'instruments' => $this->choices($input, $guide)];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, string $id, string $slug, array $input): array
+ {
+ $this->desk->case($actor, $id, true);
+ $v = Validator::make($input, ['version' => 'required|integer|min:1', 'operation_key' => 'required|uuid'])->validate();
+
+ return DB::transaction(function () use ($actor, $id, $slug, $input, $v) {
+ $case = $this->desk->case($actor, $id, true, true);
+ foreach (DB::table('desk_events')->where('case_id', $id)->where('action', self::EVENT)->orderByDesc('event_order')->cursor() as $event) {
+ $data = $this->desk->decode($event->payload);
+ if ($data['operation_key'] === $v['operation_key']) {
+ abort_unless($data['snapshot']['guide']['slug'] === $slug, 409);
+ $reference = $this->reference($input, $data['snapshot']['guide']);
+ $hash = hash('sha256', json_encode([(int) $v['version'], $slug, $reference], JSON_THROW_ON_ERROR));
+ abort_unless(hash_equals($data['request_hash'], $hash), 409, 'Esta operação já guardou uma referência diferente.');
+
+ return ['saved' => true, 'replayed' => true, 'revision' => $data['snapshot']['revision']];
+ }
+ }
+ $guide = $this->guide($slug);
+ abort_unless(($input['sha256'] ?? null) === $guide['sha256'], 409, 'O guia mudou. Conserve a nota e abra a edição actual para uma nova referência.');
+ $reference = $this->reference($input, $guide);
+ abort_if($case->closed_at || (int) $case->version !== (int) $v['version'], 409, 'O dossier mudou ou foi fechado. Os dados continuam nesta página; confira a edição guardada antes de tentar novamente.');
+ $payload = $this->desk->decode($case->payload);
+ $previous = $payload['investment_guides'][$slug] ?? null;
+ $state = app(InvestorContext::class)->state($case);
+ $context = ['revision' => $state['revision'], 'dependency_hash' => $state['dependency_hash'] ?? null];
+ if ($previous && $previous['guide'] === $guide && $previous['instruments'] === $reference['instruments'] && $previous['note'] === $reference['note'] && $previous['context'] === $context) {
+ return ['saved' => true, 'unchanged' => true, 'revision' => $previous['revision']];
+ }
+ $snapshot = ['revision' => (int) ($previous['revision'] ?? 0) + 1, 'guide' => $guide, 'instruments' => $reference['instruments'], 'note' => $reference['note'],
+ 'context' => $context, 'scope' => 'dossier_reference', 'at' => now()->toIso8601String(), 'actor_id' => $actor->id];
+ $payload['investment_guides'][$slug] = $snapshot;
+ $case->version++;
+ DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'version' => $case->version, 'updated_at' => now()]);
+ $hash = hash('sha256', json_encode([(int) $v['version'], $slug, $reference], JSON_THROW_ON_ERROR));
+ $this->desk->event($case, $actor, self::EVENT, ['operation_key' => $v['operation_key'], 'request_hash' => $hash, 'snapshot' => $snapshot]);
+
+ return ['saved' => true, 'replayed' => false, 'revision' => $snapshot['revision']];
+ });
+ }
+}
diff --git a/app/Services/InvestmentProfileCommands.php b/app/Services/InvestmentProfileCommands.php
new file mode 100644
index 00000000..8da3b4fe
--- /dev/null
+++ b/app/Services/InvestmentProfileCommands.php
@@ -0,0 +1,68 @@
+ $command
+ * @return array{version:int,id?:string,country?:string}|null
+ */
+ public function replay(User $actor, ?string $key, array $command): ?array
+ {
+ if ($key === null) {
+ return null;
+ }
+ $event = DB::table('audit_events')->where('source_system', self::SOURCE)->where('actor_user_id', $actor->id)->where('correlation_id', strtolower($key))->first();
+ if (! $event) {
+ return null;
+ }
+ $data = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR);
+ abort_unless(is_array($data) && is_string($data['command_encrypted'] ?? null) && hash_equals(Crypt::decryptString($data['command_encrypted']), $this->canonical($command)), 409,
+ 'Este pedido já foi utilizado com outros dados. Consulte o registo guardado antes de preparar outro pedido.');
+ $result = is_string($data['result_encrypted'] ?? null) ? json_decode(Crypt::decryptString($data['result_encrypted']), true, 512, JSON_THROW_ON_ERROR) : ($data['result'] ?? null);
+ if (! is_array($result) || ! is_int($result['version'] ?? null) || $result['version'] < 1
+ || (array_key_exists('id', $result) && (! is_string($result['id']) || ! Str::isUuid($result['id'])))
+ || (array_key_exists('country', $result) && (! is_string($result['country']) || preg_match('/^[A-Z]{2}$/D', $result['country']) !== 1))) {
+ throw new \LogicException('Stored workspace command result unavailable.');
+ }
+
+ $receipt = isset($result['id']) ? ['id' => $result['id'], 'version' => $result['version']] : ['version' => $result['version']];
+ if (isset($result['country'])) {
+ $receipt['country'] = $result['country'];
+ }
+
+ return $receipt;
+ }
+
+ /** @param array $command
+ * @param array{version:int,id?:string,country?:string} $result */
+ public function record(User $actor, ?string $key, array $command, array $result): void
+ {
+ if ($key === null) {
+ return;
+ }
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => self::SOURCE, 'actor_user_id' => $actor->id,
+ 'entity_type' => 'investment-profile-command', 'entity_id' => $result['id'] ?? null, 'action' => 'command_applied', 'correlation_id' => strtolower($key), 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['command_encrypted' => Crypt::encryptString($this->canonical($command)), ...(array_key_exists('country', $result) ? ['result_encrypted' => Crypt::encryptString(json_encode($result, JSON_THROW_ON_ERROR))] : ['result' => $result])], JSON_THROW_ON_ERROR)]);
+ }
+
+ /** @param array $command */
+ private function canonical(array $command): string
+ {
+ if (is_array($command['payload'] ?? null)) {
+ ksort($command['payload']);
+ }
+ ksort($command);
+
+ return json_encode($command, JSON_THROW_ON_ERROR);
+ }
+}
diff --git a/app/Services/InvestorPath.php b/app/Services/InvestorPath.php
index 1f73701e..7f440381 100644
--- a/app/Services/InvestorPath.php
+++ b/app/Services/InvestorPath.php
@@ -176,9 +176,9 @@ final class InvestorPath
->whereNull('deleted_at')
->when(! $owner && ! $manager, fn ($q) => $q->where('assignee_user_id', $actor->id))
->get(['id', 'title', 'status', 'version_no', 'due_at', 'assignee_user_id']),
- 'services' => DB::table('desk_service_versions')->where('status', 'published')->orderByDesc('version')->get(['id', 'code', 'definition'])
- ->unique('code')->values()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title']]),
+ 'services' => app(DeskServiceAvailability::class)->current()->get()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title'], 'effective_from' => $s->effective_from ?? null]),
'tools' => ['simulator' => (int) $case->user_id === $actor->id ? '/simulador-fiscal?context='.$id.($case->simulation_id ? '&draft='.$case->simulation_id : '').($opportunity ? '&opportunity='.urlencode($opportunity) : '') : null,
+ 'company' => '/investimentos/'.$id.'/forma-juridica',
'desk' => '/balcao-virtual/dossiers/'.$id.($opportunity ? '?opportunity='.urlencode($opportunity) : ''), 'guidance' => '/balcao-virtual/dossiers/'.$id.'/orientacao',
'library' => '/documentos?context='.$id, 'opportunities' => '/oportunidades?context='.$id, 'territory' => '/zonas?context='.$id, 'partners' => '/parcerias/painel?context='.$id,
'land' => ($facts['land_needed'] ?? 'unknown') !== 'no' && (int) $case->user_id === $actor->id ? ($landCase ? '/investidor/terra-duat/'.$landCase->id : '/investidor/terra-duat/novo?context='.$id.($opportunity ? '&opportunity='.urlencode($opportunity) : '')) : null]];
diff --git a/app/Services/Malware/DocumentScanAttempts.php b/app/Services/Malware/DocumentScanAttempts.php
new file mode 100644
index 00000000..89984f8f
--- /dev/null
+++ b/app/Services/Malware/DocumentScanAttempts.php
@@ -0,0 +1,76 @@
+malware_scan_attempts;
+ if ($expectedAttempt !== null && $attempt !== $expectedAttempt) {
+ return false;
+ }
+ $events = DB::table('audit_events')->where('source_system', self::SOURCE)->where('entity_type', 'document-scan')->where('entity_id', $document->id)
+ ->where('action', 'scan_started')->whereRaw("after_data->>'attempt' = ?", [(string) $attempt])->get(['after_data']);
+ if ($events->count() !== 1) {
+ return false;
+ }
+ $lease = json_decode($events->first()->after_data, true, 512, JSON_THROW_ON_ERROR);
+
+ return is_array($lease) && ($lease['run_id'] ?? null) === $run && ($lease['delivery_attempt'] ?? null) === $delivery && ($lease['attempt'] ?? null) === $attempt;
+ }
+
+ public function start(stdClass $document, string $run, int $delivery): int
+ {
+ $attempt = (int) $document->malware_scan_attempts + 1;
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => self::SOURCE, 'entity_type' => 'document-scan', 'entity_id' => $document->id,
+ 'actor_user_id' => null, 'action' => 'scan_started', 'correlation_id' => $run, 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['run_id' => $run, 'delivery_attempt' => $delivery, 'attempt' => $attempt, 'file_sha256' => trim($document->sha256), 'file_size_bytes' => $document->size_bytes ?? null], JSON_THROW_ON_ERROR)]);
+
+ return $attempt;
+ }
+
+ /** @return array{sha256:string,size_bytes:int|null}|null */
+ public function descriptor(stdClass $document, string $run, int $delivery): ?array
+ {
+ if (! $this->owns($document, $run, $delivery)) {
+ return null;
+ }
+ $event = DB::table('audit_events')->where('source_system', self::SOURCE)->where('entity_type', 'document-scan')->where('entity_id', $document->id)
+ ->where('action', 'scan_started')->whereRaw("after_data->>'attempt' = ?", [(string) $document->malware_scan_attempts])->first(['after_data']);
+ $data = $event ? json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR) : null;
+ if (! is_array($data) || ! is_string($data['file_sha256'] ?? null) || preg_match('/^[a-f0-9]{64}$/D', $data['file_sha256']) !== 1
+ || ! array_key_exists('file_size_bytes', $data) || ($data['file_size_bytes'] !== null && ! is_int($data['file_size_bytes']))) {
+ return null;
+ }
+
+ return ['sha256' => $data['file_sha256'], 'size_bytes' => $data['file_size_bytes']];
+ }
+
+ public function completed(string $documentId, string $run): bool
+ {
+ return DB::table('audit_events')->where('source_system', self::SOURCE)->where('entity_type', 'document-scan')->where('entity_id', $documentId)
+ ->where('action', 'scan_result_recorded')->where('correlation_id', $run)->whereRaw("after_data->>'retryable_failure' = 'false'")->exists();
+ }
+
+ public function finish(stdClass $document, string $run, int $delivery, string $scanId, bool $retryableFailure): void
+ {
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => self::SOURCE, 'entity_type' => 'document-scan', 'entity_id' => $document->id,
+ 'actor_user_id' => null, 'action' => 'scan_result_recorded', 'correlation_id' => $run, 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['run_id' => $run, 'delivery_attempt' => $delivery, 'attempt' => (int) $document->malware_scan_attempts, 'scan_id' => $scanId, 'retryable_failure' => $retryableFailure], JSON_THROW_ON_ERROR)]);
+ }
+
+ public function discarded(stdClass $document, string $run, int $delivery, int $expectedAttempt): void
+ {
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => self::SOURCE, 'entity_type' => 'document-scan', 'entity_id' => $document->id,
+ 'actor_user_id' => null, 'action' => 'scan_result_discarded', 'correlation_id' => $run, 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['run_id' => $run, 'delivery_attempt' => $delivery, 'attempt' => $expectedAttempt, 'current_attempt' => (int) $document->malware_scan_attempts], JSON_THROW_ON_ERROR)]);
+ }
+}
diff --git a/app/Services/Malware/DocumentScanDelivery.php b/app/Services/Malware/DocumentScanDelivery.php
new file mode 100644
index 00000000..1e5ef390
--- /dev/null
+++ b/app/Services/Malware/DocumentScanDelivery.php
@@ -0,0 +1,46 @@
+acquire($job)) {
+ return 'duplicate';
+ }
+ $attempted = false;
+ $contextAdded = false;
+ try {
+ if ($prepare !== null && ! $prepare()) {
+ return 'stale';
+ }
+ $this->addUniqueJobInformationToContext($job);
+ $contextAdded = true;
+ $attempted = true;
+ Bus::dispatch($job);
+
+ return 'accepted';
+ } finally {
+ if ($contextAdded) {
+ $this->removeUniqueJobInformationFromContext($job);
+ }
+ // A push error may follow acceptance. Keep its lease until the worker or expiry.
+ if (! $attempted) {
+ $lock->release($job);
+ }
+ }
+ }
+}
diff --git a/app/Services/Malware/DocumentScanRetry.php b/app/Services/Malware/DocumentScanRetry.php
new file mode 100644
index 00000000..616adefd
--- /dev/null
+++ b/app/Services/Malware/DocumentScanRetry.php
@@ -0,0 +1,78 @@
+documents($actor)->where('id', $id)->lockForUpdate()->first();
+ abort_unless($document && $document->status !== 'deleted' && $document->deleted_at === null, 404);
+ abort_unless(in_array($document->malware_scan_status, ['pending', 'inconclusive', 'failed'], true), 422,
+ 'Só é possível repetir uma análise pendente, inconclusiva ou falhada. Para substituir um ficheiro, carregue uma nova versão.');
+
+ DB::afterCommit(function () use ($actor, $id, $job, $document, &$outcome): void {
+ $prepared = false;
+ try {
+ $outcome = app(DocumentScanDelivery::class)->dispatch($job, function () use ($actor, $id, $job, $document, &$prepared): bool {
+ $ready = DB::transaction(function () use ($actor, $id, $job, $document): bool {
+ $currentActor = $actor->fresh();
+ if (! $currentActor) {
+ return false;
+ }
+ $access = app(DocumentManagementAccess::class);
+ if (! $access->full($currentActor) && ! $access->limited($currentActor) && ! $access->editorial($currentActor)) {
+ return false;
+ }
+ $current = $access->documents($currentActor)->where('id', $id)->lockForUpdate()->first();
+ if (! $current || $current->status === 'deleted' || $current->deleted_at !== null
+ || $current->sha256 !== $document->sha256 || $current->malware_scan_attempts !== $document->malware_scan_attempts
+ || $current->malware_scan_status !== $document->malware_scan_status || $current->updated_at !== $document->updated_at) {
+ return false;
+ }
+ DB::table('documents')->where('id', $id)->update(['status' => 'quarantined', 'malware_scan_status' => 'pending', 'malware_failure_reason' => null, 'updated_at' => now()]);
+ $access->audit($currentActor, 'scan_retry_requested', ['document_id' => $id, 'reference' => $job->runIdentifier(), 'previous_scan_status' => $current->malware_scan_status]);
+
+ return true;
+ });
+ $prepared = $ready;
+
+ return $ready;
+ });
+ } catch (Throwable) {
+ $outcome = 'unconfirmed';
+ try {
+ if ($prepared) {
+ DB::transaction(function () use ($id, $document): void {
+ $current = DB::table('documents')->where('id', $id)->lockForUpdate()->first();
+ if ($current && $current->deleted_at === null && $current->status !== 'deleted'
+ && $current->sha256 === $document->sha256 && $current->malware_scan_attempts === $document->malware_scan_attempts && $current->malware_scan_status === 'pending') {
+ DB::table('documents')->where('id', $id)->update(['status' => 'quarantined', 'malware_scan_status' => 'failed', 'malware_failure_reason' => 'queue_dispatch_failed', 'updated_at' => now()]);
+ }
+ });
+ }
+ } catch (Throwable) {
+ // An uncertain write remains private and needs reconciliation.
+ }
+ try {
+ Log::warning('Document scan retry dispatch requires verification.', ['reference' => $job->runIdentifier(), 'error_code' => 'scan_dispatch_unconfirmed']);
+ } catch (Throwable) {
+ }
+ }
+ });
+ });
+
+ return ['outcome' => $outcome, 'reference' => $job->runIdentifier()];
+ }
+}
diff --git a/app/Services/OpportunityImageProcessor.php b/app/Services/OpportunityImageProcessor.php
index 25fbd48d..1dc3aeb5 100644
--- a/app/Services/OpportunityImageProcessor.php
+++ b/app/Services/OpportunityImageProcessor.php
@@ -2,7 +2,6 @@
namespace App\Services;
-use App\Jobs\ScanDocumentForMalware;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
@@ -25,8 +24,9 @@ class OpportunityImageProcessor
$data = validator($input, ['etag' => 'required|string|size:64', 'version' => 'required|integer|min:1', 'reason' => 'required|string|min:20|max:1000'])->validate();
$stored = [];
$documents = [];
+ $scanContext = null;
try {
- DB::transaction(function () use ($actor, $opportunityId, $id, $data, &$stored, &$documents) {
+ DB::transaction(function () use ($actor, $opportunityId, $id, $data, &$stored, &$documents, &$scanContext) {
$o = Opportunity::withTrashed()->whereKey($opportunityId)->lockForUpdate()->firstOrFail();
app(PortalProfileAccess::class)->authorize($actor, 'edit', $o);
abort_if($o->trashed() || $o->status === 'archived', 409, 'Restaure antes de processar.');
@@ -65,6 +65,7 @@ class OpportunityImageProcessor
}
if ($reusable) {
$documents = $retry;
+ $scanContext = app(OpportunityTechnicalIncidents::class)->scanContext($actor, $o);
return; // Retry scans of the same streams, without new files, versions or audit decisions.
}
@@ -87,8 +88,8 @@ class OpportunityImageProcessor
abort_unless($encoded && is_string($webp), 500, 'Falha ao gerar WebP.');
$documentId = (string) Str::uuid();
$key = 'opportunity-resources/'.$documentId;
- abort_unless($disk->put($key, Crypt::encryptString($webp)) === true, 500, 'Falha ao guardar derivada cifrada.');
$stored[] = $key;
+ abort_unless($disk->put($key, Crypt::encryptString($webp)) === true, 500, 'Falha ao guardar derivada cifrada.');
$documents[] = $documentId;
DB::table('documents')->insert(['id' => $documentId, 'source_system' => 'opportunity-image-derivatives', 'file_name' => 'image-'.$width.'.webp', 'media_type' => 'image/webp', 'storage_key' => $key, 'storage_encryption' => 'laravel', 'sha256' => hash('sha256', $webp), 'status' => 'quarantined', 'data_classification' => 'restricted', 'size_bytes' => strlen($webp), 'uploaded_by' => $actor->id]);
$derivatives[] = ['document_id' => $documentId, 'width' => $w, 'height' => $h];
@@ -104,20 +105,15 @@ class OpportunityImageProcessor
DB::table('audit_events')->insert(['source_system' => 'opportunity-resources', 'entity_type' => 'images', 'action' => 'derivatives_prepared', 'actor_user_id' => $actor->id, 'data_classification' => 'restricted', 'before_data' => json_encode(['snapshot' => Crypt::encryptString(json_encode($image, JSON_THROW_ON_ERROR))]), 'after_data' => json_encode(['opportunity_id' => $opportunityId, 'resource_id' => $id, 'version' => $image->version + 1, 'reason' => Crypt::encryptString($data['reason']), 'snapshot' => Crypt::encryptString(json_encode(DB::table('opportunity_images')->where('id', $id)->first(), JSON_THROW_ON_ERROR))])]);
$o->management_version++;
$o->save();
+ $scanContext = app(OpportunityTechnicalIncidents::class)->scanContext($actor, $o);
});
} catch (\Throwable $error) {
- foreach ($stored as $key) {
- Storage::disk('local')->delete($key);
- }
+ app(OpportunityResourceFileCleanup::class)->afterFailure($stored, $error);
throw $error;
}
// Each new byte stream receives its own scan; no automatic clean result inherited from the original.
foreach ($documents as $documentId) {
- try {
- ScanDocumentForMalware::dispatch($documentId)->afterCommit();
- } catch (\Throwable) {
- DB::table('documents')->where('id', $documentId)->update(['malware_scan_status' => 'failed', 'malware_failure_reason' => 'queue_dispatch_failed']);
- }
+ app(OpportunityScanDispatch::class)->dispatch($documentId, $scanContext);
}
}
}
diff --git a/app/Services/OpportunityProfileWorkflow.php b/app/Services/OpportunityProfileWorkflow.php
index d6e32530..0554e0a0 100644
--- a/app/Services/OpportunityProfileWorkflow.php
+++ b/app/Services/OpportunityProfileWorkflow.php
@@ -326,6 +326,7 @@ class OpportunityProfileWorkflow
if (isset($p['business_transaction'])) {
abort_unless(in_array($p['business_transaction']['due_diligence_status'], ['data_room_ready', 'in_progress', 'completed', 'exceptions'], true), 422, 'Data room mínimo não preparado.');
}
+ $previousMaturity = $context['publication']['maturity'] ?? null;
if (isset($context['publication'])) {
$context['publication_history'][] = [...$context['publication'],
'public_maturity_before_republication' => ['level' => $record->maturity_level, 'label' => $record->maturity_label,
@@ -350,6 +351,17 @@ class OpportunityProfileWorkflow
$record->maturity_label = $maturity['maturity_label'];
$context['publication']['maturity'] = ['catalogue_version' => $maturity['maturity_catalogue_version'],
'stage' => $maturity['maturity_stage'], 'level' => $maturity['maturity_level'], 'label' => $maturity['maturity_label']];
+ } elseif (array_key_exists('maturity_stage', $p)) {
+ // An explicitly cleared optional answer must not retain an old
+ // public number or make that number look like a legacy level.
+ $record->maturity_level = null;
+ $record->maturity_label = null;
+ $context['publication']['maturity'] = ['catalogue_version' => OpportunityMaturity::VERSION,
+ 'stage' => null, 'level' => null, 'label' => null];
+ } elseif ($previousMaturity !== null) {
+ // No answer was supplied: keep the version with the retained
+ // public values, including records prepared by older editors.
+ $context['publication']['maturity'] = $previousMaturity;
}
$locations = array_values(array_filter($snapshot['resources']['locations'], fn ($location) => $location['payload']['is_primary'] ?? false));
$location = $locations[0]; // The contract requires exactly one primary location.
diff --git a/app/Services/OpportunityResourceFileCleanup.php b/app/Services/OpportunityResourceFileCleanup.php
new file mode 100644
index 00000000..c6e2ed7d
--- /dev/null
+++ b/app/Services/OpportunityResourceFileCleanup.php
@@ -0,0 +1,65 @@
+ $keys */
+ public function afterFailure(array $keys, Throwable $failure): void
+ {
+ try {
+ $uncertain = $this->causedByLostConnection($failure);
+ } catch (Throwable) {
+ $uncertain = true;
+ }
+ if ($uncertain) {
+ $this->unconfirmed();
+
+ return;
+ }
+ foreach (array_unique($keys) as $key) {
+ if (preg_match('/^opportunity-resources\/[a-f0-9-]{36}$/D', $key) !== 1) {
+ continue;
+ }
+ try {
+ $referenced = DB::transaction(function () use ($key) {
+ $visibility = DB::selectOne("SELECT row_security_active('documents'::regclass) AS active");
+ if ($visibility?->active !== false) {
+ return null;
+ }
+
+ return DB::table('documents')->where('storage_key', $key)->exists();
+ });
+ if ($referenced !== false) {
+ if ($referenced === null) {
+ $this->unconfirmed();
+ }
+
+ continue;
+ }
+ if (Storage::disk('local')->delete($key) !== true) {
+ $this->unconfirmed();
+ }
+ } catch (Throwable) {
+ $this->unconfirmed();
+ }
+ }
+ }
+
+ private function unconfirmed(): void
+ {
+ try {
+ Log::warning('Opportunity resource cleanup requires verification.', ['error_code' => 'resource_cleanup_unconfirmed']);
+ } catch (Throwable) { /* Preserve the original operation failure and retained bytes. */
+ }
+ }
+}
diff --git a/app/Services/OpportunityResources.php b/app/Services/OpportunityResources.php
index a0bcd5cf..234a6629 100644
--- a/app/Services/OpportunityResources.php
+++ b/app/Services/OpportunityResources.php
@@ -2,7 +2,6 @@
namespace App\Services;
-use App\Jobs\ScanDocumentForMalware;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Http\Exceptions\HttpResponseException;
@@ -69,13 +68,14 @@ class OpportunityResources
}
$stored = null;
$documentId = null;
+ $scanContext = null;
if ($file) {
[$stored, $documentId] = $this->store($kind, $file);
} elseif (! $id && $kind !== 'locations') {
throw ValidationException::withMessages(['file' => 'Selecione o ficheiro original.']);
}
try {
- $result = DB::transaction(function () use ($actor, $opportunityId, $kind, $table, $data, $payload, $file, $id, $stored, $documentId) {
+ $result = DB::transaction(function () use ($actor, $opportunityId, $kind, $table, $data, $payload, $file, $id, $stored, $documentId, &$scanContext) {
$opportunity = $this->lock($opportunityId, $data['etag']);
app(PortalProfileAccess::class)->authorize($actor, 'edit', $opportunity);
$record = $id ? DB::table($table)->where('id', $id)->where('opportunity_id', $opportunityId)->lockForUpdate()->first() : null;
@@ -136,22 +136,21 @@ class OpportunityResources
$this->audit($actor, $kind, $record, $after, $data['reason'], 'saved');
$opportunity->management_version++;
$opportunity->save();
+ if ($documentId !== null) {
+ $scanContext = app(OpportunityTechnicalIncidents::class)->scanContext($actor, $opportunity);
+ }
return $after;
});
} catch (\Throwable $error) {
if ($stored) {
- Storage::disk('local')->delete($stored);
+ app(OpportunityResourceFileCleanup::class)->afterFailure([$stored], $error);
}
throw $error;
}
if ($documentId) {
- try {
- ScanDocumentForMalware::dispatch($documentId)->afterCommit();
- } catch (\Throwable) {
- DB::table('documents')->where('id', $documentId)->where('malware_scan_status', '!=', 'clean')->update(['status' => 'quarantined', 'malware_scan_status' => 'failed', 'malware_failure_reason' => 'queue_dispatch_failed', 'updated_at' => now()]);
- }
+ app(OpportunityScanDispatch::class)->dispatch($documentId, $scanContext);
}
return $result;
@@ -286,8 +285,13 @@ class OpportunityResources
}
}
$id = (string) Str::uuid();
- $key = $file->storeAs('opportunity-resources', $id, 'local');
- abort_unless(is_string($key), 500, 'Falha ao guardar original privado.');
+ try {
+ $key = $file->storeAs('opportunity-resources', $id, 'local');
+ abort_unless(is_string($key), 500, 'Falha ao guardar original privado.');
+ } catch (\Throwable $error) {
+ app(OpportunityResourceFileCleanup::class)->afterFailure(['opportunity-resources/'.$id], $error);
+ throw $error;
+ }
return [$key, $id];
}
diff --git a/app/Services/OpportunityScanDispatch.php b/app/Services/OpportunityScanDispatch.php
new file mode 100644
index 00000000..86ea7de9
--- /dev/null
+++ b/app/Services/OpportunityScanDispatch.php
@@ -0,0 +1,50 @@
+|null $context */
+ public function dispatch(string $documentId, ?array $context): void
+ {
+ $job = new ScanDocumentForMalware($documentId, $context);
+ $dispatch = function () use ($documentId, $context, $job): void {
+ try {
+ // Existing uniqueness, retries and scanner are retained.
+ app(DocumentScanDelivery::class)->dispatch($job);
+ } catch (Throwable) {
+ try {
+ DB::transaction(function () use ($documentId): void {
+ $document = DB::table('documents')->where('id', $documentId)->lockForUpdate()->first();
+ if ($document && $document->deleted_at === null && $document->status !== 'deleted' && $document->malware_scan_status === 'pending') {
+ DB::table('documents')->where('id', $documentId)->update(['status' => 'quarantined', 'malware_scan_status' => 'failed', 'malware_failure_reason' => 'queue_dispatch_failed', 'updated_at' => now()]);
+ }
+ });
+ } catch (Throwable) {
+ try {
+ Log::warning('Document scan dispatch state requires verification.', ['reference' => $job->runIdentifier(), 'error_code' => 'scan_dispatch_unconfirmed']);
+ } catch (Throwable) {
+ }
+ }
+ if ($context !== null) {
+ app(OpportunityTechnicalIncidents::class)->recordScan($context, $job->runIdentifier(), 'scan_dispatch_unconfirmed');
+ }
+ }
+ };
+ try {
+ DB::afterCommit($dispatch);
+ } catch (Throwable) {
+ // Registration itself failed: never escape after a successful resource commit.
+ if ($context !== null) {
+ app(OpportunityTechnicalIncidents::class)->recordScan($context, $job->runIdentifier(), 'scan_dispatch_unconfirmed');
+ }
+ }
+ }
+}
diff --git a/app/Services/OpportunityTechnicalExecution.php b/app/Services/OpportunityTechnicalExecution.php
new file mode 100644
index 00000000..56edd130
--- /dev/null
+++ b/app/Services/OpportunityTechnicalExecution.php
@@ -0,0 +1,40 @@
+ $input
+ * @param callable():T $operation
+ * @return T */
+ public function run(User $actor, Opportunity $before, string $action, array $input, callable $operation): mixed
+ {
+ try {
+ return $operation();
+ } catch (Throwable $failure) {
+ if ($failure instanceof ValidationException || $failure instanceof AuthorizationException || $failure instanceof AuthenticationException
+ || $failure instanceof ModelNotFoundException || ($failure instanceof HttpExceptionInterface && $failure->getStatusCode() < 500)
+ || ($failure instanceof HttpResponseException && $failure->getResponse()->getStatusCode() < 500)) {
+ throw $failure;
+ }
+ $etag = is_string($input['etag'] ?? null) && preg_match('/^[a-f0-9]{64}$/D', $input['etag']) === 1 ? $input['etag'] : '';
+ $incident = $this->incidents->record($actor, $before, $action, $etag, $failure);
+ throw new OpportunityWorkflowUnavailable($incident['reference'], $incident['recorded'], $failure);
+ }
+ }
+}
diff --git a/app/Services/OpportunityTechnicalIncidents.php b/app/Services/OpportunityTechnicalIncidents.php
new file mode 100644
index 00000000..9562c0b2
--- /dev/null
+++ b/app/Services/OpportunityTechnicalIncidents.php
@@ -0,0 +1,134 @@
+|null */
+ public function scanContext(User $actor, Opportunity $record): ?array
+ {
+ $attributes = $record->getAttributes();
+ if (! array_key_exists('organization_id', $attributes) || ! array_key_exists('workflow_context', $attributes)
+ || ! in_array($record->opportunity_category, OpportunityManagement::CATEGORIES, true)) {
+ return null;
+ }
+
+ return ['opportunity_id' => $record->id, 'category' => $record->opportunity_category, 'organization_id' => $record->organization_id,
+ 'observed_version' => (int) $record->management_version, 'observed_content_revision' => $record->workflow_context['content_revision'] ?? null,
+ 'observed_state' => app(PortalProfileAccess::class)->state($record), 'reported_for_user_id' => $actor->id];
+ }
+
+ /** The queue executes as a system process; the initiating account is not impersonated.
+ * @param array $context
+ * @return array{reference:string,recorded:bool} */
+ public function recordScan(array $context, string $reference, string $errorCode): array
+ {
+ try {
+ if (! Str::isUuid($reference) || ! in_array($errorCode, self::SCAN_ERRORS, true)
+ || ! is_int($context['opportunity_id'] ?? null) || $context['opportunity_id'] <= 0
+ || ! in_array($context['category'] ?? null, OpportunityManagement::CATEGORIES, true)
+ || ! array_key_exists('organization_id', $context) || ($context['organization_id'] !== null && (! is_string($context['organization_id']) || ! Str::isUuid($context['organization_id'])))
+ || ! is_int($context['reported_for_user_id'] ?? null) || $context['reported_for_user_id'] <= 0
+ || ! is_int($context['observed_version'] ?? null) || $context['observed_version'] < 0 || ! is_string($context['observed_state'] ?? null)) {
+ throw new \LogicException('Invalid internal scan context.');
+ }
+ $metadata = ['reference' => $reference, 'opportunity_id' => $context['opportunity_id'], 'category' => $context['category'], 'organization_id' => $context['organization_id'],
+ 'operation' => 'scan_document', 'attempted_etag' => '', 'observed_version' => $context['observed_version'], 'observed_content_revision' => $context['observed_content_revision'] ?? null,
+ 'observed_state' => $context['observed_state'], 'error_code' => $errorCode, 'origin' => 'scan_system', 'reported_for_user_id' => $context['reported_for_user_id']];
+ $recorded = DB::transaction(function () use ($reference, $metadata) {
+ DB::table('audit_events')->insertOrIgnore(['id' => $reference, 'correlation_id' => $reference, 'source_system' => self::SOURCE, 'actor_user_id' => null,
+ 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $reference, 'action' => 'workflow_failed', 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['incident' => $metadata], JSON_THROW_ON_ERROR)]);
+ $event = DB::table('audit_events')->where('id', $reference)->first();
+ $old = $event ? json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR)['incident'] ?? null : null;
+
+ return $event && $event->source_system === self::SOURCE && $event->entity_type === 'opportunity-technical-incident' && $event->action === 'workflow_failed' && $event->actor_user_id === null
+ && is_array($old) && ($old['origin'] ?? null) === 'scan_system' && ($old['operation'] ?? null) === 'scan_document'
+ && ($old['opportunity_id'] ?? null) === $metadata['opportunity_id'] && ($old['organization_id'] ?? null) === $metadata['organization_id']
+ && ($old['category'] ?? null) === $metadata['category'] && ($old['reported_for_user_id'] ?? null) === $metadata['reported_for_user_id'];
+ });
+ if (! $recorded) {
+ throw new \LogicException('Scan incident reference belongs to another event.');
+ }
+
+ return ['reference' => $reference, 'recorded' => true];
+ } catch (Throwable) {
+ try {
+ Log::warning('Opportunity scan incident could not be stored.', ['reference' => $reference, 'error_code' => in_array($errorCode, self::SCAN_ERRORS, true) ? $errorCode : 'scan_worker_failed']);
+ } catch (Throwable) { /* Preserve the original worker/dispatch outcome. */
+ }
+
+ return ['reference' => $reference, 'recorded' => false];
+ }
+ }
+
+ /** Called after the business transaction has unwound.
+ * @return array{reference:string,recorded:bool} */
+ public function record(User $actor, Opportunity $before, string $action, string $attemptedEtag, Throwable $failure): array
+ {
+ $reference = (string) Str::uuid();
+ $metadata = ['reference' => $reference, 'opportunity_id' => $before->id, 'category' => $before->opportunity_category, 'organization_id' => $before->organization_id, 'operation' => $action, 'attempted_etag' => $attemptedEtag,
+ 'observed_version' => (int) $before->management_version, 'observed_content_revision' => $before->workflow_context['content_revision'] ?? null,
+ 'observed_state' => app(PortalProfileAccess::class)->state($before),
+ 'error_code' => ($failure instanceof QueryException || $failure instanceof PDOException) ? 'database_failure' : 'workflow_unavailable'];
+ try {
+ DB::transaction(fn () => DB::table('audit_events')->insert(['id' => $reference, 'correlation_id' => $reference, 'source_system' => self::SOURCE, 'actor_user_id' => $actor->id, 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $reference,
+ 'action' => 'workflow_failed', 'data_classification' => 'restricted', 'after_data' => json_encode(['incident' => $metadata], JSON_THROW_ON_ERROR)]));
+
+ return ['reference' => $reference, 'recorded' => true];
+ } catch (Throwable) {
+ // Database failure must not hide the original result or expose its message/SQL.
+ try {
+ Log::warning('Opportunity technical incident could not be stored.', ['reference' => $reference, 'error_code' => $metadata['error_code']]);
+ } catch (Throwable) { /* The response still gives the correlation reference. */
+ }
+
+ return ['reference' => $reference, 'recorded' => false];
+ }
+ }
+
+ /** Current access and actor ownership are both required, even after revocation.
+ * @return list */
+ public function recent(User $actor, Opportunity $record): array
+ {
+ app(PortalProfileAccess::class)->authorize($actor, 'view', $record);
+ $result = [];
+ foreach (DB::table('audit_events')->where('source_system', self::SOURCE)->where('entity_type', 'opportunity-technical-incident')->whereRaw("after_data->'incident'->>'opportunity_id' = ?", [(string) $record->id])
+ ->whereRaw("COALESCE(after_data->'incident'->>'organization_id','') = ?", [$record->organization_id ?? ''])
+ ->whereRaw("COALESCE(after_data->'incident'->>'category','') = ?", [$record->opportunity_category ?? ''])
+ ->where(function ($query) use ($actor) {
+ $query->where('actor_user_id', $actor->id)->orWhere(function ($system) use ($actor) {
+ $system->whereNull('actor_user_id')->whereRaw("after_data->'incident'->>'origin' = 'scan_system'")->whereRaw("after_data->'incident'->>'operation' = 'scan_document'")
+ ->whereRaw("after_data->'incident'->>'reported_for_user_id' = ?", [(string) $actor->id]);
+ });
+ })->where('action', 'workflow_failed')->orderByDesc('occurred_at')->orderByDesc('id')->limit(10)->get(['id', 'occurred_at', 'after_data']) as $event) {
+ $data = json_decode($event->after_data, true)['incident'] ?? null;
+ if (! is_array($data) || ($data['reference'] ?? null) !== $event->id || ! in_array($data['operation'] ?? null, self::OPERATIONS, true)
+ || ! is_int($data['observed_version'] ?? null) || ! in_array($data['error_code'] ?? null, ['database_failure', 'workflow_unavailable', ...self::SCAN_ERRORS], true) || ! is_string($event->occurred_at)) {
+ continue;
+ }
+ $state = app(TechnicalIncidentHandling::class)->summaryFor($event->id);
+ $result[] = ['reference' => $event->id, 'operation' => $data['operation'], 'version' => $data['observed_version'], 'occurred_at' => $event->occurred_at, 'error_code' => $data['error_code'],
+ 'handling' => $state === null ? null : ['version' => $state['version'], 'status' => $state['status'], 'updated_at' => $state['updated_at']]];
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Services/OpportunityTechnicalSupport.php b/app/Services/OpportunityTechnicalSupport.php
new file mode 100644
index 00000000..a634c45e
--- /dev/null
+++ b/app/Services/OpportunityTechnicalSupport.php
@@ -0,0 +1,128 @@
+inspect()['installed'];
+ }
+
+ public function allows(User $actor): bool
+ {
+ $access = app(PortalProfileAccess::class);
+
+ return $this->installed() && $access->available() && ! $access->has($actor, 'auditor') && $access->has($actor, 'technical_support');
+ }
+
+ /** @return array */
+ public function queue(User $actor, string $status = 'all', bool $unread = false): array
+ {
+ abort_unless(in_array($status, ['all', 'open', 'in_progress', 'resolved'], true), 422);
+ $query = $this->query($actor);
+ if ($unread) {
+ $query->whereNotExists($this->seenQuery($actor));
+ }
+ if ($status !== 'all') {
+ $query->whereRaw("COALESCE((SELECT treatment.after_data->'handling'->>'status' FROM audit_events treatment WHERE treatment.source_system='portal-opportunity-support' AND treatment.entity_type='opportunity-technical-incident' AND treatment.entity_id=event.id AND treatment.action='incident_handled' ORDER BY (treatment.after_data->'handling'->'version') DESC NULLS FIRST,treatment.id DESC LIMIT 1),'open') = ?", [$status]);
+ }
+
+ return $query->select(['event.id', 'event.occurred_at', 'event.after_data'])->selectSub($this->seenQuery($actor)->select('notice.occurred_at')->limit(1), 'consulted_at')
+ ->orderByDesc('event.occurred_at')->orderByDesc('event.id')->paginate(20)->withQueryString()->through(function ($event) {
+ $data = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR)['incident'];
+
+ return ['reference' => $event->id, 'occurred_at' => $event->occurred_at, 'operation' => $data['operation'], 'version' => $data['observed_version'], 'error_code' => $data['error_code'],
+ 'handling' => app(TechnicalIncidentHandling::class)->summaryFor($event->id), 'details_url' => '/suporte-tecnico/incidentes/'.$event->id, 'unread' => $event->consulted_at === null];
+ })->toArray();
+ }
+
+ /** Optional navigation projection: failure must not block unrelated portal work. */
+ public function unreadCount(User $actor): ?int
+ {
+ try {
+ return DB::transaction(fn () => $this->query($actor)->whereNotExists($this->seenQuery($actor))->count());
+ } catch (QueryException) {
+ return null;
+ }
+ }
+
+ private function seenQuery(User $actor): Builder
+ {
+ return DB::table('audit_events as notice')->where('notice.source_system', self::NOTICE_SOURCE)->where('notice.entity_type', 'opportunity-technical-incident')
+ ->where('notice.action', 'incident_consulted')->where('notice.actor_user_id', $actor->id)->whereColumn('notice.entity_id', 'event.id');
+ }
+
+ /** @return array{unread:bool} */
+ public function notice(User $actor, string $reference): array
+ {
+ $root = $this->query($actor)->where('event.id', $reference)->select('event.id')->selectSub($this->seenQuery($actor)->select('notice.occurred_at')->limit(1), 'consulted_at')->first() ?? abort(404);
+
+ return ['unread' => $root->consulted_at === null];
+ }
+
+ /** A per-actor, commutative acknowledgement; never a treatment or business transition.
+ * @return array{reference:string,actor_id:int,read:bool,read_at:string} */
+ public function markConsulted(User $actor, string $reference): array
+ {
+ return DB::transaction(function () use ($actor, $reference) {
+ $this->root($actor, $reference, true);
+ $query = DB::table('audit_events')->where('source_system', self::NOTICE_SOURCE)->where('entity_type', 'opportunity-technical-incident')->where('entity_id', $reference)
+ ->where('action', 'incident_consulted')->where('actor_user_id', $actor->id);
+ $seen = $query->first(['occurred_at']);
+ if ($seen === null) {
+ $id = (string) Str::uuid();
+ DB::table('audit_events')->insert(['id' => $id, 'correlation_id' => $reference, 'source_system' => self::NOTICE_SOURCE, 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $reference,
+ 'actor_user_id' => $actor->id, 'action' => 'incident_consulted', 'data_classification' => 'restricted', 'after_data' => json_encode(['consulted' => true], JSON_THROW_ON_ERROR)]);
+ $seen = $query->first(['occurred_at']);
+ }
+
+ $readAt = $seen?->occurred_at;
+ abort_unless(is_string($readAt), 503, 'A confirmação da consulta não ficou disponível; pode repetir esta acção.');
+
+ return ['reference' => $reference, 'actor_id' => $actor->id, 'read' => true, 'read_at' => $readAt];
+ });
+ }
+
+ public function root(User $actor, string $reference, bool $lock = false): \stdClass
+ {
+ $query = $this->query($actor)->where('event.id', $reference)->select(['event.id', 'event.occurred_at', 'event.after_data']);
+ if ($lock) {
+ $query->lock('FOR UPDATE OF event');
+ }
+
+ return $query->first() ?? abort(404);
+ }
+
+ private function query(User $actor): Builder
+ {
+ abort_unless($this->allows($actor), 403);
+ $grants = app(PortalProfileAccess::class)->grants($actor, 'technical_support');
+
+ return DB::table('audit_events as event')->join('opportunities as opportunity', DB::raw('opportunity.id::text'), '=', DB::raw("event.after_data->'incident'->>'opportunity_id'"))
+ ->where('event.source_system', 'portal-opportunity-incident')->where('event.entity_type', 'opportunity-technical-incident')->where('event.action', 'workflow_failed')->whereNull('opportunity.deleted_at')
+ ->whereRaw("opportunity.opportunity_category = event.after_data->'incident'->>'category'")
+ ->whereRaw("COALESCE(opportunity.organization_id::text,'') = COALESCE(event.after_data->'incident'->>'organization_id','')")
+ ->where(function (Builder $scopes) use ($grants) {
+ $scopes->whereRaw('FALSE');
+ foreach ($grants as $grant) {
+ $scopes->orWhere(function (Builder $scope) use ($grant) {
+ $scope->whereIn('opportunity.opportunity_category', json_decode($grant->opportunity_types, true, 512, JSON_THROW_ON_ERROR));
+ if ($grant->organization_id !== null) {
+ $scope->where('opportunity.organization_id', $grant->organization_id);
+ }
+ });
+ }
+ });
+
+ }
+}
diff --git a/app/Services/OpportunityWorkflowExecution.php b/app/Services/OpportunityWorkflowExecution.php
new file mode 100644
index 00000000..e770d048
--- /dev/null
+++ b/app/Services/OpportunityWorkflowExecution.php
@@ -0,0 +1,28 @@
+ $input */
+ public function transition(User $actor, int $id, array $input): Opportunity
+ {
+ $action = $input['action'] ?? null;
+ if (! in_array($action, ['submit', 'publish'], true)) {
+ return $this->workflow->transition($actor, $id, $input);
+ }
+ $record = Opportunity::withTrashed()->findOrFail($id);
+ app(PortalProfileAccess::class)->authorize($actor, 'view', $record);
+ if (! in_array($action, $this->workflow->actions($actor, $record), true)) {
+ return $this->workflow->transition($actor, $id, $input);
+ }
+
+ return $this->execution->run($actor, $record, $action, $input, fn () => $this->workflow->transition($actor, $id, $input));
+ }
+}
diff --git a/app/Services/OrganizationCountry.php b/app/Services/OrganizationCountry.php
index 3993b06f..ac9a5c37 100644
--- a/app/Services/OrganizationCountry.php
+++ b/app/Services/OrganizationCountry.php
@@ -48,7 +48,7 @@ class OrganizationCountry
public function save(User $actor, string $id, array $data): array
{
$this->authorize($actor, $id, true);
- $data = Validator::make($data, ['version' => 'required|integer|min:1',
+ $data = Validator::make($data, ['version' => 'required|integer|min:1', 'operation_key' => ['sometimes', 'required', 'uuid'],
'country' => ['required', 'string', app(CountryCatalogue::class)->rule()],
'source_reference' => 'required|string|min:5|max:2000'], [
'country.required' => 'Selecione o país de constituição da organização.',
@@ -57,9 +57,17 @@ class OrganizationCountry
])->validate();
return DB::transaction(function () use ($actor, $id, $data) {
+ DB::table('users')->where('id', $actor->id)->lockForUpdate()->firstOrFail();
DB::table('memberships')->where('organization_id', $id)->where('user_id', $actor->id)->lockForUpdate()->get();
$this->authorize($actor, $id, true);
$row = DB::table('organizations')->where('id', $id)->lockForUpdate()->firstOrFail();
+ $this->authorize($actor, $id, true);
+ $commands = app(InvestmentProfileCommands::class);
+ $command = ['kind' => 'organization_country', 'target_id' => $id, 'version' => (int) $data['version'], 'payload' => ['country' => $data['country'], 'source_reference' => $data['source_reference']]];
+ $replay = $commands->replay($actor, $data['operation_key'] ?? null, $command);
+ if ($replay !== null) {
+ return ['version' => $replay['version'], 'country' => $data['country']];
+ }
abort_unless((int) $row->version_no === (int) $data['version'], 409, 'Organização alterada. Recarregue.');
$provenance = ['kind' => 'representative_declaration', 'reference' => $data['source_reference'],
'actor_id' => $actor->id, 'at' => now()->toIso8601String(), 'source_system' => $row->source_system,
@@ -72,6 +80,8 @@ class OrganizationCountry
'after_data' => json_encode(['organization_id' => $id, 'version' => $row->version_no + 1,
'snapshot' => Crypt::encryptString(json_encode(['country' => $data['country'], 'provenance' => $provenance], JSON_THROW_ON_ERROR))])]);
+ $commands->record($actor, $data['operation_key'] ?? null, $command, ['version' => $row->version_no + 1]);
+
return ['version' => $row->version_no + 1, 'country' => $data['country']];
});
}
@@ -79,11 +89,23 @@ class OrganizationCountry
/** @return array */
public function snapshot(User $actor, string $id): array
{
+ $snapshot = $this->readableSnapshot($actor, $id);
+ abort_unless($snapshot['country'] !== null, 422, 'País de constituição não informado no cadastro mestre.');
+
+ return $snapshot;
+ }
+
+ /** Caller owns a transaction; authorize again after waiting for the source lock.
+ * @return array */
+ public function readableSnapshot(User $actor, string $id): array
+ {
+ $this->authorize($actor, $id);
+ DB::table('memberships')->where('organization_id', $id)->where('user_id', $actor->id)->lockForUpdate()->get();
$this->authorize($actor, $id);
$org = DB::table('organizations')->where('id', $id)->lockForUpdate()->firstOrFail();
- abort_unless($org->incorporation_country_code !== null, 422, 'País de constituição não informado no cadastro mestre.');
+ $this->authorize($actor, $id);
- return ['organization_id' => $id, 'organization_version' => $org->version_no, 'country' => $org->incorporation_country_code,
+ return ['organization_id' => $org->id, 'organization_version' => $org->version_no, 'country' => $org->incorporation_country_code,
'provenance' => json_decode($org->incorporation_country_provenance, true), 'reused_at' => now()->toIso8601String(), 'reused_by' => $actor->id];
}
}
diff --git a/app/Services/PartnershipAgreementHistory.php b/app/Services/PartnershipAgreementHistory.php
new file mode 100644
index 00000000..dcb0f596
--- /dev/null
+++ b/app/Services/PartnershipAgreementHistory.php
@@ -0,0 +1,141 @@
+ */
+ private array $people = [];
+
+ public function __construct(private PartnershipAgreementProjection $projection) {}
+
+ /** @return array */
+ public function page(User $actor, int $id, ?string $before = null): array
+ {
+ $context = app(PartnershipExchange::class)->room($actor, $id);
+ $boundary = $before === null ? null : $this->decode($before, $actor, $context);
+ $events = DB::table('partnership_events')->where('partnership_id', $context['partnership']->id)->where('event_type', 'partnership_agreement.changed.v1')
+ ->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $id])
+ ->when($boundary, fn ($q) => $q->where('aggregate_version', '<', $boundary))->orderByDesc('aggregate_version')->limit(11)->get(['aggregate_version', 'actor_id', 'occurred_at', 'payload']);
+ $page = $events->take(10);
+ $base = '/parcerias/salas/'.$id.'/historico';
+ $last = $page->last();
+ $next = $events->count() > 10 && $last ? $base.'?before='.rawurlencode(Crypt::encryptString(json_encode(['purpose' => 'agreement', 'actor' => $actor->id, 'room' => $id, 'interest' => (int) $context['interest']->id, 'partnership' => (int) $context['partnership']->id, 'before' => (int) $last->aggregate_version], JSON_THROW_ON_ERROR))) : null;
+
+ return ['room_id' => $id, 'entries' => $page->map(fn ($event) => $this->entry($event, $actor, $context))->all(), 'first_url' => $base, 'next_url' => $next, 'older_page' => $before !== null, 'room_href' => '/parcerias/salas/'.$id, 'dashboard_href' => '/parcerias/painel'];
+ }
+
+ /** @param array{partnership:stdClass,interest:stdClass,room:stdClass} $context */
+ private function decode(string $token, User $actor, array $context): int
+ {
+ try {
+ $value = json_decode(Crypt::decryptString($token), true, 512, JSON_THROW_ON_ERROR);
+ } catch (DecryptException|\JsonException) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não é válida. Volte ao início do histórico.']);
+ }
+ if (! is_array($value) || ($value['purpose'] ?? null) !== 'agreement' || ($value['actor'] ?? null) !== $actor->id || ($value['room'] ?? null) !== (int) $context['room']->id || ($value['interest'] ?? null) !== (int) $context['interest']->id || ($value['partnership'] ?? null) !== (int) $context['partnership']->id || ! $this->positive($value['before'] ?? null)) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não pertence a esta sala e conta. Volte ao início do histórico.']);
+ }
+
+ return $value['before'];
+ }
+
+ /** @param array{partnership:stdClass,interest:stdClass,room:stdClass} $context
+ * @return array
+ */
+ private function entry(stdClass $event, User $actor, array $context): array
+ {
+ $envelope = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR);
+ $data = is_array($envelope) && is_array($envelope['payload'] ?? null) ? $envelope['payload'] : [];
+ $scope = $data['_notification_context'] ?? null;
+ $proponent = is_array($scope) ? $this->scope($scope['partnership'] ?? null) : null;
+ $candidate = is_array($scope) ? $this->scope($scope['interest'] ?? null) : null;
+ $known = is_array($scope) && ($scope['version'] ?? null) === 1 && ($scope['room_id'] ?? null) === (int) $context['room']->id && $proponent !== null && $candidate !== null && ($proponent['id'] ?? null) === (int) $context['partnership']->id && ($candidate['id'] ?? null) === (int) $context['interest']->id;
+ $exchange = app(PartnershipExchange::class);
+ $visible = $known && ($exchange->owns($actor, (object) $proponent, false) || $exchange->owns($actor, (object) $candidate, false));
+ $version = $this->positive($data['version'] ?? null) ? $data['version'] : null;
+ $unavailable = ['availability' => $known ? 'restricted' : 'scope_unknown'];
+
+ return ['version' => $version, 'restricted' => ! $visible,
+ 'action' => $visible && in_array($data['action'] ?? null, ['record', 'confirm', 'start', 'complete', 'cancel', 'renew'], true) ? $data['action'] : null,
+ 'actor_name' => $visible ? $this->person((int) $event->actor_id) : null, 'occurred_at' => $visible ? $event->occurred_at : null,
+ 'reason' => $visible && is_string($data['reason'] ?? null) ? $data['reason'] : null,
+ 'confirmation_party' => $visible && in_array($data['confirmation_party'] ?? null, ['proponent', 'candidate'], true) ? $data['confirmation_party'] : null,
+ 'partnership_version' => $visible && $this->positive($data['partnership_version'] ?? null) ? $data['partnership_version'] : null,
+ 'interest_version' => $visible && $this->positive($data['interest_version'] ?? null) ? $data['interest_version'] : null,
+ 'previous' => $visible ? $this->snapshot($data['previous'] ?? null, $actor, (int) $context['room']->id) : $unavailable,
+ 'after' => $visible ? $this->snapshot($data['applied'] ?? null, $actor, (int) $context['room']->id) : $unavailable];
+ }
+
+ /** @return array */
+ private function snapshot(mixed $value, User $actor, int $id): array
+ {
+ if ($value === null) {
+ return ['availability' => 'not_recorded'];
+ }
+ if (! is_array($value) || ($value['id'] ?? null) !== $id || ! $this->positive($value['version'] ?? null) || ! is_string($value['status'] ?? null)) {
+ return ['availability' => 'scope_unknown'];
+ }
+ $view = ['availability' => 'available', 'version' => $value['version'], 'status' => $value['status'], 'instrument_availability' => 'not_recorded'];
+ if (! array_key_exists('agreement', $value)) {
+ return $view;
+ }
+ $instrument = $value['agreement'];
+ if ($instrument === null) {
+ return $view;
+ }
+ if (! is_array($instrument)) {
+ return [...$view, 'instrument_availability' => 'malformed'];
+ }
+ $scope = $instrument['recorded_context'] ?? null;
+ $proponent = is_array($scope) ? $this->scope($scope['proponent'] ?? null) : null;
+ $candidate = is_array($scope) ? $this->scope($scope['candidate'] ?? null) : null;
+ if ($proponent === null || $candidate === null || ! $this->positive($scope['partnership_version'] ?? null) || ! $this->positive($scope['interest_version'] ?? null)) {
+ return [...$view, 'instrument_availability' => 'scope_unknown'];
+ }
+ $exchange = app(PartnershipExchange::class);
+ if (! $exchange->owns($actor, (object) $proponent, false) && ! $exchange->owns($actor, (object) $candidate, false)) {
+ return [...$view, 'instrument_availability' => 'restricted'];
+ }
+ $fields = $this->projection->fields($instrument, true);
+
+ return [...$view, 'instrument_availability' => 'available', 'instrument' => $fields, 'instrument_partnership_version' => $scope['partnership_version'], 'instrument_interest_version' => $scope['interest_version']];
+ }
+
+ /** @return array{id?:int,user_id:int,organization_id:string|null}|null */
+ private function scope(mixed $value): ?array
+ {
+ if (! is_array($value) || ! $this->positive($value['user_id'] ?? null) || ! array_key_exists('organization_id', $value) || ! ($value['organization_id'] === null || is_string($value['organization_id']) && Str::isUuid($value['organization_id']))) {
+ return null;
+ }
+ $scope = ['user_id' => $value['user_id'], 'organization_id' => $value['organization_id']];
+ if ($this->positive($value['id'] ?? null)) {
+ $scope['id'] = $value['id'];
+ }
+
+ return $scope;
+ }
+
+ /** @phpstan-assert-if-true positive-int $value */
+ private function positive(mixed $value): bool
+ {
+ return is_int($value) && $value > 0;
+ }
+
+ private function person(int $id): ?string
+ {
+ if (! array_key_exists($id, $this->people)) {
+ $this->people[$id] = DB::table('users')->where('id', $id)->value('name');
+ }
+
+ return $this->people[$id];
+ }
+}
diff --git a/app/Services/PartnershipAgreementProjection.php b/app/Services/PartnershipAgreementProjection.php
new file mode 100644
index 00000000..6c3fcb90
--- /dev/null
+++ b/app/Services/PartnershipAgreementProjection.php
@@ -0,0 +1,84 @@
+ */
+ private array $people = [];
+
+ public function current(?string $json): stdClass|string|null
+ {
+ $value = $json === null ? null : json_decode($json, false, 512, JSON_THROW_ON_ERROR);
+ if ($value === null) {
+ return null;
+ }
+ if (! $value instanceof stdClass) {
+ return 'unrecognized';
+ }
+
+ return (object) $this->fields((array) $value);
+ }
+
+ /** @param array $instrument
+ * @return array
+ */
+ public function fields(array $instrument, bool $names = false): array
+ {
+ $fields = [];
+ foreach (['title', 'terms', 'legal_signature_status'] as $key) {
+ if (is_string($instrument[$key] ?? null)) {
+ $fields[$key] = $instrument[$key];
+ }
+ }
+ if (array_key_exists('confirmations', $instrument)) {
+ $fields['confirmations'] = $this->confirmations($instrument['confirmations'], $names);
+ }
+
+ return $fields;
+ }
+
+ /** @return array|stdClass|string|null */
+ private function confirmations(mixed $value, bool $names): array|stdClass|string|null
+ {
+ if ($value === null) {
+ return null;
+ }
+ if ($value instanceof stdClass) {
+ $value = (array) $value;
+ }
+ if (! is_array($value) || $value !== [] && array_is_list($value)) {
+ return 'unrecognized';
+ }
+ $result = [];
+ foreach (['proponent', 'candidate'] as $party) {
+ if (! array_key_exists($party, $value)) {
+ continue;
+ }
+ $stamp = $value[$party] instanceof stdClass ? (array) $value[$party] : (is_array($value[$party]) ? $value[$party] : []);
+ $id = is_int($stamp['actor_id'] ?? null) && $stamp['actor_id'] > 0 ? $stamp['actor_id'] : null;
+ $result[$party] = ['actor_id' => $id, 'date' => is_string($stamp['date'] ?? null) ? $stamp['date'] : null, 'reason' => is_string($stamp['reason'] ?? null) ? $stamp['reason'] : null];
+ if ($names) {
+ $result[$party]['actor_name'] = $id ? $this->person($id) : null;
+ }
+ }
+ if (array_diff(array_keys($value), ['proponent', 'candidate']) !== []) {
+ $result['_unrecognized_references'] = true;
+ }
+
+ return $result === [] ? (object) [] : $result;
+ }
+
+ private function person(int $id): ?string
+ {
+ if (! array_key_exists($id, $this->people)) {
+ $this->people[$id] = DB::table('users')->where('id', $id)->value('name');
+ }
+
+ return $this->people[$id];
+ }
+}
diff --git a/app/Services/PartnershipAgreements.php b/app/Services/PartnershipAgreements.php
new file mode 100644
index 00000000..84607276
--- /dev/null
+++ b/app/Services/PartnershipAgreements.php
@@ -0,0 +1,140 @@
+owns($actor, $context['partnership']) ? 'proponent' : ($exchange->owns($actor, $context['interest']) ? 'candidate' : null);
+ }
+
+ /** @param array{partnership:stdClass,interest:stdClass,room:stdClass} $context
+ * @return list
+ */
+ public function commands(User $actor, array $context): array
+ {
+ if ($this->party($actor, $context) === null) {
+ return [];
+ }
+ $rows = DB::table('partnership_events')->where('partnership_id', $context['partnership']->id)->where('actor_id', $actor->id)->where('event_type', 'partnership_agreement.changed.v1')->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $context['room']->id])->whereRaw("payload->'payload'->>'client_key' IS NOT NULL")->orderBy('aggregate_version')->selectRaw("payload->'payload'->>'client_key' AS key,payload->'payload'->>'action' AS action,payload->'payload'->'version' AS version,payload->'payload'->>'status' AS status,payload->'payload'->>'confirmation_party' AS party")->get();
+ $commands = [];
+ foreach ($rows as $row) {
+ $version = is_string($row->version) ? json_decode($row->version, true, 512, JSON_THROW_ON_ERROR) : $row->version;
+ if (is_string($row->key) && Str::isUuid($row->key) && in_array($row->action, self::ACTIONS, true) && is_int($version) && $version > 0 && is_string($row->status)) {
+ $commands[] = ['key' => $row->key, 'action' => $row->action, 'version' => $version, 'status' => $row->status, 'party' => in_array($row->party, ['proponent', 'candidate'], true) ? $row->party : null];
+ }
+ }
+
+ return $commands;
+ }
+
+ /** @param array $input
+ * @return array{recorded:bool,replayed:bool,version:int,status:string,saved_version:int}
+ */
+ public function act(User $actor, int $id, array $input): array
+ {
+ $data = Validator::make($input, ['client_key' => 'nullable|uuid', 'version' => 'required|integer|min:1', 'partnership_version' => 'nullable|integer|min:1', 'interest_version' => 'nullable|integer|min:1', 'action' => 'required|in:'.implode(',', self::ACTIONS), 'title' => 'required_if:action,record|nullable|string|max:200', 'terms' => 'required_if:action,record|nullable|string|max:20000', 'reason' => 'required|string|max:2000'])->validate();
+ $key = is_string($data['client_key'] ?? null) ? strtolower($data['client_key']) : null;
+ unset($data['client_key']);
+ if ($data['action'] !== 'record') {
+ $data = Arr::except($data, ['title', 'terms']);
+ }
+ $hash = hash('sha256', json_encode(Arr::sortRecursive($data), JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $id, $data, $key, $hash) {
+ $exchange = app(PartnershipExchange::class);
+ $context = $exchange->room($actor, $id);
+ $record = $exchange->find($context['partnership']->id, true);
+ $interest = DB::table('partnership_interests')->where('id', $context['interest']->id)->lockForUpdate()->first();
+ $room = DB::table('partnership_rooms')->where('id', $id)->lockForUpdate()->first();
+ abort_unless($interest && $room && (int) $interest->partnership_id === (int) $record->id && (int) $room->interest_id === (int) $interest->id, 409, 'O contexto da sala foi alterado.');
+ $context = ['partnership' => $record, 'interest' => $interest, 'room' => $room];
+ $party = $this->party($actor, $context);
+ abort_unless($party !== null, 403, 'A representação actual não permite alterar o acordo.');
+ if ($key !== null) {
+ $event = DB::table('partnership_events')->where('partnership_id', $record->id)->where('actor_id', $actor->id)->where('event_type', 'partnership_agreement.changed.v1')->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $id])->whereRaw("payload->'payload'->>'client_key' = ?", [$key])->selectRaw("payload->'payload'->>'command_hash' AS hash,payload->'payload'->'version' AS version")->first();
+ if ($event) {
+ abort_unless($event->hash === $hash, 409, 'Chave já utilizada com outro conteúdo.');
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ abort_unless(is_int($version) && $version > 0, 409, 'Versão anterior não identificada.');
+
+ return ['recorded' => true, 'replayed' => true, 'version' => (int) $room->version, 'status' => $room->status, 'saved_version' => $version];
+ }
+ }
+ abort_unless((int) $room->version === (int) $data['version'], 409, 'Acordo alterado. Compare antes de continuar.');
+ foreach (['partnership_version' => $record->version, 'interest_version' => $interest->version] as $field => $version) {
+ abort_if(isset($data[$field]) && (int) $data[$field] !== (int) $version, 409, 'A proposta ou candidatura foi alterada. Reveja o contexto antes de decidir.');
+ }
+ $agreement = $room->agreement ? json_decode($room->agreement, true, 512, JSON_THROW_ON_ERROR) : null;
+ abort_unless($agreement === null || is_array($agreement), 409, 'O instrumento guardado não tem uma estrutura reconhecida.');
+ $status = $room->status;
+ $before = $this->snapshot($room, $agreement);
+ $action = $data['action'];
+ if ($action === 'record') {
+ abort_unless(in_array($status, ['negotiation', 'agreement_recorded'], true), 409);
+ $previous = $agreement['previous_versions'] ?? [];
+ abort_unless(is_array($previous), 409, 'O histórico do instrumento não tem uma estrutura reconhecida.');
+ if ($agreement) {
+ $previous[] = Arr::except($agreement, ['previous_versions']);
+ }
+ $agreement = ['title' => $data['title'], 'terms' => $data['terms'], 'recorded_by' => $actor->id, 'recorded_at' => now()->toIso8601String(), 'confirmations' => [], 'parties' => [$record->user_id, $interest->user_id], 'legal_signature_status' => 'not_verified', 'previous_versions' => $previous,
+ 'recorded_context' => ['partnership_version' => (int) $record->version, 'interest_version' => (int) $interest->version, 'proponent' => ['user_id' => (int) $record->user_id, 'organization_id' => $record->organization_id], 'candidate' => ['user_id' => (int) $interest->user_id, 'organization_id' => $interest->organization_id]]];
+ $status = 'agreement_recorded';
+ } elseif ($action === 'confirm') {
+ abort_unless($status === 'agreement_recorded' && $agreement, 409);
+ abort_unless(! isset($agreement['confirmations']) || is_array($agreement['confirmations']), 409, 'As confirmações guardadas não têm uma estrutura reconhecida.');
+ $agreement['confirmations'][$party] = ['actor_id' => $actor->id, 'date' => now()->toIso8601String(), 'reason' => $data['reason']];
+ if ($this->confirmation($agreement['confirmations']['proponent'] ?? null) && $this->confirmation($agreement['confirmations']['candidate'] ?? null)) {
+ $status = 'agreed';
+ }
+ } else {
+ $allowed = ['start' => ['agreed'], 'complete' => ['execution'], 'cancel' => ['negotiation', 'agreement_recorded', 'agreed', 'execution'], 'renew' => ['agreed', 'execution']];
+ abort_unless(in_array($status, $allowed[$action] ?? [], true), 409);
+ if ($action === 'complete') {
+ abort_if(DB::table('partnership_milestones')->where('room_id', $id)->where('status', '!=', 'completed')->exists(), 409, 'Existem marcos pendentes.');
+ }
+ $status = ['start' => 'execution', 'complete' => 'closed', 'cancel' => 'cancelled', 'renew' => 'negotiation'][$action];
+ if ($action === 'renew') {
+ abort_unless(is_array($agreement) && is_array($agreement['previous_versions'] ?? []), 409, 'O instrumento ou o seu histórico não tem uma estrutura reconhecida.');
+ $agreement['previous_versions'][] = Arr::except($agreement, ['previous_versions']);
+ $agreement['confirmations'] = [];
+ }
+ }
+ DB::table('partnership_rooms')->where('id', $id)->update(['agreement' => $agreement ? json_encode($agreement, JSON_THROW_ON_ERROR) : null, 'status' => $status, 'version' => $room->version + 1, 'updated_at' => now()]);
+ $saved = DB::table('partnership_rooms')->where('id', $id)->first();
+ $metadata = ['room_id' => $id, 'status' => $status, 'version' => (int) $saved->version, 'reason' => $data['reason'], 'action' => $action, 'confirmation_party' => $action === 'confirm' ? $party : null, 'partnership_version' => (int) $record->version, 'interest_version' => (int) $interest->version, 'previous' => $before, 'applied' => $this->snapshot($saved, $agreement)];
+ if ($key !== null) {
+ $metadata += ['client_key' => $key, 'command_hash' => $hash];
+ }
+ $exchange->event($record, $actor, 'partnership_agreement.changed.v1', $metadata, 'Acordo: '.$status, [$record->user_id, $interest->user_id]);
+
+ return ['recorded' => true, 'replayed' => false, 'version' => (int) $saved->version, 'status' => $status, 'saved_version' => (int) $saved->version];
+ });
+ }
+
+ private function confirmation(mixed $value): bool
+ {
+ return is_array($value) && is_int($value['actor_id'] ?? null) && $value['actor_id'] > 0;
+ }
+
+ /** @param array|null $agreement
+ * @return array
+ */
+ private function snapshot(stdClass $room, ?array $agreement): array
+ {
+ return ['id' => (int) $room->id, 'version' => (int) $room->version, 'status' => $room->status, 'agreement' => $agreement];
+ }
+}
diff --git a/app/Services/PartnershipCandidacies.php b/app/Services/PartnershipCandidacies.php
new file mode 100644
index 00000000..dc9fad2f
--- /dev/null
+++ b/app/Services/PartnershipCandidacies.php
@@ -0,0 +1,188 @@
+status === 'published' && (! $record->deadline || $record->deadline >= today()->toDateString());
+ }
+
+ /** @return array> */
+ public function commands(User $actor, int $partnership): array
+ {
+ $commands = [];
+ $events = DB::table('partnership_events')->where('partnership_id', $partnership)->where('actor_id', $actor->id)
+ ->whereIn('event_type', ['partnership_interest.submitted.v1', 'partnership_interest.changed.v1'])->whereRaw("payload->'payload'->>'client_key' IS NOT NULL")->get(['payload', 'event_type']);
+ foreach ($events as $event) {
+ $payload = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ $commands[(int) $payload['interest_id']][] = ['key' => $payload['client_key'], 'version' => (int) $payload['interest_version'], 'action' => $event->event_type === 'partnership_interest.submitted.v1' ? 'submit' : $payload['action']];
+ }
+
+ return $commands;
+ }
+
+ /** @param array $data */
+ public function submit(User $actor, int $id, array $data): stdClass
+ {
+ $data = Validator::make($data, ['client_key' => ['nullable', 'uuid'], 'interest_id' => ['nullable', 'integer', 'min:1'], 'partnership_version' => ['nullable', 'integer', 'min:1'], 'version' => ['nullable', 'integer', 'min:1'], 'organization_id' => ['nullable', 'uuid'], 'proposal' => ['required', 'string', 'max:15000'],
+ 'payload' => ['array:'.implode(',', self::PAYLOAD)], 'payload.consent' => ['accepted'], 'payload.capacity' => ['nullable', 'string', 'max:5000'], 'payload.availability' => ['nullable', 'string', 'max:1000'], 'payload.contribution' => ['nullable', 'string', 'max:5000'], 'payload.conflicts' => ['nullable', 'string', 'max:5000'], 'payload.sector_id' => ['nullable', 'integer'], 'payload.territory_id' => ['nullable', 'uuid']])->validate();
+ if (isset($data['client_key'])) {
+ $data['client_key'] = strtolower($data['client_key']);
+ }
+ foreach (['interest_id', 'partnership_version', 'version'] as $integer) {
+ if (isset($data[$integer])) {
+ $data[$integer] = (int) $data[$integer];
+ }
+ }
+ $hash = $this->hash(Arr::except($data, 'client_key'));
+
+ return DB::transaction(function () use ($actor, $id, $data, $hash) {
+ $exchange = app(PartnershipExchange::class);
+ $record = $exchange->find($id, true);
+ $replay = $this->replay($actor, $record, 'partnership_interest.submitted.v1', $data['client_key'] ?? null, $hash);
+ if ($replay) {
+ abort_unless($exchange->owns($actor, $replay), 403);
+
+ return $replay;
+ }
+ if (isset($data['interest_id'])) {
+ $existing = DB::table('partnership_interests')->where('partnership_id', $id)->where('id', $data['interest_id'])->lockForUpdate()->first();
+ abort_unless($existing !== null, 404, 'A candidatura não pertence a esta parceria.');
+ } else {
+ $matches = DB::table('partnership_interests')->where('partnership_id', $id)->where(fn ($q) => $q->where('user_id', $actor->id)->when($data['organization_id'] ?? null, fn ($org) => $org->orWhere('organization_id', $data['organization_id'])))->orderBy('id')->lockForUpdate()->get();
+ abort_if($matches->count() > 1, 409, 'Há mais de uma candidatura possível. Abra a candidatura que pretende actualizar.');
+ $existing = $matches->first();
+ }
+ if ($existing) {
+ abort_unless($exchange->owns($actor, $existing), 403);
+ }
+ $organization = array_key_exists('organization_id', $data) ? $data['organization_id'] : ($existing->organization_id ?? null);
+ abort_if($organization && ! $exchange->represents($actor, $organization), 403);
+ abort_unless($this->accepting($record), 409, 'Receção de interesses encerrada.');
+ abort_if(isset($data['partnership_version']) && (int) $record->version !== $data['partnership_version'], 409, 'A proposta da parceria mudou. Compare os dados antes de submeter.');
+ abort_if((int) $record->user_id === $actor->id || $exchange->owns($actor, $record, false) || $organization && $organization === $record->organization_id, 403, 'Auto-candidatura não permitida.');
+ if ($organization) {
+ abort_if(DB::table('partnership_interests')->where('partnership_id', $id)->where('organization_id', $organization)->where('status', '!=', 'withdrawn')->when($existing, fn ($q) => $q->where('id', '!=', $existing->id))->exists(), 409, 'A organização já tem uma candidatura ativa.');
+ }
+ Validator::make($data, ['payload.sector_id' => ['nullable', 'exists:sectors,id'], 'payload.territory_id' => ['nullable', 'exists:geo_locations,id']])->validate();
+ if ($existing) {
+ abort_unless(isset($data['version']) && (int) $existing->version === $data['version'], 409, 'Candidatura existente ou alterada; abra-a para atualizar.');
+ abort_unless(in_array($existing->status, ['submitted', 'clarification', 'withdrawn'], true), 409);
+ }
+ $before = $existing ? $this->snapshot($existing) : null;
+ $payload = array_replace($existing ? Arr::only(json_decode($existing->payload, true, 512, JSON_THROW_ON_ERROR), self::PAYLOAD) : [], $data['payload']);
+ $fields = ['proposal' => $data['proposal'], 'payload' => json_encode($payload, JSON_THROW_ON_ERROR), 'organization_id' => $organization, 'status' => 'submitted', 'assessment' => '{}', 'version' => $existing ? (int) $existing->version + 1 : 1, 'updated_at' => now()];
+ if ($existing) {
+ $interestId = (int) $existing->id;
+ DB::table('partnership_interests')->where('id', $interestId)->update($fields);
+ } else {
+ $interestId = (int) DB::table('partnership_interests')->insertGetId([...$fields, 'partnership_id' => $id, 'user_id' => $actor->id, 'created_at' => now()]);
+ }
+ $saved = DB::table('partnership_interests')->where('id', $interestId)->first();
+ $metadata = ['interest_id' => $interestId, 'interest_version' => (int) $saved->version, 'partnership_version' => (int) $record->version, 'previous' => $before, 'submitted' => $this->snapshot($saved)];
+ if (isset($data['client_key'])) {
+ $metadata += ['client_key' => $data['client_key'], 'command_hash' => $hash];
+ }
+ $exchange->event($record, $actor, 'partnership_interest.submitted.v1', $metadata, 'Manifestação de interesse recebida', [$record->user_id, $actor->id]);
+ $saved->command_replayed = false;
+
+ return $saved;
+ });
+ }
+
+ /** @param array $assessment */
+ public function decide(User $actor, int $id, int $version, string $action, string $reason, array $assessment = [], ?int $partnershipVersion = null, ?string $weightsHash = null, ?string $clientKey = null): stdClass
+ {
+ $clientKey = $clientKey === null ? null : strtolower($clientKey);
+ $hash = $this->hash(['interest_id' => $id, 'version' => $version, 'action' => $action, 'reason' => $reason, 'assessment' => $assessment, 'partnership_version' => $partnershipVersion, 'weights_hash' => $weightsHash]);
+
+ return DB::transaction(function () use ($actor, $id, $version, $action, $reason, $assessment, $partnershipVersion, $weightsHash, $clientKey, $hash) {
+ $parent = DB::table('partnership_interests')->where('id', $id)->first(['partnership_id']);
+ abort_unless($parent !== null, 404);
+ $exchange = app(PartnershipExchange::class);
+ $record = $exchange->find($parent->partnership_id, true);
+ $interest = DB::table('partnership_interests')->where('id', $id)->lockForUpdate()->first();
+ abort_unless($interest !== null && (int) $interest->partnership_id === (int) $record->id, 409);
+ abort_unless($exchange->owns($actor, $action === 'withdraw' ? $interest : $record), 403);
+ if ($action === 'withdraw') {
+ abort_if($assessment !== [], 403, 'A avaliação fundamentada pertence ao responsável pela proposta.');
+ }
+ $replay = $this->replay($actor, $record, 'partnership_interest.changed.v1', $clientKey, $hash);
+ if ($replay) {
+ return $replay;
+ }
+ abort_unless((int) $interest->version === $version, 409, 'Candidatura alterada.');
+ abort_unless(in_array($interest->status, ['submitted', 'clarification', 'shortlisted'], true), 409);
+ if ($action !== 'withdraw') {
+ abort_if($partnershipVersion !== null && (int) $record->version !== $partnershipVersion, 409, 'A proposta ou os requisitos foram alterados. Compare antes de decidir.');
+ abort_if($weightsHash !== null && app(PartnershipMatching::class)->explain($record, $interest)['weights_hash'] !== $weightsHash, 409, 'Os critérios de correspondência foram alterados. Compare antes de decidir.');
+ }
+ $states = ['withdraw' => 'withdrawn', 'clarify' => 'clarification', 'shortlist' => 'shortlisted', 'reject' => 'rejected', 'connect' => 'negotiation', 'assess' => $interest->status];
+ abort_unless(isset($states[$action]), 422);
+ $before = $this->snapshot($interest);
+ foreach ($assessment as $code => $criterion) {
+ abort_unless(array_key_exists($code, config('partnerships.criteria')) && is_array($criterion), 422);
+ $assessment[$code] = [...Validator::make($criterion, ['state' => 'required|in:met,unmet,unknown', 'evidence' => 'required_unless:state,unknown|nullable|string|max:2000'])->validate(), 'assessed_by' => $actor->id, 'assessed_at' => now()->toIso8601String()];
+ }
+ $assessed = array_replace(json_decode($interest->assessment, true, 512, JSON_THROW_ON_ERROR), $assessment);
+ $matching = $action === 'withdraw' ? null : app(PartnershipMatching::class)->explain($record, $interest, $assessed);
+ if (in_array($action, ['shortlist', 'connect'], true)) {
+ abort_if(($matching['eligibility'] ?? null) === 'unmet', 422, 'Existe requisito obrigatório comprovadamente incumprido.');
+ }
+ if ($action === 'connect') {
+ abort_unless($interest->status === 'shortlisted', 409, 'Selecione primeiro a candidatura para lista curta.');
+ DB::table('partnership_rooms')->insertOrIgnore(['interest_id' => $id, 'created_at' => now(), 'updated_at' => now()]);
+ }
+ DB::table('partnership_interests')->where('id', $id)->update(['status' => $states[$action], 'assessment' => json_encode($assessed, JSON_THROW_ON_ERROR), 'decision_reason' => $reason, 'version' => $version + 1, 'updated_at' => now()]);
+ $saved = DB::table('partnership_interests')->where('id', $id)->first();
+ $metadata = ['interest_id' => $id, 'interest_version' => $version + 1, 'partnership_version' => (int) $record->version, 'action' => $action, 'from' => $interest->status, 'to' => $states[$action], 'reason' => $reason, 'assessment' => $assessed, 'matching_context' => $matching, 'previous' => $before];
+ if ($clientKey !== null) {
+ $metadata += ['client_key' => $clientKey, 'command_hash' => $hash];
+ }
+ $exchange->event($record, $actor, 'partnership_interest.changed.v1', $metadata, 'Candidatura: '.$states[$action], [$record->user_id, $interest->user_id]);
+ $saved->command_replayed = false;
+
+ return $saved;
+ });
+ }
+
+ /** @return array */
+ private function snapshot(stdClass $interest): array
+ {
+ return ['version' => (int) $interest->version, 'status' => $interest->status, 'organization_id' => $interest->organization_id, 'proposal' => $interest->proposal, 'payload' => json_decode($interest->payload, true, 512, JSON_THROW_ON_ERROR), 'assessment' => json_decode($interest->assessment, true, 512, JSON_THROW_ON_ERROR), 'decision_reason' => $interest->decision_reason];
+ }
+
+ /** @param array $command */
+ private function hash(array $command): string
+ {
+ return hash('sha256', json_encode(Arr::sortRecursive($command), JSON_THROW_ON_ERROR));
+ }
+
+ private function replay(User $actor, stdClass $record, string $type, ?string $key, string $hash): ?stdClass
+ {
+ if ($key === null) {
+ return null;
+ }
+ $event = DB::table('partnership_events')->where('partnership_id', $record->id)->where('actor_id', $actor->id)->where('event_type', $type)->whereRaw("payload->'payload'->>'client_key' = ?", [$key])->first(['payload']);
+ if (! $event) {
+ return null;
+ }
+ $payload = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ abort_unless($payload['command_hash'] === $hash, 409, 'Chave já utilizada com outro conteúdo.');
+ $interest = DB::table('partnership_interests')->where('partnership_id', $record->id)->where('id', $payload['interest_id'])->first();
+ abort_unless($interest !== null, 409, 'A candidatura original não está disponível.');
+ $interest->command_replayed = true;
+
+ return $interest;
+ }
+}
diff --git a/app/Services/PartnershipCandidacyHistory.php b/app/Services/PartnershipCandidacyHistory.php
new file mode 100644
index 00000000..502fa743
--- /dev/null
+++ b/app/Services/PartnershipCandidacyHistory.php
@@ -0,0 +1,198 @@
+ */
+ private array $people = [];
+
+ /** @var array */
+ private array $organizations = [];
+
+ /** @return array */
+ public function page(User $actor, int $id, ?string $before = null): array
+ {
+ $interest = DB::table('partnership_interests')->where('id', $id)->first();
+ abort_unless($interest !== null, 404);
+ $exchange = app(PartnershipExchange::class);
+ $record = $exchange->find($interest->partnership_id);
+ $responsible = $exchange->owns($actor, $record, false);
+ abort_unless($responsible || $exchange->owns($actor, $interest, false), 403, 'Histórico reservado aos intervenientes autorizados desta candidatura.');
+ $boundary = $before === null ? null : $this->decodeCursor($before, $actor, $id);
+ $events = DB::table('partnership_events')->where('partnership_id', $record->id)
+ ->whereIn('event_type', ['partnership_interest.submitted.v1', 'partnership_interest.changed.v1'])
+ ->whereRaw("payload->'payload'->>'interest_id' = ?", [(string) $id])
+ ->when($boundary, fn ($query) => $query->where('aggregate_version', '<', $boundary))
+ ->orderByDesc('aggregate_version')->limit(self::PAGE_SIZE + 1)->get(['aggregate_version', 'event_type', 'actor_id', 'occurred_at', 'payload']);
+ $hasMore = $events->count() > self::PAGE_SIZE;
+ $page = $events->take(self::PAGE_SIZE);
+ $entries = $page->map(fn ($event) => $this->entry($event, $actor, $interest, $responsible))->all();
+ $base = '/parcerias/candidaturas/'.$id.'/historico';
+ $last = $page->last();
+ $next = $hasMore && $last ? $base.'?before='.rawurlencode(Crypt::encryptString(json_encode(['actor' => $actor->id, 'interest' => $id, 'before' => (int) $last->aggregate_version], JSON_THROW_ON_ERROR))) : null;
+
+ return ['candidacy_id' => $id, 'entries' => $entries, 'next_url' => $next, 'first_url' => $base, 'older_page' => $before !== null,
+ 'partnership_href' => $record->status === 'published' || $responsible ? '/parcerias/'.$record->id : null, 'dashboard_href' => '/parcerias/painel'];
+ }
+
+ private function decodeCursor(string $token, User $actor, int $id): int
+ {
+ try {
+ $cursor = json_decode(Crypt::decryptString($token), true, 512, JSON_THROW_ON_ERROR);
+ } catch (DecryptException|\JsonException) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não é válida. Volte ao início do histórico.']);
+ }
+ if (! is_array($cursor) || ($cursor['actor'] ?? null) !== $actor->id || ($cursor['interest'] ?? null) !== $id || ! is_int($cursor['before'] ?? null) || $cursor['before'] < 1) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não pertence a esta candidatura e conta. Volte ao início do histórico.']);
+ }
+
+ return $cursor['before'];
+ }
+
+ /** @return array */
+ private function entry(stdClass $event, User $actor, stdClass $interest, bool $responsible): array
+ {
+ $envelope = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR);
+ $data = is_array($envelope) && is_array($envelope['payload'] ?? null) ? $envelope['payload'] : [];
+ $previous = is_array($data['previous'] ?? null) ? $data['previous'] : null;
+ $submitted = is_array($data['submitted'] ?? null) ? $data['submitted'] : null;
+ $decision = $event->event_type === 'partnership_interest.changed.v1';
+ $after = $submitted;
+ if ($decision) {
+ $after = array_replace($previous ?? [], ['version' => $data['interest_version'] ?? null, 'status' => $data['to'] ?? null, 'assessment' => $data['assessment'] ?? null, 'decision_reason' => $data['reason'] ?? null]);
+ }
+ $beforeView = $this->snapshot($previous, $actor, $interest, $responsible);
+ $afterView = $this->snapshot($after, $actor, $interest, $responsible);
+ $canRead = $responsible || $beforeView['availability'] === 'available' || $afterView['availability'] === 'available';
+ $version = is_int($data['interest_version'] ?? null) && $data['interest_version'] > 0 ? $data['interest_version'] : null;
+ if (! $canRead) {
+ return ['version' => $version, 'restricted' => true, 'action' => null, 'actor_name' => null, 'occurred_at' => null, 'reason' => null, 'previous' => $beforeView, 'after' => $afterView, 'matching' => null, 'partnership_version' => null];
+ }
+ $action = $decision ? ($data['action'] ?? null) : 'submit';
+
+ return ['version' => $version, 'restricted' => false, 'action' => is_string($action) && in_array($action, ['submit', 'assess', 'clarify', 'shortlist', 'reject', 'connect', 'withdraw'], true) ? $action : null,
+ 'actor_name' => $this->person((int) $event->actor_id), 'occurred_at' => $event->occurred_at, 'reason' => is_string($data['reason'] ?? null) ? $data['reason'] : null,
+ 'previous' => $beforeView, 'after' => $afterView, 'matching' => $afterView['availability'] === 'available' ? $this->matching($data['matching_context'] ?? null) : null,
+ 'partnership_version' => is_int($data['partnership_version'] ?? null) ? $data['partnership_version'] : (is_int($envelope['publication_version'] ?? null) ? $envelope['publication_version'] : null)];
+ }
+
+ /** @param array|null $snapshot
+ * @return array
+ */
+ private function snapshot(?array $snapshot, User $actor, stdClass $interest, bool $responsible): array
+ {
+ if ($snapshot === null) {
+ return ['availability' => 'not_recorded'];
+ }
+ $scopeKnown = array_key_exists('organization_id', $snapshot) && ($snapshot['organization_id'] === null || is_string($snapshot['organization_id']) && Str::isUuid($snapshot['organization_id']));
+ if (! $responsible && ! $scopeKnown) {
+ return ['availability' => 'scope_unknown'];
+ }
+ if (! $responsible && ! app(PartnershipExchange::class)->owns($actor, (object) ['organization_id' => $snapshot['organization_id'], 'user_id' => $interest->user_id], false)) {
+ return ['availability' => 'restricted'];
+ }
+ $organization = $scopeKnown && is_string($snapshot['organization_id']) ? $snapshot['organization_id'] : null;
+ $payload = is_array($snapshot['payload'] ?? null) ? $snapshot['payload'] : null;
+ $fields = [];
+ foreach (['proposal', 'decision_reason'] as $key) {
+ if (array_key_exists($key, $snapshot) && ($snapshot[$key] === null || is_string($snapshot[$key]))) {
+ $fields[$key] = $snapshot[$key];
+ }
+ }
+ foreach (['capacity', 'availability', 'contribution', 'conflicts'] as $key) {
+ if ($payload !== null && array_key_exists($key, $payload) && ($payload[$key] === null || is_string($payload[$key]))) {
+ $fields[$key] = $payload[$key];
+ }
+ }
+ $consent = $payload !== null && array_key_exists('consent', $payload) ? $payload['consent'] : null;
+ $knownConsent = in_array($consent, [true, false, 0, 1, '0', '1', 'yes', 'on'], true);
+ $references = [];
+ foreach (['sector_id', 'territory_id'] as $key) {
+ if ($payload !== null && (is_string($payload[$key] ?? null) || is_int($payload[$key] ?? null))) {
+ $references[$key] = (string) $payload[$key];
+ }
+ }
+
+ return ['availability' => 'available', 'version' => is_int($snapshot['version'] ?? null) ? $snapshot['version'] : null,
+ 'status' => is_string($snapshot['status'] ?? null) ? $snapshot['status'] : null, 'scope_known' => $scopeKnown, 'organization_id' => $organization,
+ 'organization_name' => $organization ? $this->organization($organization) : null,
+ 'fields' => $fields, 'consent_known' => $knownConsent, 'consent' => $knownConsent ? in_array($consent, [true, 1, '1', 'yes', 'on'], true) : null,
+ 'assessment_recorded' => is_array($snapshot['assessment'] ?? null), 'assessment' => $this->assessment($snapshot['assessment'] ?? null), 'references' => $references,
+ 'complete' => array_key_exists('proposal', $fields) && $scopeKnown && $payload !== null && is_array($snapshot['assessment'] ?? null)];
+ }
+
+ /** @return list> */
+ private function assessment(mixed $value): array
+ {
+ $items = [];
+ foreach (is_array($value) ? $value : [] as $code => $entry) {
+ if (! is_array($entry) || ! is_string($code)) {
+ continue;
+ }
+ $label = config('partnerships.criteria.'.$code, $code);
+ $items[] = ['code' => $code, 'label' => is_string($label) ? $label : $code, 'label_source' => 'current_catalogue',
+ 'state' => is_string($entry['state'] ?? null) ? $entry['state'] : null, 'evidence' => is_string($entry['evidence'] ?? null) ? $entry['evidence'] : null,
+ 'actor_name' => is_int($entry['assessed_by'] ?? null) ? $this->person($entry['assessed_by']) : null, 'assessed_at' => is_string($entry['assessed_at'] ?? null) ? $entry['assessed_at'] : null];
+ }
+
+ return $items;
+ }
+
+ /** @return array|null */
+ private function matching(mixed $value): ?array
+ {
+ if (! is_array($value)) {
+ return null;
+ }
+ $criteria = [];
+ foreach (is_array($value['criteria'] ?? null) ? $value['criteria'] : [] as $criterion) {
+ if (! is_array($criterion) || ! is_string($criterion['code'] ?? null)) {
+ continue;
+ }
+ $projected = ['code' => $criterion['code'], 'mandatory' => is_bool($criterion['mandatory'] ?? null) ? $criterion['mandatory'] : null,
+ 'weight' => is_int($criterion['weight'] ?? null) || is_float($criterion['weight'] ?? null) ? $criterion['weight'] : null];
+ foreach (['label', 'state', 'evidence', 'explanation'] as $field) {
+ $projected[$field] = is_string($criterion[$field] ?? null) ? $criterion[$field] : null;
+ }
+ $criteria[] = $projected;
+ }
+ $matching = ['criteria' => $criteria];
+ foreach (['algorithm_version', 'weights_hash', 'eligibility'] as $field) {
+ $matching[$field] = is_string($value[$field] ?? null) ? $value[$field] : null;
+ }
+ foreach (['score_min', 'score_max', 'unknown_weight'] as $field) {
+ $matching[$field] = is_int($value[$field] ?? null) || is_float($value[$field] ?? null) ? $value[$field] : null;
+ }
+
+ return $matching;
+ }
+
+ private function person(int $id): ?string
+ {
+ if (! array_key_exists($id, $this->people)) {
+ $this->people[$id] = DB::table('users')->where('id', $id)->value('name');
+ }
+
+ return $this->people[$id];
+ }
+
+ private function organization(string $id): ?string
+ {
+ if (! array_key_exists($id, $this->organizations)) {
+ $this->organizations[$id] = DB::table('organizations')->where('id', $id)->value('name');
+ }
+
+ return $this->organizations[$id];
+ }
+}
diff --git a/app/Services/PartnershipDraftSaves.php b/app/Services/PartnershipDraftSaves.php
new file mode 100644
index 00000000..15b6bff6
--- /dev/null
+++ b/app/Services/PartnershipDraftSaves.php
@@ -0,0 +1,46 @@
+where('partnership_id', $record->id)->where('actor_id', $actor->id)->where('event_type', 'partnership_opportunity.changed.v1')->whereRaw("payload->'payload'->>'operation_key' = ?", [$key])->selectRaw("payload->'payload'->>'operation_hash' AS hash, payload->'payload'->'result_version' AS version")->first();
+ if (! $event) {
+ return null;
+ }
+ abort_unless($event->hash === $hash, 409, 'Chave de gravação já utilizada com outro conteúdo.');
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ abort_unless(is_int($version) && $version > 0, 409, 'A versão da gravação anterior não foi identificada.');
+ $record->command_replayed = true;
+ $record->command_saved_version = $version;
+
+ return $record;
+ }
+
+ /** @return list */
+ public function commands(User $actor, stdClass $record): array
+ {
+ abort_unless(app(PartnershipExchange::class)->owns($actor, $record), 403);
+ $events = DB::table('partnership_events')->where('partnership_id', $record->id)->where('actor_id', $actor->id)->where('event_type', 'partnership_opportunity.changed.v1')->whereRaw("payload->'payload'->>'operation_key' IS NOT NULL")->orderBy('aggregate_version')->selectRaw("payload->'payload'->>'operation_key' AS key, payload->'payload'->'result_version' AS version")->get();
+ $commands = [];
+ foreach ($events as $event) {
+ $version = is_string($event->version) ? json_decode($event->version, true, 512, JSON_THROW_ON_ERROR) : $event->version;
+ if (is_string($event->key) && Str::isUuid($event->key) && is_int($version) && $version > 0) {
+ $commands[] = ['key' => $event->key, 'version' => $version];
+ }
+ }
+
+ return $commands;
+ }
+}
diff --git a/app/Services/PartnershipExchange.php b/app/Services/PartnershipExchange.php
index 3358fb2b..15868f7c 100644
--- a/app/Services/PartnershipExchange.php
+++ b/app/Services/PartnershipExchange.php
@@ -3,9 +3,9 @@
namespace App\Services;
use App\Models\User;
+use Illuminate\Database\Query\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
@@ -13,11 +13,68 @@ use stdClass;
class PartnershipExchange
{
+ private const PAYLOAD_FIELDS = ['summary', 'requirements', 'mandatory', 'confidentiality', 'consent', 'availability'];
+
+ private const ROOT_FIELDS = ['title', 'offer', 'seeking', 'organization_id', 'sector_id', 'kind', 'partnership_type', 'deadline'];
+
public function represents(User $actor, ?string $organization, bool $write = true): bool
{
- return $organization !== null && DB::table('memberships')->where('user_id', $actor->id)->where('organization_id', $organization)->whereNull('deleted_at')
- ->when($write, fn ($q) => $q->whereIn('role', ['admin', 'manager', 'officer']))->exists()
- && DB::table('organizations')->where('id', $organization)->whereNull('deleted_at')->exists();
+ return $organization !== null && $this->representatives($organization, $write)->where('representative.user_id', $actor->id)->exists();
+ }
+
+ private function representatives(?string $organization, bool $write = true): Builder
+ {
+ return DB::table('memberships as representative')->join('organizations as represented', 'represented.id', '=', 'representative.organization_id')
+ ->when($organization !== null, fn ($query) => $query->where('representative.organization_id', $organization))->whereNull('representative.deleted_at')->whereNull('represented.deleted_at')
+ ->when($write, fn ($q) => $q->whereIn('representative.role', ['admin', 'manager', 'officer']))->select('representative.user_id');
+ }
+
+ /** @return list */
+ public function readableOrganizations(User $actor): array
+ {
+ $organizations = [];
+ foreach ($this->representatives(null, false)->where('representative.user_id', $actor->id)->select('representative.organization_id')->pluck('representative.organization_id') as $id) {
+ if (! is_string($id) || ! Str::isUuid($id)) {
+ throw new \LogicException('Organization identity must be a UUID from the authorized catalogue.');
+ }
+ $organizations[] = $id;
+ }
+
+ return $organizations;
+ }
+
+ /** @return list */
+ public function notificationRecipients(stdClass ...$parties): array
+ {
+ $recipients = [];
+ foreach ($parties as $party) {
+ $ids = $party->organization_id ? $this->representatives($party->organization_id)->pluck('representative.user_id')->all() : User::query()->whereKey($party->user_id)->pluck('id')->all();
+ foreach ($ids as $id) {
+ $recipients[(int) $id] = (int) $id;
+ }
+ }
+
+ return array_values($recipients);
+ }
+
+ /** @return list}> */
+ public function participants(stdClass $record, stdClass $interest): array
+ {
+ // Called only after room access is checked. The selector reuses the same representation query as commands.
+ $participants = [];
+ foreach (['proponent' => $record, 'candidate' => $interest] as $party => $source) {
+ $users = User::query()->when($source->organization_id,
+ fn ($q) => $q->whereIn('id', $this->representatives($source->organization_id)),
+ fn ($q) => $q->whereKey($source->user_id))->get(['id', 'name']);
+ foreach ($users as $user) {
+ $participants[$user->id] ??= ['id' => $user->id, 'name' => $user->name, 'parties' => []];
+ $participants[$user->id]['parties'][] = $party;
+ }
+ }
+ $participants = array_values($participants);
+ usort($participants, fn ($a, $b) => strnatcasecmp($a['name'], $b['name']) ?: $a['id'] <=> $b['id']);
+
+ return $participants;
}
public function owns(User $actor, stdClass $record, bool $write = true): bool
@@ -39,170 +96,114 @@ class PartnershipExchange
{
$data = Validator::make($data, [
'client_key' => [$id ? 'nullable' : 'required', 'uuid'], 'version' => [$id ? 'required' : 'nullable', 'integer', 'min:1'],
+ 'operation_key' => ['nullable', 'uuid'],
'title' => ['nullable', 'string', 'max:200'], 'offer' => ['nullable', 'string', 'max:15000'], 'seeking' => ['nullable', 'string', 'max:15000'],
- 'kind' => ['required', 'in:offering,seeking'], 'partnership_type' => ['nullable', Rule::in(array_keys(config('partnerships.types')))],
- 'organization_id' => ['nullable', 'uuid'], 'sector_id' => ['nullable', 'integer', Rule::exists('sectors', 'id')->where('is_active', true)->whereNull('deleted_at')],
- 'deadline' => ['nullable', 'date_format:Y-m-d'], 'payload' => ['array:summary,requirements,mandatory,confidentiality,consent,availability'],
+ 'kind' => ['required', 'in:offering,seeking'], 'partnership_type' => ['nullable', 'string'],
+ 'organization_id' => ['nullable', 'uuid'], 'sector_id' => ['nullable', 'integer'],
+ 'deadline' => ['nullable', 'date_format:Y-m-d'], 'payload' => ['array:'.implode(',', self::PAYLOAD_FIELDS)],
'payload.summary' => ['nullable', 'string', 'max:15000'], 'payload.requirements' => ['nullable', 'string', 'max:10000'],
- 'payload.mandatory' => ['array', 'max:7'], 'payload.mandatory.*' => [Rule::in(array_keys(config('partnerships.criteria')))],
+ 'payload.mandatory' => ['array', 'max:7'], 'payload.mandatory.*' => ['string'],
'payload.confidentiality' => ['in:public,private'], 'payload.consent' => ['boolean'], 'payload.availability' => ['nullable', 'string', 'max:1000'],
'locations' => ['array', 'max:30'], 'locations.*.geo_location_id' => ['required', 'uuid'], 'locations.*.role' => ['required', 'in:primary,operating,coverage'],
'locations.*.source_reference' => ['required', 'string', 'max:2000'],
'origins' => ['array', 'max:20'], 'origins.*.type' => ['required', 'string'], 'origins.*.target_id' => ['required', 'string', 'max:100'],
- ])->validate();
- abort_if(($data['organization_id'] ?? null) && ! $this->represents($actor, $data['organization_id']), 403, 'Representação da organização não autorizada.');
+ ], ['payload.availability.max' => 'Indique a disponibilidade em até 1000 caracteres.'])->validate();
+ if ($id === null) {
+ unset($data['operation_key']);
+ } elseif (is_string($data['operation_key'] ?? null)) {
+ $data['operation_key'] = strtolower($data['operation_key']);
+ }
$creationHash = hash('sha256', json_encode(Arr::sortRecursive($data), JSON_THROW_ON_ERROR));
+ $operationHash = hash('sha256', json_encode(Arr::sortRecursive(Arr::except($data, ['client_key', 'operation_key'])), JSON_THROW_ON_ERROR));
- return DB::transaction(function () use ($actor, $data, $id, $creationHash) {
+ return DB::transaction(function () use ($actor, $data, $id, $creationHash, $operationHash) {
+ $creating = $id === null;
DB::select('select pg_advisory_xact_lock(71026, ?)', [$actor->id]);
if ($id) {
$record = $this->find($id, true);
abort_unless($this->owns($actor, $record), 403);
+ $replay = app(PartnershipDraftSaves::class)->replay($actor, $record, $data['operation_key'] ?? null, $operationHash);
+ if ($replay) {
+ return $replay;
+ }
abort_unless((int) $record->version === (int) $data['version'], 409, 'Rascunho alterado; recarregue.');
abort_unless(in_array($record->status, ['draft', 'returned', 'rejected', 'published'], true), 409, 'Estado não permite edição.');
} else {
$existing = DB::table('portal_partnerships')->where('user_id', $actor->id)->where('client_key', $data['client_key'])->first();
if ($existing) {
+ abort_unless($this->owns($actor, $existing), 403, 'A representação actual desta proposta não autoriza recuperar a gravação.');
abort_unless((json_decode($existing->payload, true)['_creation_hash'] ?? null) === $creationHash, 409, 'Chave de rascunho já utilizada com outro conteúdo.');
+ $existing->command_replayed = true;
+
return $existing;
}
$id = DB::table('portal_partnerships')->insertGetId(['user_id' => $actor->id, 'client_key' => $data['client_key'], 'title' => '', 'sector' => '', 'province' => '', 'offer' => '', 'seeking' => '', 'status' => 'draft', 'created_at' => now(), 'updated_at' => now()]);
$record = $this->find($id, true);
}
- $origins = $data['origins'] ?? [];
- foreach ($origins as $origin) {
+ $previous = $creating ? null : app(PartnershipPublication::class)->snapshot($record);
+ abort_if(($data['organization_id'] ?? null) && ! $this->represents($actor, $data['organization_id']), 403, 'Representação da organização não autorizada.');
+ // Replaying an already committed creation is a read; live-reference checks apply to new writes.
+ Validator::make($data, ['partnership_type' => ['nullable', Rule::in(array_keys(config('partnerships.types')))], 'payload.mandatory.*' => [Rule::in(array_keys(config('partnerships.criteria')))], 'sector_id' => ['nullable', Rule::exists('sectors', 'id')->where('is_active', true)->whereNull('deleted_at')]], ['sector_id.exists' => 'Seleccione um sector activo ou deixe a classificação por definir.'])->validate();
+ $origins = $data['origins'] ?? DB::table('partnership_origins')->where('partnership_id', $id)->get(['type', 'target_id'])->map(fn ($row) => (array) $row)->all();
+ foreach ($data['origins'] ?? [] as $origin) {
app(PartnershipSources::class)->resolve($origin['type'], $origin['target_id'], $actor);
}
- $locations = $data['locations'] ?? [];
- foreach ($locations as $location) {
+ $locations = $data['locations'] ?? DB::table('partnership_locations')->where('partnership_id', $id)->get(['geo_location_id', 'role', 'source_reference'])->map(fn ($row) => (array) $row)->all();
+ foreach ($data['locations'] ?? [] as $location) {
abort_unless(app(InvestmentGeography::class)->publicReferences()->where('id', $location['geo_location_id'])->exists(), 422, 'Localização não pertence ao cadastro territorial público.');
}
- DB::table('portal_partnerships')->where('id', $id)->update(['title' => $data['title'] ?? '', 'offer' => $data['offer'] ?? '', 'seeking' => $data['seeking'] ?? '',
- 'organization_id' => $data['organization_id'] ?? null, 'sector_id' => $data['sector_id'] ?? null, 'kind' => $data['kind'], 'partnership_type' => $data['partnership_type'] ?? null,
- 'deadline' => $data['deadline'] ?? null, 'payload' => json_encode([...($data['payload'] ?? []), '_creation_hash' => json_decode($record->payload, true)['_creation_hash'] ?? $creationHash], JSON_THROW_ON_ERROR),
- 'status' => 'draft', 'version' => $record->version + 1, 'updated_at' => now()]);
- DB::table('partnership_origins')->where('partnership_id', $id)->delete();
- foreach ($origins as $origin) {
- DB::table('partnership_origins')->insertOrIgnore(['partnership_id' => $id, 'type' => $origin['type'], 'target_id' => $origin['target_id']]);
+ $existingPayload = json_decode($record->payload, true);
+ $payload = array_replace(Arr::only($existingPayload, self::PAYLOAD_FIELDS), $data['payload'] ?? []);
+ $fields = array_replace(Arr::only((array) $record, self::ROOT_FIELDS), Arr::only($data, self::ROOT_FIELDS));
+ foreach (['title', 'offer', 'seeking'] as $field) {
+ $fields[$field] ??= '';
}
- DB::table('partnership_locations')->where('partnership_id', $id)->delete();
- foreach ($locations as $location) {
- DB::table('partnership_locations')->insertOrIgnore(['partnership_id' => $id, 'geo_location_id' => $location['geo_location_id'], 'role' => $location['role'], 'source_reference' => $location['source_reference']]);
+ DB::table('portal_partnerships')->where('id', $id)->update([...$fields, 'payload' => json_encode([...$payload, '_creation_hash' => $existingPayload['_creation_hash'] ?? $creationHash], JSON_THROW_ON_ERROR),
+ 'status' => 'draft', 'version' => $record->version + 1, 'updated_at' => now()]);
+ if (array_key_exists('origins', $data)) {
+ DB::table('partnership_origins')->where('partnership_id', $id)->delete();
+ foreach ($origins as $origin) {
+ DB::table('partnership_origins')->insertOrIgnore(['partnership_id' => $id, 'type' => $origin['type'], 'target_id' => $origin['target_id']]);
+ }
+ }
+ if (array_key_exists('locations', $data)) {
+ DB::table('partnership_locations')->where('partnership_id', $id)->delete();
+ foreach ($locations as $location) {
+ DB::table('partnership_locations')->insertOrIgnore(['partnership_id' => $id, 'geo_location_id' => $location['geo_location_id'], 'role' => $location['role'], 'source_reference' => $location['source_reference']]);
+ }
}
$saved = $this->find($id);
- $this->event($saved, $actor, 'partnership_opportunity.changed.v1', ['previous_status' => $record->status, 'origins' => $origins, 'locations' => $locations], 'Rascunho guardado', [$record->user_id]);
+ $metadata = ['previous_status' => $record->status, 'origins' => $origins, 'locations' => $locations, 'action' => $creating ? 'create' : 'edit', 'result_version' => (int) $saved->version, 'previous' => $previous, 'applied' => app(PartnershipPublication::class)->snapshot($saved)];
+ if (! $creating && isset($data['operation_key'])) {
+ $metadata += ['operation_key' => $data['operation_key'], 'operation_hash' => $operationHash];
+ }
+ $this->event($saved, $actor, 'partnership_opportunity.changed.v1', $metadata, 'Rascunho guardado', [$record->user_id]);
+ $saved->command_replayed = false;
+ if (! $creating && isset($data['operation_key'])) {
+ $saved->command_saved_version = (int) $saved->version;
+ }
return $saved;
});
}
- public function transition(User $actor, int $id, int $version, string $action, string $reason): stdClass
+ public function transition(User $actor, int $id, int $version, string $action, string $reason, ?string $clientKey = null): stdClass
{
- return DB::transaction(function () use ($actor, $id, $version, $action, $reason) {
- $record = $this->find($id, true);
- abort_unless((int) $record->version === $version, 409, 'Proposta alterada; recarregue.');
- $moderation = in_array($action, ['publish', 'return', 'reject', 'suspend'], true);
- if ($moderation) {
- Gate::forUser($actor)->authorize('manage-portal');
- abort_if($this->owns($actor, $record), 403, 'Não pode moderar a própria proposta.');
- } else {
- abort_unless($this->owns($actor, $record), 403);
- }
- $from = $record->status;
- $allowed = ['submit' => ['draft', 'returned', 'rejected'], 'publish' => ['submitted', 'pending'], 'return' => ['submitted', 'pending'],
- 'reject' => ['submitted', 'pending'], 'suspend' => ['published'], 'archive' => ['draft', 'published', 'suspended', 'rejected'], 'renew' => ['published', 'suspended', 'archived']];
- abort_unless(isset($allowed[$action]) && in_array($from, $allowed[$action], true), 409, 'Transição inválida.');
- if ($action === 'submit') {
- $payload = json_decode($record->payload, true);
- Validator::make(['title' => $record->title, 'type' => $record->partnership_type, 'offer' => $record->offer, 'seeking' => $record->seeking, 'consent' => $payload['consent'] ?? false],
- ['title' => 'required', 'type' => 'required', 'offer' => 'required_without:seeking', 'seeking' => 'required_without:offer', 'consent' => 'accepted'])->validate();
- }
- $status = ['submit' => 'submitted', 'publish' => 'published', 'return' => 'returned', 'reject' => 'rejected', 'suspend' => 'suspended', 'archive' => 'archived', 'renew' => 'draft'][$action];
- DB::table('portal_partnerships')->where('id', $id)->update(['status' => $status, 'version' => $version + 1, 'reviewed_by' => $moderation ? $actor->id : $record->reviewed_by,
- 'published_at' => $action === 'publish' ? now() : $record->published_at, 'updated_at' => now()]);
- $saved = $this->find($id);
- $this->event($saved, $actor, 'partnership_opportunity.'.$status.'.v1', ['from' => $from, 'to' => $status, 'reason' => $reason], 'Proposta: '.$status, [$record->user_id]);
-
- return $saved;
- });
+ return app(PartnershipPublication::class)->transition($actor, $id, $version, $action, $reason, $clientKey);
}
/** @param array $data */
public function interest(User $actor, int $id, array $data): stdClass
{
- $data = Validator::make($data, ['version' => ['nullable', 'integer', 'min:1'], 'organization_id' => ['nullable', 'uuid'], 'proposal' => ['required', 'string', 'max:15000'],
- 'payload' => ['array:capacity,availability,contribution,conflicts,consent,sector_id,territory_id'], 'payload.consent' => ['accepted'],
- 'payload.capacity' => ['nullable', 'string', 'max:5000'], 'payload.availability' => ['nullable', 'string', 'max:1000'], 'payload.contribution' => ['nullable', 'string', 'max:5000'], 'payload.conflicts' => ['nullable', 'string', 'max:5000'],
- 'payload.sector_id' => ['nullable', 'integer', 'exists:sectors,id'], 'payload.territory_id' => ['nullable', 'uuid', 'exists:geo_locations,id']])->validate();
- abort_if(($data['organization_id'] ?? null) && ! $this->represents($actor, $data['organization_id']), 403);
-
- return DB::transaction(function () use ($actor, $id, $data) {
- $record = $this->find($id, true);
- abort_unless($record->status === 'published' && (! $record->deadline || $record->deadline >= today()->toDateString()), 409, 'Receção de interesses encerrada.');
- abort_if((int) $record->user_id === $actor->id || $this->owns($actor, $record, false) || ($data['organization_id'] ?? null) && $data['organization_id'] === $record->organization_id, 403, 'Auto-candidatura não permitida.');
- $existing = DB::table('partnership_interests')->where('partnership_id', $id)->where(fn ($q) => $q->where('user_id', $actor->id)
- ->when($data['organization_id'] ?? null, fn ($org) => $org->orWhere('organization_id', $data['organization_id'])))->orderBy('id')->lockForUpdate()->first();
- if ($data['organization_id'] ?? null) {
- abort_if(DB::table('partnership_interests')->where('partnership_id', $id)->where('organization_id', $data['organization_id'])->where('status', '!=', 'withdrawn')
- ->when($existing, fn ($q) => $q->where('id', '!=', $existing->id))->exists(), 409, 'A organização já tem uma candidatura ativa.');
- }
- if ($existing) {
- abort_unless($this->owns($actor, $existing), 403);
- abort_unless(isset($data['version']) && (int) $existing->version === (int) $data['version'], 409, 'Candidatura existente ou alterada; abra-a para atualizar.');
- abort_unless(in_array($existing->status, ['submitted', 'clarification', 'withdrawn'], true), 409);
- $interestId = $existing->id;
- DB::table('partnership_interests')->where('id', $interestId)->update(['proposal' => $data['proposal'], 'payload' => json_encode($data['payload']), 'organization_id' => $data['organization_id'] ?? null,
- 'status' => 'submitted', 'assessment' => '{}', 'version' => $existing->version + 1, 'updated_at' => now()]);
- } else {
- $interestId = DB::table('partnership_interests')->insertGetId(['partnership_id' => $id, 'user_id' => $actor->id, 'organization_id' => $data['organization_id'] ?? null,
- 'proposal' => $data['proposal'], 'payload' => json_encode($data['payload']), 'created_at' => now(), 'updated_at' => now()]);
- }
- $this->event($record, $actor, 'partnership_interest.submitted.v1', ['interest_id' => $interestId, 'interest_version' => $existing ? $existing->version + 1 : 1], 'Manifestação de interesse recebida', [$record->user_id, $actor->id]);
-
- return DB::table('partnership_interests')->where('id', $interestId)->first();
- });
+ return app(PartnershipCandidacies::class)->submit($actor, $id, $data);
}
/** @param array $assessment */
- public function decideInterest(User $actor, int $id, int $version, string $action, string $reason, array $assessment = []): stdClass
+ public function decideInterest(User $actor, int $id, int $version, string $action, string $reason, array $assessment = [], ?int $partnershipVersion = null, ?string $weightsHash = null, ?string $clientKey = null): stdClass
{
- return DB::transaction(function () use ($actor, $id, $version, $action, $reason, $assessment) {
- $interest = DB::table('partnership_interests')->where('id', $id)->lockForUpdate()->first();
- abort_unless($interest !== null, 404);
- $record = $this->find($interest->partnership_id, true);
- abort_unless((int) $interest->version === $version, 409, 'Candidatura alterada.');
- if ($action === 'withdraw') {
- abort_if($assessment !== [], 403, 'A avaliação fundamentada pertence ao responsável pela proposta.');
- abort_unless($this->owns($actor, $interest), 403);
- abort_unless(in_array($interest->status, ['submitted', 'clarification', 'shortlisted'], true), 409);
- } else {
- abort_unless($this->owns($actor, $record), 403);
- abort_unless(in_array($interest->status, ['submitted', 'clarification', 'shortlisted'], true), 409);
- }
- $states = ['withdraw' => 'withdrawn', 'clarify' => 'clarification', 'shortlist' => 'shortlisted', 'reject' => 'rejected', 'connect' => 'negotiation', 'assess' => $interest->status];
- abort_unless(isset($states[$action]), 422);
- foreach ($assessment as $code => $criterion) {
- abort_unless(array_key_exists($code, config('partnerships.criteria')) && is_array($criterion), 422);
- Validator::make($criterion, ['state' => 'required|in:met,unmet,unknown', 'evidence' => 'required_unless:state,unknown|nullable|string|max:2000'])->validate();
- $assessment[$code]['assessed_by'] = $actor->id;
- $assessment[$code]['assessed_at'] = now()->toIso8601String();
- }
- $assessed = array_replace(json_decode($interest->assessment, true), $assessment);
- if (in_array($action, ['shortlist', 'connect'], true)) {
- $match = app(PartnershipMatching::class)->explain($record, $interest, $assessed);
- abort_if($match['eligibility'] === 'unmet', 422, 'Existe requisito obrigatório comprovadamente incumprido.');
- }
- if ($action === 'connect') {
- abort_unless($interest->status === 'shortlisted', 409, 'Selecione primeiro a candidatura para lista curta.');
- DB::table('partnership_rooms')->insertOrIgnore(['interest_id' => $id, 'created_at' => now(), 'updated_at' => now()]);
- }
- DB::table('partnership_interests')->where('id', $id)->update(['status' => $states[$action], 'assessment' => json_encode($assessed), 'decision_reason' => $reason, 'version' => $version + 1, 'updated_at' => now()]);
- $this->event($record, $actor, 'partnership_interest.changed.v1', ['interest_id' => $id, 'interest_version' => $version + 1, 'from' => $interest->status, 'to' => $states[$action], 'reason' => $reason, 'assessment' => $assessed], 'Candidatura: '.$states[$action], [$record->user_id, $interest->user_id]);
-
- return DB::table('partnership_interests')->where('id', $id)->first();
- });
+ return app(PartnershipCandidacies::class)->decide($actor, $id, $version, $action, $reason, $assessment, $partnershipVersion, $weightsHash, $clientKey);
}
/** @return array{room:stdClass,interest:stdClass,partnership:stdClass} */
@@ -224,6 +225,15 @@ class PartnershipExchange
public function event(stdClass $record, User $actor, string $type, array $payload, string $title, array $recipients = []): void
{
DB::transaction(function () use ($record, $actor, $type, $payload, $title, $recipients): void {
+ if ($recipients !== []) {
+ $context = app(PartnershipNotifications::class)->context($record, $payload);
+ $payload['_notification_context'] = $context;
+ $parties = [(object) $context['partnership']];
+ if ($context['interest'] !== null) {
+ $parties[] = (object) $context['interest'];
+ }
+ $recipients = $this->notificationRecipients(...$parties);
+ }
DB::select('select pg_advisory_xact_lock(hashtextextended(?,0))', ['partnership-events:'.$record->id]);
$sequence = (DB::table('partnership_events')->where('partnership_id', $record->id)->max('aggregate_version') ?? 0) + 1;
$eventId = (string) Str::uuid();
diff --git a/app/Services/PartnershipMilestones.php b/app/Services/PartnershipMilestones.php
new file mode 100644
index 00000000..9f102c8d
--- /dev/null
+++ b/app/Services/PartnershipMilestones.php
@@ -0,0 +1,78 @@
+ Creation keys are private to the actor who submitted them. */
+ public function creationKeys(User $actor, int $partnership, int $room): array
+ {
+ $keys = [];
+ $events = DB::table('partnership_events')->where('partnership_id', $partnership)->where('actor_id', $actor->id)
+ ->where('event_type', 'partnership_milestone.changed.v1')->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $room])
+ ->whereRaw("payload->'payload'->>'client_key' IS NOT NULL")->get(['payload']);
+ foreach ($events as $event) {
+ $payload = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ $keys[(int) $payload['milestone_id']] = $payload['client_key'];
+ }
+
+ return $keys;
+ }
+
+ /** @param array $data
+ * @return array{saved:bool,milestone_id:int,version:int,replayed:bool}
+ */
+ public function save(User $actor, int $roomId, array $data, ?int $milestone = null): array
+ {
+ $command = ['title' => $data['title'], 'responsible_id' => (int) $data['responsible_id'], 'due_date' => $data['due_date'] ?? null,
+ 'status' => $data['status'], 'evidence' => $data['evidence'] ?? null];
+ $creationHash = hash('sha256', json_encode($command, JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $roomId, $data, $milestone, $command, $creationHash) {
+ $exchange = app(PartnershipExchange::class);
+ $context = $exchange->room($actor, $roomId);
+ abort_unless($exchange->owns($actor, $context['partnership']) || $exchange->owns($actor, $context['interest']), 403);
+ $room = DB::table('partnership_rooms')->where('id', $roomId)->lockForUpdate()->first();
+ abort_unless($room !== null, 404);
+ if ($milestone === null && ($data['client_key'] ?? null)) {
+ // The room lock serializes this actor/room key check and its event, including legacy clients.
+ $previous = DB::table('partnership_events')->where('partnership_id', $context['partnership']->id)->where('actor_id', $actor->id)
+ ->where('event_type', 'partnership_milestone.changed.v1')->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $roomId])
+ ->whereRaw("payload->'payload'->>'client_key' = ?", [$data['client_key']])->first(['payload']);
+ if ($previous) {
+ $payload = json_decode($previous->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ abort_unless($payload['creation_hash'] === $creationHash, 409, 'Chave de criação de marco já utilizada com outro conteúdo.');
+ $saved = DB::table('partnership_milestones')->where('room_id', $roomId)->where('id', $payload['milestone_id'])->first();
+ abort_unless($saved !== null, 409, 'O marco original não está disponível para reconciliar a criação.');
+
+ return ['saved' => true, 'milestone_id' => (int) $saved->id, 'version' => (int) $saved->version, 'replayed' => true];
+ }
+ }
+ abort_unless(in_array($room->status, ['agreement_recorded', 'agreed', 'execution'], true), 409, 'O estado da sala não permite alterar marcos.');
+ $responsible = User::query()->whereKey($command['responsible_id'])->first();
+ abort_unless($responsible !== null && ($exchange->owns($responsible, $context['partnership']) || $exchange->owns($responsible, $context['interest'])), 422, 'Responsável deve ser participante identificado.');
+ $previousResponsible = null;
+ $version = 1;
+ if ($milestone !== null) {
+ $existing = DB::table('partnership_milestones')->where('room_id', $roomId)->where('id', $milestone)->lockForUpdate()->first();
+ abort_unless($existing !== null, 404);
+ abort_unless((int) $existing->version === (int) $data['version'], 409, 'O marco foi alterado. Compare com os dados actuais.');
+ $previousResponsible = (int) $existing->responsible_id;
+ $version = (int) $existing->version + 1;
+ DB::table('partnership_milestones')->where('id', $milestone)->update([...$command, 'version' => $version, 'updated_at' => now()]);
+ } else {
+ $milestone = (int) DB::table('partnership_milestones')->insertGetId([...$command, 'room_id' => $roomId, 'created_at' => now(), 'updated_at' => now()]);
+ }
+ $metadata = ['room_id' => $roomId, 'milestone_id' => $milestone, 'status' => $command['status'], 'previous_responsible_id' => $previousResponsible, 'responsible_id' => $command['responsible_id']];
+ if ($version === 1 && ($data['client_key'] ?? null)) {
+ $metadata += ['client_key' => $data['client_key'], 'creation_hash' => $creationHash];
+ }
+ $exchange->event($context['partnership'], $actor, 'partnership_milestone.changed.v1', $metadata, 'Marco atualizado', [$context['partnership']->user_id, $context['interest']->user_id]);
+
+ return ['saved' => true, 'milestone_id' => $milestone, 'version' => $version, 'replayed' => false];
+ });
+ }
+}
diff --git a/app/Services/PartnershipNotifications.php b/app/Services/PartnershipNotifications.php
new file mode 100644
index 00000000..e387b4fd
--- /dev/null
+++ b/app/Services/PartnershipNotifications.php
@@ -0,0 +1,145 @@
+ $payload
+ * @return array
+ */
+ public function context(stdClass $record, array $payload): array
+ {
+ $interest = null;
+ $room = null;
+ if (isset($payload['room_id'])) {
+ $room = DB::table('partnership_rooms')->where('id', $payload['room_id'])->first();
+ if (! $room) {
+ throw new LogicException('Notification room does not exist.');
+ }
+ $interest = DB::table('partnership_interests')->where('id', $room->interest_id)->first();
+ }
+ if (isset($payload['interest_id'])) {
+ $selected = DB::table('partnership_interests')->where('id', $payload['interest_id'])->first();
+ if (! $selected || $interest && (int) $selected->id !== (int) $interest->id) {
+ throw new LogicException('Notification candidacy is inconsistent.');
+ }
+ $interest = $selected;
+ }
+ if ($interest && (int) $interest->partnership_id !== (int) $record->id) {
+ throw new LogicException('Notification belongs to another partnership.');
+ }
+
+ return ['version' => 1, 'partnership' => $this->scope($record), 'interest' => $interest ? $this->scope($interest) : null, 'room_id' => $room ? (int) $room->id : null];
+ }
+
+ /** @return array{id:int,user_id:int,organization_id:string|null} */
+ private function scope(stdClass $record): array
+ {
+ return ['id' => (int) $record->id, 'user_id' => (int) $record->user_id, 'organization_id' => $record->organization_id];
+ }
+
+ /** @return list */
+ public function forUser(User $actor): array
+ {
+ // Filter before the visible limit. An old, inaccessible notice never conceals a newer eligible page.
+ return array_values($this->query($actor)->lazyByIdDesc(100, 'n.id', 'id')->map(fn ($notice) => $this->project($actor, $notice))->filter()->take(50)->all());
+ }
+
+ public function markRead(User $actor, int $id): void
+ {
+ DB::transaction(function () use ($actor, $id): void {
+ $notice = $this->query($actor)->where('n.id', $id)->lockForUpdate()->first();
+ abort_unless($notice && $this->project($actor, $notice) !== null, 404);
+ if ($notice->read_at === null) {
+ DB::table('partnership_notifications')->where('id', $id)->where('user_id', $actor->id)->whereNull('read_at')->update(['read_at' => now()]);
+ }
+ });
+ }
+
+ private function query(User $actor): Builder
+ {
+ return DB::table('partnership_notifications as n')->join('partnership_events as e', 'e.id', '=', 'n.event_id')->where('n.user_id', $actor->id)
+ ->select(['n.id', 'n.title', 'n.read_at', 'e.partnership_id', 'e.event_type', 'e.payload']);
+ }
+
+ /** @return array{id:int,title:string,href:string,read_at:string|null}|null */
+ private function project(User $actor, stdClass $notice): ?array
+ {
+ $envelope = json_decode($notice->payload, true, 512, JSON_THROW_ON_ERROR);
+ $payload = is_array($envelope) && is_array($envelope['payload'] ?? null) ? $envelope['payload'] : [];
+ $record = DB::table('portal_partnerships')->where('id', $notice->partnership_id)->first();
+ if (! $record) {
+ return null;
+ }
+ $context = $payload['_notification_context'] ?? null;
+ if (array_key_exists('_notification_context', $payload)) {
+ if (! is_array($context) || ($context['version'] ?? null) !== 1 || ! $this->knownScope($context['partnership'] ?? null) || (int) $context['partnership']['id'] !== (int) $record->id) {
+ return null;
+ }
+ if (($context['interest'] ?? null) !== null && ! $this->knownScope($context['interest'])) {
+ return null;
+ }
+ } else {
+ $context = $this->legacyContext($notice, $payload);
+ if ($context === null) {
+ return null;
+ }
+ }
+ $interest = null;
+ if (is_array($context['interest'] ?? null)) {
+ $interest = DB::table('partnership_interests')->where('id', $context['interest']['id'])->where('partnership_id', $record->id)->first();
+ if (! $interest) {
+ return null;
+ }
+ }
+ $exchange = app(PartnershipExchange::class);
+ $proponent = is_array($context['partnership'] ?? null) && $exchange->owns($actor, $record, false) && $exchange->owns($actor, (object) $context['partnership'], false);
+ $candidate = $interest && $exchange->owns($actor, $interest, false) && $exchange->owns($actor, (object) $context['interest'], false);
+ if (! $proponent && ! $candidate) {
+ return null;
+ }
+ $href = '/parcerias/'.$record->id;
+ if ($interest) {
+ $href = '/parcerias/candidaturas/'.$interest->id.'/historico';
+ if (is_int($context['room_id'] ?? null) && DB::table('partnership_rooms')->where('id', $context['room_id'])->where('interest_id', $interest->id)->exists()) {
+ $href = '/parcerias/salas/'.$context['room_id'];
+ }
+ }
+
+ return ['id' => (int) $notice->id, 'title' => $notice->title, 'href' => $href, 'read_at' => $notice->read_at];
+ }
+
+ private function knownScope(mixed $scope): bool
+ {
+ return is_array($scope) && is_int($scope['id'] ?? null) && $scope['id'] > 0 && is_int($scope['user_id'] ?? null) && $scope['user_id'] > 0
+ && array_key_exists('organization_id', $scope) && ($scope['organization_id'] === null || is_string($scope['organization_id']) && Str::isUuid($scope['organization_id']));
+ }
+
+ /** @param array $payload
+ * @return array|null
+ */
+ private function legacyContext(stdClass $notice, array $payload): ?array
+ {
+ if (! in_array($notice->event_type, ['partnership_interest.submitted.v1', 'partnership_interest.changed.v1'], true) || ! is_int($payload['interest_id'] ?? null)) {
+ return null;
+ }
+ $snapshot = $notice->event_type === 'partnership_interest.submitted.v1' ? ($payload['submitted'] ?? null) : ($payload['previous'] ?? null);
+ if (! is_array($snapshot) || ! array_key_exists('organization_id', $snapshot)) {
+ return null;
+ }
+ $interest = DB::table('partnership_interests')->where('id', $payload['interest_id'])->where('partnership_id', $notice->partnership_id)->first();
+ if (! $interest) {
+ return null;
+ }
+ $scope = ['id' => (int) $interest->id, 'user_id' => (int) $interest->user_id, 'organization_id' => $snapshot['organization_id']];
+
+ return $this->knownScope($scope) ? ['partnership' => null, 'interest' => $scope, 'room_id' => null] : null;
+ }
+}
diff --git a/app/Services/PartnershipPublication.php b/app/Services/PartnershipPublication.php
new file mode 100644
index 00000000..059217aa
--- /dev/null
+++ b/app/Services/PartnershipPublication.php
@@ -0,0 +1,110 @@
+ ['draft', 'returned', 'rejected'], 'publish' => ['submitted', 'pending'], 'return' => ['submitted', 'pending'], 'reject' => ['submitted', 'pending'], 'suspend' => ['published'], 'archive' => ['draft', 'published', 'suspended', 'rejected'], 'renew' => ['published', 'suspended', 'archived']];
+
+ private const STATES = ['submit' => 'submitted', 'publish' => 'published', 'return' => 'returned', 'reject' => 'rejected', 'suspend' => 'suspended', 'archive' => 'archived', 'renew' => 'draft'];
+
+ private const MODERATION = ['publish', 'return', 'reject', 'suspend'];
+
+ private function permitted(User $actor, stdClass $record, string $action): bool
+ {
+ $owns = app(PartnershipExchange::class)->owns($actor, $record);
+
+ return in_array($action, self::MODERATION, true) ? Gate::forUser($actor)->allows('manage-portal') && ! $owns : $owns;
+ }
+
+ /** @return list */
+ public function actions(?User $actor, stdClass $record): array
+ {
+ $actions = [];
+ foreach (self::ALLOWED as $action => $states) {
+ if ($actor && in_array($record->status, $states, true) && $this->permitted($actor, $record, $action)) {
+ $actions[] = $action;
+ }
+ }
+
+ return $actions;
+ }
+
+ /** @return list */
+ public function commands(?User $actor, stdClass $record): array
+ {
+ if (! $actor) {
+ return [];
+ }
+ $commands = [];
+ $events = DB::table('partnership_events')->where('partnership_id', $record->id)->where('actor_id', $actor->id)->where('event_type', 'like', 'partnership_opportunity.%')->whereRaw("payload->'payload'->>'client_key' IS NOT NULL")->orderBy('aggregate_version')->get(['payload']);
+ foreach ($events as $event) {
+ $data = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ if (is_string($data['client_key'] ?? null) && is_string($data['action'] ?? null) && isset(self::ALLOWED[$data['action']]) && is_int($data['result_version'] ?? null) && $this->permitted($actor, $record, $data['action'])) {
+ $commands[] = ['key' => $data['client_key'], 'action' => $data['action'], 'version' => $data['result_version']];
+ }
+ }
+
+ return $commands;
+ }
+
+ public function transition(User $actor, int $id, int $version, string $action, string $reason, ?string $clientKey = null): stdClass
+ {
+ $reason = trim($reason);
+ $clientKey = $clientKey === null ? null : strtolower($clientKey);
+ Validator::make(['version' => $version, 'reason' => $reason, 'client_key' => $clientKey], ['version' => 'required|integer|min:1', 'reason' => 'required|string|max:2000', 'client_key' => 'nullable|uuid'])->validate();
+ $hash = hash('sha256', json_encode(Arr::sortRecursive(['version' => $version, 'action' => $action, 'reason' => $reason]), JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $id, $version, $action, $reason, $clientKey, $hash) {
+ $record = app(PartnershipExchange::class)->find($id, true);
+ abort_unless($this->permitted($actor, $record, $action), 403, 'A competência actual não permite esta acção sobre a proposta.');
+ if ($clientKey !== null) {
+ $event = DB::table('partnership_events')->where('partnership_id', $id)->where('actor_id', $actor->id)->where('event_type', 'like', 'partnership_opportunity.%')->whereRaw("payload->'payload'->>'client_key' = ?", [$clientKey])->first(['payload']);
+ if ($event) {
+ $data = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ abort_unless(($data['command_hash'] ?? null) === $hash, 409, 'Chave já utilizada com outro conteúdo.');
+ $record->command_replayed = true;
+
+ return $record;
+ }
+ }
+ abort_unless((int) $record->version === $version, 409, 'Proposta alterada; compare antes de decidir.');
+ abort_unless(isset(self::ALLOWED[$action]) && in_array($record->status, self::ALLOWED[$action], true), 409, 'Transição inválida.');
+ if ($action === 'submit') {
+ $payload = json_decode($record->payload, true);
+ Validator::make(['title' => $record->title, 'type' => $record->partnership_type, 'offer' => $record->offer, 'seeking' => $record->seeking, 'consent' => $payload['consent'] ?? false], ['title' => 'required', 'type' => 'required', 'offer' => 'required_without:seeking', 'seeking' => 'required_without:offer', 'consent' => 'accepted'])->validate();
+ }
+ $before = $this->snapshot($record);
+ $status = self::STATES[$action];
+ $moderation = in_array($action, self::MODERATION, true);
+ DB::table('portal_partnerships')->where('id', $id)->update(['status' => $status, 'version' => $version + 1, 'reviewed_by' => $moderation ? $actor->id : $record->reviewed_by, 'published_at' => $action === 'publish' ? now() : $record->published_at, 'updated_at' => now()]);
+ $saved = app(PartnershipExchange::class)->find($id);
+ $metadata = ['from' => $record->status, 'to' => $status, 'reason' => $reason, 'action' => $action, 'result_version' => $version + 1, 'previous' => $before, 'applied' => $this->snapshot($saved)];
+ if ($clientKey !== null) {
+ $metadata += ['client_key' => $clientKey, 'command_hash' => $hash];
+ }
+ app(PartnershipExchange::class)->event($saved, $actor, 'partnership_opportunity.'.$status.'.v1', $metadata, 'Proposta: '.$status, [$record->user_id]);
+ $saved->command_replayed = false;
+
+ return $saved;
+ });
+ }
+
+ /** @return array */
+ public function snapshot(stdClass $record): array
+ {
+ $payload = json_decode($record->payload, true, 512, JSON_THROW_ON_ERROR);
+ unset($payload['_creation_hash']);
+
+ return [...Arr::only((array) $record, ['id', 'user_id', 'organization_id', 'title', 'kind', 'partnership_type', 'sector_id', 'deadline', 'offer', 'seeking', 'version', 'status', 'published_at']),
+ 'payload' => $payload, 'origins' => DB::table('partnership_origins')->where('partnership_id', $record->id)->get(['type', 'target_id'])->map(fn ($row) => (array) $row)->all(),
+ 'locations' => DB::table('partnership_locations')->where('partnership_id', $record->id)->get(['geo_location_id', 'role', 'source_reference'])->map(fn ($row) => (array) $row)->all()];
+ }
+}
diff --git a/app/Services/PartnershipPublicationHistory.php b/app/Services/PartnershipPublicationHistory.php
new file mode 100644
index 00000000..f0f16503
--- /dev/null
+++ b/app/Services/PartnershipPublicationHistory.php
@@ -0,0 +1,195 @@
+ */
+ private array $people = [];
+
+ /** @var array */
+ private array $organizations = [];
+
+ /** @return array */
+ public function page(User $actor, int $id, ?string $before = null): array
+ {
+ ['record' => $record, 'moderator' => $moderator] = $this->context($actor, $id);
+ $boundary = $before === null ? null : $this->decode($before, $actor, $id);
+ $events = $this->events((int) $record->id, $boundary, 11);
+ $page = $events->take(10);
+ $last = $page->last();
+ $base = '/parcerias/'.$id.'/historico';
+ $next = $events->count() > 10 && $last ? $base.'?before='.rawurlencode(Crypt::encryptString(json_encode(['purpose' => 'publication', 'actor' => $actor->id, 'partnership' => $id, 'before' => (int) $last->aggregate_version], JSON_THROW_ON_ERROR))) : null;
+
+ return ['partnership_id' => $id, 'entries' => $page->map(fn ($event) => $this->entry($event, $actor, $id, $moderator))->all(), 'first_url' => $base, 'next_url' => $next, 'older_page' => $before !== null, 'partnership_href' => '/parcerias/'.$id, 'dashboard_href' => '/parcerias/painel'];
+ }
+
+ /** @return array{limit:int,has_more:bool,href:string,entries:list>} */
+ public function summary(User $actor, int $id): array
+ {
+ ['record' => $record, 'moderator' => $moderator] = $this->context($actor, $id);
+ $limit = 5;
+ $events = $this->events((int) $record->id, null, $limit + 1);
+ $entries = array_values($events->take($limit)->map(function ($event) use ($actor, $id, $moderator) {
+ $entry = $this->entry($event, $actor, $id, $moderator);
+
+ return ['version' => $entry['version'], 'restricted' => $entry['restricted'], 'action' => $entry['action'], 'actor_name' => $entry['actor_name'], 'occurred_at' => $entry['occurred_at'], 'reason' => $entry['reason'],
+ 'status_before' => ($entry['previous']['availability'] ?? null) === 'available' ? ($entry['previous']['status'] ?? null) : null,
+ 'status_after' => ($entry['after']['availability'] ?? null) === 'available' ? ($entry['after']['status'] ?? null) : null];
+ })->all());
+
+ return ['limit' => $limit, 'has_more' => $events->count() > $limit, 'href' => '/parcerias/'.$id.'/historico', 'entries' => $entries];
+ }
+
+ /** @return array{record:stdClass,moderator:bool} */
+ private function context(User $actor, int $id): array
+ {
+ $record = app(PartnershipExchange::class)->find($id);
+ $moderator = Gate::forUser($actor)->allows('manage-portal');
+ abort_unless($moderator || app(PartnershipExchange::class)->owns($actor, $record, false), 403, 'Histórico reservado aos responsáveis autorizados pela proposta e à moderação.');
+
+ return ['record' => $record, 'moderator' => $moderator];
+ }
+
+ /** @return Collection */
+ private function events(int $id, ?int $before, int $limit): Collection
+ {
+ return DB::table('partnership_events')->where('partnership_id', $id)->where('event_type', 'like', 'partnership_opportunity.%')->when($before, fn ($q) => $q->where('aggregate_version', '<', $before))->orderByDesc('aggregate_version')->limit($limit)->get(['aggregate_version', 'event_type', 'actor_id', 'occurred_at', 'payload']);
+ }
+
+ private function decode(string $token, User $actor, int $id): int
+ {
+ try {
+ $value = json_decode(Crypt::decryptString($token), true, 512, JSON_THROW_ON_ERROR);
+ } catch (DecryptException|\JsonException) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não é válida. Volte ao início do histórico.']);
+ }
+ if (! is_array($value) || ($value['purpose'] ?? null) !== 'publication' || ($value['actor'] ?? null) !== $actor->id || ($value['partnership'] ?? null) !== $id || ! is_int($value['before'] ?? null) || $value['before'] < 1) {
+ throw ValidationException::withMessages(['before' => 'A referência da página não pertence a esta conta e publicação. Volte ao início do histórico.']);
+ }
+
+ return $value['before'];
+ }
+
+ /** @return array */
+ private function entry(stdClass $event, User $actor, int $id, bool $moderator): array
+ {
+ $envelope = json_decode($event->payload, true, 512, JSON_THROW_ON_ERROR);
+ $data = is_array($envelope) && is_array($envelope['payload'] ?? null) ? $envelope['payload'] : [];
+ $previous = is_array($data['previous'] ?? null) ? $data['previous'] : null;
+ $applied = is_array($data['applied'] ?? null) ? $data['applied'] : null;
+ $version = is_int($data['result_version'] ?? null) ? $data['result_version'] : (is_array($envelope) && is_int($envelope['publication_version'] ?? null) ? $envelope['publication_version'] : null);
+ if ($applied === null) {
+ $scope = $data['_notification_context']['partnership'] ?? null;
+ $applied = is_array($scope) ? $scope : [];
+ $applied['version'] = $version;
+ if (is_string($data['to'] ?? null)) {
+ $applied['status'] = $data['to'];
+ }
+ if (is_array($data['origins'] ?? null)) {
+ $applied['origins'] = $data['origins'];
+ }if (is_array($data['locations'] ?? null)) {
+ $applied['locations'] = $data['locations'];
+ }
+ }
+ if ($previous === null && (is_string($data['from'] ?? null) || is_string($data['previous_status'] ?? null))) {
+ $previous = ['status' => $data['from'] ?? $data['previous_status']];
+ }
+ // A synthetic insertion placeholder is not a prior version of a newly created proposal.
+ if (($data['action'] ?? null) === 'create' && array_key_exists('previous', $data) && $data['previous'] === null) {
+ $previous = null;
+ }
+ $beforeView = $this->snapshot($previous, $actor, $id, $moderator);
+ $afterView = $this->snapshot($applied, $actor, $id, $moderator);
+ $visible = $moderator || $beforeView['availability'] === 'available' || $afterView['availability'] === 'available';
+ $action = is_string($data['action'] ?? null) && in_array($data['action'], ['create', 'edit', 'submit', 'publish', 'return', 'reject', 'suspend', 'archive', 'renew'], true) ? $data['action'] : null;
+
+ return ['version' => $version, 'restricted' => ! $visible, 'action' => $visible ? $action : null, 'actor_name' => $visible ? $this->person((int) $event->actor_id) : null, 'occurred_at' => $visible ? $event->occurred_at : null, 'reason' => $visible && is_string($data['reason'] ?? null) ? $data['reason'] : null, 'previous' => $beforeView, 'after' => $afterView];
+ }
+
+ /** @param array|null $snapshot
+ * @return array
+ */
+ private function snapshot(?array $snapshot, User $actor, int $id, bool $moderator): array
+ {
+ if ($snapshot === null) {
+ return ['availability' => 'not_recorded'];
+ }
+ if (array_key_exists('id', $snapshot) && (! is_int($snapshot['id']) || $snapshot['id'] !== $id)) {
+ return ['availability' => 'scope_unknown'];
+ }
+ $known = is_int($snapshot['id'] ?? null) && $snapshot['id'] === $id && is_int($snapshot['user_id'] ?? null) && $snapshot['user_id'] > 0 && array_key_exists('organization_id', $snapshot) && ($snapshot['organization_id'] === null || is_string($snapshot['organization_id']) && Str::isUuid($snapshot['organization_id']));
+ if (! $moderator && ! $known) {
+ return ['availability' => 'scope_unknown'];
+ }
+ if (! $moderator && ! app(PartnershipExchange::class)->owns($actor, (object) $snapshot, false)) {
+ return ['availability' => 'restricted'];
+ }
+ $fields = [];
+ foreach (['title', 'offer', 'seeking', 'kind', 'partnership_type', 'deadline', 'published_at'] as $key) {
+ if (array_key_exists($key, $snapshot) && ($snapshot[$key] === null || is_string($snapshot[$key]))) {
+ $fields[$key] = $snapshot[$key];
+ }
+ }
+ $payload = is_array($snapshot['payload'] ?? null) ? $snapshot['payload'] : null;
+ foreach (['summary', 'requirements', 'confidentiality', 'availability'] as $key) {
+ if ($payload !== null && array_key_exists($key, $payload) && ($payload[$key] === null || is_string($payload[$key]))) {
+ $fields[$key] = $payload[$key];
+ }
+ }
+ $consent = $payload['consent'] ?? null;
+ $consentKnown = in_array($consent, [true, false, 1, 0, '1', '0', 'yes', 'on'], true);
+ $mandatory = $payload['mandatory'] ?? null;
+ $mandatoryKnown = is_array($mandatory) && array_is_list($mandatory) && count(array_filter($mandatory, 'is_string')) === count($mandatory);
+ $origins = [];
+ foreach (is_array($snapshot['origins'] ?? null) ? $snapshot['origins'] : [] as $origin) {
+ if (is_array($origin) && is_string($origin['type'] ?? null) && $origin['type'] !== '' && is_string($origin['target_id'] ?? null) && $origin['target_id'] !== '') {
+ $origins[] = ['type' => $origin['type'], 'target_id' => $origin['target_id']];
+ }
+ }
+ $locations = [];
+ foreach (is_array($snapshot['locations'] ?? null) ? $snapshot['locations'] : [] as $location) {
+ if (is_array($location) && is_string($location['geo_location_id'] ?? null) && Str::isUuid($location['geo_location_id'])) {
+ $locations[] = ['geo_location_id' => $location['geo_location_id'], 'role' => is_string($location['role'] ?? null) ? $location['role'] : null, 'source_reference' => is_string($location['source_reference'] ?? null) ? $location['source_reference'] : null];
+ }
+ }
+ $organization = $known && is_string($snapshot['organization_id']) ? $snapshot['organization_id'] : null;
+ $originsIncomplete = is_array($snapshot['origins'] ?? null) && count($origins) !== count($snapshot['origins']);
+ $locationsIncomplete = is_array($snapshot['locations'] ?? null) && (count($locations) !== count($snapshot['locations']) || count(array_filter($locations, fn ($location) => $location['role'] === null || $location['source_reference'] === null)) > 0);
+
+ return ['availability' => 'available', 'version' => is_int($snapshot['version'] ?? null) ? $snapshot['version'] : null, 'status' => is_string($snapshot['status'] ?? null) ? $snapshot['status'] : null, 'scope_known' => $known, 'organization_id' => $organization, 'organization_name' => $organization ? $this->organization($organization) : null,
+ 'fields' => $fields, 'sector_recorded' => array_key_exists('sector_id', $snapshot) && ($snapshot['sector_id'] === null || is_int($snapshot['sector_id']) || is_string($snapshot['sector_id'])), 'sector_id' => is_int($snapshot['sector_id'] ?? null) || is_string($snapshot['sector_id'] ?? null) ? (string) $snapshot['sector_id'] : null,
+ 'consent_known' => $consentKnown, 'consent' => $consentKnown ? in_array($consent, [true, 1, '1', 'yes', 'on'], true) : null, 'mandatory_known' => $mandatoryKnown, 'mandatory' => $mandatoryKnown ? $mandatory : [],
+ 'origins_recorded' => is_array($snapshot['origins'] ?? null), 'origins' => $origins, 'origins_incomplete' => $originsIncomplete,
+ 'locations_recorded' => is_array($snapshot['locations'] ?? null), 'locations' => $locations, 'locations_incomplete' => $locationsIncomplete,
+ 'complete' => $known && is_int($snapshot['version'] ?? null) && is_string($snapshot['status'] ?? null) && array_key_exists('title', $fields) && $payload !== null && is_array($snapshot['origins'] ?? null) && ! $originsIncomplete && is_array($snapshot['locations'] ?? null) && ! $locationsIncomplete];
+ }
+
+ private function person(int $id): ?string
+ {
+ if (! array_key_exists($id, $this->people)) {
+ $this->people[$id] = DB::table('users')->where('id', $id)->value('name');
+ }
+
+ return $this->people[$id];
+ }
+
+ private function organization(string $id): ?string
+ {
+ if (! array_key_exists($id, $this->organizations)) {
+ $this->organizations[$id] = DB::table('organizations')->where('id', $id)->value('name');
+ }
+
+ return $this->organizations[$id];
+ }
+}
diff --git a/app/Services/PartnershipRoomUploads.php b/app/Services/PartnershipRoomUploads.php
new file mode 100644
index 00000000..5624e9ff
--- /dev/null
+++ b/app/Services/PartnershipRoomUploads.php
@@ -0,0 +1,69 @@
+getRealPath();
+ abort_unless(is_string($path), 503);
+ $hash = hash_file('sha256', $path);
+ abort_unless(is_string($hash), 503);
+ $commandHash = hash('sha256', json_encode(['sha256' => $hash, 'file_name' => basename($file->getClientOriginalName()), 'shared' => $shared], JSON_THROW_ON_ERROR));
+ $stored = null;
+ try {
+ $result = DB::transaction(function () use ($actor, $roomId, $file, $shared, $clientKey, $hash, $commandHash, &$stored) {
+ $exchange = app(PartnershipExchange::class);
+ $context = $exchange->room($actor, $roomId);
+ abort_unless($exchange->owns($actor, $context['partnership']) || $exchange->owns($actor, $context['interest']), 403);
+ $room = DB::table('partnership_rooms')->where('id', $roomId)->lockForUpdate()->first();
+ abort_unless($room !== null, 404);
+ if ($clientKey !== null) {
+ $previous = DB::table('partnership_events')->where('partnership_id', $context['partnership']->id)->where('actor_id', $actor->id)->where('event_type', 'partnership.document_added.v1')
+ ->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $roomId])->whereRaw("payload->'payload'->>'client_key' = ?", [$clientKey])->first(['payload']);
+ if ($previous) {
+ $payload = json_decode($previous->payload, true, 512, JSON_THROW_ON_ERROR)['payload'];
+ abort_unless($payload['upload_hash'] === $commandHash, 409, 'Chave de envio já utilizada com outro documento ou autorização.');
+ abort_unless(DB::table('partnership_documents')->where('room_id', $roomId)->where('document_id', $payload['document_id'])->where('owner_id', $actor->id)->exists(), 409, 'O envio original não está disponível para reconciliar.');
+
+ return ['uploaded' => true, 'document_id' => $payload['document_id'], 'replayed' => true];
+ }
+ }
+ abort_if(in_array($room->status, ['closed', 'cancelled'], true), 409, 'Sala encerrada.');
+ $documentId = (string) Str::uuid();
+ $stored = $file->storeAs('partnerships/'.$roomId, $documentId, 'local');
+ abort_unless(is_string($stored) && $stored !== '', 503);
+ abort_unless(hash_file('sha256', Storage::disk('local')->path($stored)) === $hash, 503, 'Os bytes armazenados não correspondem ao envio.');
+ DB::table('documents')->insert(['id' => $documentId, 'source_system' => 'partnership-exchange', 'data_classification' => 'restricted', 'file_name' => basename($file->getClientOriginalName()),
+ 'media_type' => $file->getMimeType(), 'storage_key' => $stored, 'sha256' => $hash, 'status' => 'quarantined', 'size_bytes' => $file->getSize(), 'uploaded_by' => $actor->id]);
+ DB::table('partnership_documents')->insert(['room_id' => $roomId, 'document_id' => $documentId, 'owner_id' => $actor->id, 'shared' => $shared]);
+ $metadata = ['room_id' => $roomId, 'document_id' => $documentId, 'shared' => $shared];
+ if ($clientKey !== null) {
+ $metadata += ['client_key' => $clientKey, 'upload_hash' => $commandHash];
+ }
+ $exchange->event($context['partnership'], $actor, 'partnership.document_added.v1', $metadata, 'Documento privado anexado');
+
+ return ['uploaded' => true, 'document_id' => $documentId, 'replayed' => false];
+ });
+ } catch (\Throwable $error) {
+ if (is_string($stored) && str_starts_with($stored, 'partnerships/'.$roomId.'/')) {
+ Storage::disk('local')->delete($stored);
+ }
+ throw $error;
+ }
+ if (! $result['replayed']) {
+ ScanDocumentForMalware::dispatch($result['document_id'])->afterCommit();
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Services/PortalAudit.php b/app/Services/PortalAudit.php
index 864107ec..3eb2fd4d 100644
--- a/app/Services/PortalAudit.php
+++ b/app/Services/PortalAudit.php
@@ -5,24 +5,35 @@ namespace App\Services;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
+use Illuminate\Validation\ValidationException;
class PortalAudit
{
/** @param array $data */
- public static function save(Model $record, array $data, int $actor): void
+ public static function save(Model $record, array $data, int $actor, ?int $expectedVersion = null): void
{
- DB::transaction(function () use ($record, $data, $actor) {
+ DB::transaction(function () use ($record, $data, $actor, $expectedVersion) {
$created = ! $record->exists;
if (! $created) {
$locked = $record->newQuery()->where($record->getKeyName(), $record->getKey())->lockForUpdate()->firstOrFail();
$record->setRawAttributes($locked->getAttributes(), true);
+ if ($expectedVersion !== null && (int) $locked->getAttribute('version_no') !== $expectedVersion) {
+ throw ValidationException::withMessages(['version' => 'Este registo foi alterado por outra operação. Compare os dados actuais antes de continuar; as suas alterações foram conservadas.']);
+ }
}
+ $versionedCrm = in_array($record->getTable(), ['investors', 'contacts', 'leads', 'tasks'], true);
// Exclude free text and personal data from the immutable event payload.
$fields = ['primary_territory_id', 'territory_version', 'version_no', 'status', 'is_active', 'is_featured', 'sort_order', 'sector_id', 'maturity_level',
'estimated_investment_amount', 'estimated_investment_currency', 'owner_user_id', 'assignee_user_id', 'due_at',
'cluster_id', 'project_id', 'corridor_id', 'dossier_id', 'interest_request_id', 'publication_status', 'editor_id', 'reviewer_id', 'role', 'stage', 'value_chain_id', 'from_value_chain_id', 'to_value_chain_id', 'link_type', 'deleted_at'];
$before = array_intersect_key($record->getAttributes(), array_flip($fields));
$record->fill($data);
+ if ($versionedCrm && ! $created && ! $record->isDirty()) {
+ return;
+ }
+ if ($versionedCrm && ! array_key_exists('version_no', $data)) {
+ $record->setAttribute('version_no', $created ? ($record->getAttribute('version_no') ?? 1) : (int) $record->getOriginal('version_no') + 1);
+ }
$changed = array_keys($record->getDirty());
$record->save();
if (! $changed) {
diff --git a/app/Services/PortalProfileAccess.php b/app/Services/PortalProfileAccess.php
index fbdf60ea..ee81b574 100644
--- a/app/Services/PortalProfileAccess.php
+++ b/app/Services/PortalProfileAccess.php
@@ -381,8 +381,12 @@ class PortalProfileAccess
}
}
+ $support = app(OpportunityTechnicalSupport::class);
+ $hasSupport = $support->allows($actor);
+
return ['contexts' => $contexts, 'internalPromoter' => $internalPromoter, 'mine' => $contexts ? '/minhas-oportunidades' : null, 'create' => $contexts ? '/minhas-oportunidades/create' : null,
'request' => '/perfil/promotor', 'review' => $this->available() && ($this->has($actor, 'validator') || $this->has($actor, 'publisher') || $this->has($actor, 'auditor') || $this->superuser($actor)) ? '/minhas-oportunidades' : null,
+ 'technicalSupport' => $hasSupport ? '/suporte-tecnico/incidentes' : null, 'technicalSupportUnread' => $hasSupport ? $support->unreadCount($actor) : null,
'audit' => $this->has($actor, 'auditor') || $this->superuser($actor) ? '/perfis/auditoria' : null, 'administration' => $this->superuser($actor) ? '/perfis/gestao' : null];
}
diff --git a/app/Services/PortalProfileAdministration.php b/app/Services/PortalProfileAdministration.php
index 059e2aa7..44d1fb72 100644
--- a/app/Services/PortalProfileAdministration.php
+++ b/app/Services/PortalProfileAdministration.php
@@ -25,7 +25,10 @@ class PortalProfileAdministration
if (($input['internal_designation'] ?? false) === true) {
return app(PortalInternalDesignation::class)->grant($actor, $input);
}
- $data = Validator::make($input, ['user_id' => 'required|integer|exists:users,id', 'role' => ['required', Rule::in(['promoter', 'validator', 'publisher', 'auditor'])],
+ if (($input['role'] ?? null) === 'technical_support') {
+ abort_unless(app(OpportunityTechnicalSupport::class)->installed(), 503, 'Instale a actualização do perfil de Suporte técnico antes de o atribuir.');
+ }
+ $data = Validator::make($input, ['user_id' => 'required|integer|exists:users,id', 'role' => ['required', Rule::in(['promoter', 'validator', 'publisher', 'auditor', 'technical_support'])],
'organization_id' => 'nullable|uuid|exists:organizations,id', 'opportunity_types' => 'required|array|min:1', 'opportunity_types.*' => ['required', Rule::in(OpportunityManagement::CATEGORIES)],
'responsibilities' => 'sometimes|array', 'responsibilities.*' => ['required', Rule::in(['validation_coordinator', 'technical_reviewer', 'legal_reviewer', 'appeal_reviewer', 'publication_coordinator'])],
'expires_at' => 'nullable|date|after:now', 'reason' => 'required|string|min:20|max:1000'])->validate();
@@ -56,6 +59,7 @@ class PortalProfileAdministration
public function insertGrant(string $id, User $approver, array $data): void
{
DB::table('portal_role_assignments')->insert(['id' => $id, 'user_id' => $data['user_id'], 'role' => $data['role'], 'organization_id' => $data['organization_id'] ?? null,
+ 'policy_version' => $data['role'] === 'technical_support' ? 'profiles-technical-support-20261103' : PortalProfileAccess::VERSION,
'opportunity_types' => json_encode(array_values(array_unique($data['opportunity_types'])), JSON_THROW_ON_ERROR), 'responsibilities' => json_encode($data['responsibilities'] ?? [], JSON_THROW_ON_ERROR),
'source' => $data['source'] ?? 'independent-administration', 'request_id' => $data['request_id'] ?? null, 'approved_by' => $approver->id,
'starts_at' => now(), 'expires_at' => $data['expires_at'] ?? null, 'created_at' => now(), 'updated_at' => now()]);
diff --git a/app/Services/PortalProfileInstallation.php b/app/Services/PortalProfileInstallation.php
index 38bde626..d42a7399 100644
--- a/app/Services/PortalProfileInstallation.php
+++ b/app/Services/PortalProfileInstallation.php
@@ -21,11 +21,101 @@ class PortalProfileInstallation
public function fingerprint(): string
{
$files = [...PortalProfileAccess::fingerprintFiles(), __FILE__, config_path('portal_profiles.php'),
- app_path('Http/Controllers/PortalProfileInstallationController.php'), resource_path('js/pages/profiles/installation.tsx'), resource_path('js/pages/profiles/bootstrap-confirmation.tsx'), base_path('routes/web.php')];
+ app_path('Services/TechnicalSupportProfileSchema.php'), app_path('Services/OpportunityTechnicalSupport.php'), app_path('Services/TechnicalIncidentHandling.php'), app_path('Services/OpportunityTechnicalIncidents.php'), app_path('Services/OpportunityWorkflowExecution.php'), app_path('Exceptions/OpportunityWorkflowUnavailable.php'), app_path('Http/Controllers/TechnicalSupportController.php'),
+ database_path('migrations/'.TechnicalSupportProfileSchema::MIGRATION.'.php'), resource_path('js/pages/profiles/support-installation.tsx'), resource_path('js/lib/profile-support-installation.ts'), resource_path('js/lib/page-preparation-guard.ts'), resource_path('js/lib/portal-api.ts'), resource_path('js/lib/operation-key.ts'), resource_path('js/pages/profiles/technical-support.tsx'), resource_path('js/pages/profiles/technical-incident.tsx'), resource_path('js/components/technical-incident-handling.tsx'), resource_path('js/components/opportunity-technical-incidents.tsx'), resource_path('js/lib/technical-incident-handling.ts'), resource_path('js/lib/technical-incident-labels.ts'),
+ app_path('Jobs/ScanDocumentForMalware.php'), app_path('Services/Malware/DocumentScanAttempts.php'), app_path('Services/Malware/DocumentScanDelivery.php'), app_path('Services/Malware/DocumentScanRetry.php'), app_path('Http/Controllers/DocumentMalwareController.php'), resource_path('js/pages/management/shared.tsx'), resource_path('js/pages/investment/zone-attachments.tsx'), app_path('Services/OpportunityScanDispatch.php'), app_path('Services/OpportunityTechnicalExecution.php'), app_path('Services/OpportunityResourceFileCleanup.php'), resource_path('js/components/technical-incident-notice.tsx'), app_path('Http/Controllers/PortalProfileInstallationController.php'), resource_path('js/pages/profiles/installation.tsx'), resource_path('js/pages/profiles/bootstrap-confirmation.tsx'), base_path('routes/web.php')];
return hash('sha256', json_encode(array_map(fn ($path) => hash_file('sha256', $path), array_unique($files)), JSON_THROW_ON_ERROR));
}
+ /** @return array{verified:bool,date:string|null,fingerprint:string|null} */
+ private function readiness(\stdClass $identity, string $code): array
+ {
+ $path = config('portal_profiles.proof_directory').'/readiness.json';
+ $bytes = is_file($path) && is_readable($path) ? file_get_contents($path) : false;
+ $decoded = is_string($bytes) ? json_decode($bytes, true) : null;
+ $proof = is_array($decoded) ? $decoded : [];
+ $date = is_string($proof['verified_at'] ?? null) ? $proof['verified_at'] : null;
+ $timestamp = $date !== null ? strtotime($date) : false;
+ $target = is_array($proof['target'] ?? null) ? $proof['target'] : [];
+ $port = $target['port'] ?? null;
+ $dump = $proof['dump_path'] ?? null;
+ $files = $proof['files_path'] ?? null;
+ $verified = $timestamp !== false && $timestamp >= time() - 86400 && $timestamp <= time() && ($proof['code_hash'] ?? null) === $code && ($target['database'] ?? null) === $identity->database
+ && (is_int($port) || (is_string($port) && ctype_digit($port))) && (int) $port === (int) $identity->port
+ && ($proof['restore_verified'] ?? null) === true && ($proof['files_verified'] ?? null) === true && ($proof['compatibility_verified'] ?? null) === true && ($proof['qa_passed'] ?? null) === true
+ && is_string($dump) && is_file($dump) && is_readable($dump) && hash_file('sha256', $dump) === ($proof['dump_sha256'] ?? null)
+ && is_string($files) && is_file($files) && is_readable($files) && hash_file('sha256', $files) === ($proof['files_sha256'] ?? null);
+
+ return ['verified' => $verified, 'date' => $date, 'fingerprint' => is_string($bytes) ? hash('sha256', $bytes) : null];
+ }
+
+ /** @return array */
+ public function supportPreview(User $actor): array
+ {
+ $this->authorize($actor);
+ $base = $this->preview($actor);
+ $schema = app(TechnicalSupportProfileSchema::class)->inspect();
+ $dependencies = ['profiles_installed' => $base['installed'], 'profiles_consistent' => $base['consistent'], ...$base['dependencies']];
+ $readiness = $this->readiness($base['target'], $base['code_hash']);
+ $action = $schema['installed'] ? 'none' : ($schema['repairable'] ? 'repair_known_base' : ($schema['state'] === 'base' && ! $schema['ledger'] ? 'install' : 'blocked'));
+ $plan = ['target' => $base['target'], 'actorId' => $actor->id, 'code_hash' => $base['code_hash'], 'migration' => TechnicalSupportProfileSchema::MIGRATION, 'schema' => $schema,
+ 'dependencies' => $dependencies, 'installed' => $schema['installed'], 'consistent' => $schema['consistent'], 'repairable' => $schema['repairable'], 'action' => $action,
+ 'ready' => ! in_array(false, $dependencies, true) && ($schema['consistent'] || $schema['repairable']) && $readiness['verified'] && $action !== 'blocked',
+ 'backupDate' => $readiness['date'], 'readiness_fingerprint' => $readiness['fingerprint'],
+ 'changes' => ['Acrescenta Suporte técnico aos papéis reconhecidos. Atribuir o perfil é uma operação posterior na Gestão de perfis.', 'Conserva contas, atribuições, oportunidades, incidentes e histórico.', 'Aplica apenas a actualização de perfis indicada neste destino.'],
+ 'rollback' => 'A reversão da actualização exige preservar atribuições de Suporte técnico, incluindo as históricas; o downgrade recusa removê-las.'];
+ $commands = [];
+ foreach (DB::table('audit_events')->where('source_system', 'portal-profile-installation')->where('action', 'technical-support-install')->where('actor_user_id', $actor->id)->get(['correlation_id', 'after_data']) as $event) {
+ $data = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR);
+ $commands[] = ['key' => $event->correlation_id, 'code_hash' => $data['code_hash'] ?? null];
+ }
+ $plan['hash'] = hash('sha256', json_encode($plan, JSON_THROW_ON_ERROR));
+ $plan['commands'] = $commands;
+ $plan['mfa_confirmed'] = $this->access->mfa($actor);
+
+ return $plan;
+ }
+
+ /** @param array $input
+ * @return array */
+ public function applySupport(User $actor, array $input): array
+ {
+ $this->authorize($actor, true);
+ $data = Validator::make($input, ['hash' => 'required|string|size:64', 'confirm' => 'required|accepted', 'idempotency_key' => 'required|uuid', 'reason' => 'required|string|min:20|max:1000'])->validate();
+ $data['idempotency_key'] = strtolower($data['idempotency_key']);
+ $data['confirm'] = true;
+ $data['reason'] = trim($data['reason']);
+ Validator::make(['reason' => $data['reason']], ['reason' => 'required|string|min:20|max:1000'])->validate();
+
+ return $this->receipt($actor, 'technical-support-install', $data, function () use ($actor, $data) {
+ $plan = $this->supportPreview($actor);
+ abort_unless(hash_equals($plan['hash'], $data['hash']), 409, 'O plano mudou. Consulte e compare a prévia actual.');
+ abort_unless($plan['consistent'] || $plan['repairable'], 409, 'A estrutura dos perfis diverge da versão reconhecida. Preserve os dados e reconcilie a divergência.');
+ abort_unless(! in_array(false, $plan['dependencies'], true), 422, 'Instale e confira primeiro a base dos perfis e as suas dependências.');
+ $identity = ['actor_id' => $actor->id, 'command_key' => $data['idempotency_key'], 'target' => $plan['target']];
+ if ($plan['installed']) {
+ return [...$identity, 'installed' => true, 'changed' => false, 'migration' => TechnicalSupportProfileSchema::MIGRATION, 'code_hash' => $plan['code_hash'], 'mode' => 'already_installed', 'flags_changed' => false, 'privileges_granted' => false];
+ }
+ abort_unless($plan['ready'] && in_array($plan['action'], ['install', 'repair_known_base'], true), 422, 'Provas actuais de backup, restauro, ficheiros e compatibilidade são necessárias.');
+ $previousFlag = config('portal_profiles.authenticated_installation');
+ config(['portal_profiles.authenticated_installation' => true]);
+ try {
+ if ($plan['action'] === 'repair_known_base') {
+ (require database_path('migrations/'.TechnicalSupportProfileSchema::MIGRATION.'.php'))->up();
+ } else {
+ abort_unless(Artisan::call('migrate', ['--path' => 'database/migrations/'.TechnicalSupportProfileSchema::MIGRATION.'.php', '--force' => true]) === 0, 500, 'A actualização dos perfis falhou.');
+ }
+ } finally {
+ config(['portal_profiles.authenticated_installation' => $previousFlag]);
+ }
+ $after = app(TechnicalSupportProfileSchema::class)->inspect();
+ abort_unless($after['installed'] && $after['consistent'], 500, 'A verificação da actualização falhou; a transacção será revertida.');
+
+ return [...$identity, 'installed' => true, 'changed' => true, 'migration' => TechnicalSupportProfileSchema::MIGRATION, 'code_hash' => $plan['code_hash'], 'mode' => $plan['action'], 'flags_changed' => false, 'privileges_granted' => false];
+ });
+ }
+
public function designatedBootstrap(User $actor): bool
{
$emails = config('portal_profiles.bootstrap_designated_emails', []);
@@ -78,16 +168,8 @@ class PortalProfileInstallation
'existing_identity_organization_audit' => Schema::hasTable('users') && Schema::hasTable('organizations') && Schema::hasTable('memberships') && Schema::hasTable('audit_events'),
];
$code = $this->fingerprint();
- $proofPath = config('portal_profiles.proof_directory').'/readiness.json';
- $proofBytes = is_file($proofPath) ? file_get_contents($proofPath) : false;
- $proof = is_string($proofBytes) ? json_decode($proofBytes, true) : [];
- $proof = is_array($proof) ? $proof : [];
- $fresh = isset($proof['verified_at']) && strtotime($proof['verified_at']) >= time() - 86400;
- $evidence = $fresh && ($proof['code_hash'] ?? '') === $code && ($proof['target']['database'] ?? '') === $identity->database
- && (int) ($proof['target']['port'] ?? 0) === (int) $identity->port && ($proof['restore_verified'] ?? false) && ($proof['files_verified'] ?? false)
- && ($proof['compatibility_verified'] ?? false) && ($proof['qa_passed'] ?? false)
- && is_file($proof['dump_path'] ?? '') && hash_file('sha256', $proof['dump_path']) === ($proof['dump_sha256'] ?? null)
- && is_file($proof['files_path'] ?? '') && hash_file('sha256', $proof['files_path']) === ($proof['files_sha256'] ?? null);
+ $readiness = $this->readiness($identity, $code);
+ $evidence = $readiness['verified'];
$ready = $consistent && ! in_array(false, $dependencies, true) && $evidence;
$pair = $installed ? DB::table('portal_superuser_pair')->where('id', 1)->first() : null;
$bootstrap = ['initialized' => $pair !== null, 'holders' => $pair ? [(int) $pair->first_user_id, (int) $pair->second_user_id] : [], 'version' => $pair?->version,
@@ -96,8 +178,9 @@ class PortalProfileInstallation
->where(fn ($q) => $q->where('requested_by', $actor->id)->orWhere('subject_user_id', $actor->id))->first() : null;
$bootstrap['pending'] = $pending ? ['approval_id' => $pending->id, 'confirmation_url' => '/management/profile-install/bootstrap/'.$pending->id, 'expires_at' => $pending->expires_at] : null;
$plan = ['target' => $identity, 'code_hash' => $code, 'installed' => $installed, 'consistent' => $consistent, 'ledger' => $ledger, 'schema' => $schema,
- 'dependencies' => $dependencies, 'ready' => $ready, 'backupDate' => $proof['verified_at'] ?? null, 'bootstrap' => $bootstrap,
+ 'dependencies' => $dependencies, 'ready' => $ready, 'backupDate' => $readiness['date'], 'readiness_fingerprint' => $readiness['fingerprint'], 'bootstrap' => $bootstrap,
'path_190000_installed' => DB::table('migrations')->where('migration', '2026_10_09_190000_prepare_investor_path')->exists(),
+ 'technicalSupportUpdateUrl' => '/management/profile-install/technical-support',
'migration' => self::MIGRATION, 'changes' => ['Quatro tabelas, uma coluna em users e três em opportunities; zero contas e zero atribuições automáticas.',
'030000 precede esta ação; 190000 continua etapa posterior do percurso, sem dependência DDL desta migração.', 'Nenhuma flag ativada, dado publicado, titular escolhido ou privilégio legado removido.'],
'rollback' => 'DDL e ledger são atómicos em PostgreSQL. Se vazio, down deve remover todas as colunas adicionadas; se houver uso/histórico, preservar e restaurar backup verificado, sem rollback destrutivo.'];
diff --git a/app/Services/ProactiveSupply.php b/app/Services/ProactiveSupply.php
index a869b0fa..06b46823 100644
--- a/app/Services/ProactiveSupply.php
+++ b/app/Services/ProactiveSupply.php
@@ -4,6 +4,7 @@ namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
+use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
@@ -70,13 +71,89 @@ final class ProactiveSupply
// Exact repeated observations are retained in storage, counted separately.
$total = (clone $base)->whereNull('o.duplicate_of')->count();
$duplicates = (clone $base)->whereNotNull('o.duplicate_of')->count();
- $rows = (clone $base)->whereNull('o.duplicate_of')->orderBy('o.name')->orderBy('o.id')->offset(($page - 1) * 25)->limit(25)->get(['o.id', 'o.entity_key', 'o.name', 'o.province', 'o.district', 'o.territory_id', 'o.territory_resolution', 'o.cae', 'o.activity', 'o.sector', 'o.source_date', 'o.sheet', 'o.row_number', 'o.source_hash', 'o.identity_conflict', 's.name as source_name', 's.period as source_period', 's.imported_at']);
+ $rows = (clone $base)->whereNull('o.duplicate_of')->orderBy('o.name')->orderBy('o.id')->offset(($page - 1) * 25)->limit(25)->get(['o.id', 'o.name', 'o.province', 'o.district', 'o.territory_id', 'o.territory_resolution', 'o.cae', 'o.activity', 'o.sector', 'o.source_date', 'o.sheet', 'o.row_number', 'o.source_hash', 'o.identity_conflict', 's.name as source_name', 's.period as source_period', 's.imported_at']);
$coverage = DB::table('proactive_supply_observations')->selectRaw("count(*) FILTER (WHERE territory_id IS NULL) AS unmapped, count(*) FILTER (WHERE territory_resolution='province_only_district_unknown') AS province_only")->first();
return ['installed' => true, 'rows' => $rows, 'total' => $total, 'duplicate_sightings' => $duplicates, 'page' => $page, 'per_page' => 25, 'sectors' => $sectors, 'territory_coverage' => $coverage, 'limitations' => self::LIMITATIONS, 'status' => $total ? 'Registos documentais encontrados; não equivalem a empresas únicas ou oferta actual confirmada.' : 'Informação insuficiente nesta base e nestes filtros.'];
});
}
+ /** Review all retained observations, including those that cannot enter a territorial query.
+ * @param array $input
+ * @return array */
+ public function review(User $actor, array $input, ?Opportunity $record = null): array
+ {
+ $this->authorize($actor, $record);
+ $filters = Validator::make($input, [
+ 'source_hash' => ['nullable', 'string', 'regex:/^[a-f0-9]{64}$/D'],
+ 'observation_id' => ['nullable', 'string', 'regex:/^[a-f0-9]{64}$/D'],
+ 'q' => ['nullable', 'string', 'max:120'],
+ 'status' => ['nullable', Rule::in(['all', 'unmapped', 'ambiguous', 'territory_unavailable', 'identity_conflict', 'repeated', 'unclassified', 'unnamed'])],
+ 'page' => ['nullable', 'integer', 'min:1', 'max:100000'],
+ ])->validate();
+ $filters['status'] = $filters['status'] ?? 'unmapped';
+ $filters['page'] = (int) ($filters['page'] ?? 1);
+ if (! Schema::hasTable('proactive_supply_observations') || ! Schema::hasTable('proactive_supply_sources')) {
+ return ['installed' => false, 'filters' => $filters, 'sources' => [], 'coverage' => null, 'rows' => [], 'total' => null, 'per_page' => 25,
+ 'limitations' => self::LIMITATIONS, 'status' => 'Base interna ainda não carregada neste ambiente.'];
+ }
+
+ return $this->read($actor, function () use ($filters): array {
+ $sources = DB::table('proactive_supply_sources')->orderBy('name')->orderBy('sha256')->get(['sha256', 'name', 'period', 'limitations', 'imported_at']);
+ if (! empty($filters['source_hash']) && ! $sources->contains('sha256', $filters['source_hash'])) {
+ throw ValidationException::withMessages(['source_hash' => 'A origem escolhida não está disponível nesta base interna.']);
+ }
+ $base = DB::table('proactive_supply_observations as o')->join('proactive_supply_sources as s', 's.sha256', '=', 'o.source_hash')
+ ->leftJoinSub(app(InvestmentGeography::class)->publicReferences()->select('id', 'name', 'location_type'), 'territory', 'territory.id', '=', 'o.territory_id');
+ if (! empty($filters['source_hash'])) {
+ $base->where('o.source_hash', $filters['source_hash']);
+ }
+ $counts = (clone $base)->selectRaw("count(*) AS observations,
+ count(*) FILTER (WHERE o.duplicate_of IS NULL) AS distinct_observations,
+ count(*) FILTER (WHERE o.duplicate_of IS NOT NULL) AS repeated,
+ count(*) FILTER (WHERE o.territory_id IS NULL) AS unmapped,
+ count(*) FILTER (WHERE o.territory_resolution='ambiguous') AS ambiguous,
+ count(*) FILTER (WHERE o.territory_id IS NOT NULL AND territory.id IS NULL) AS territory_unavailable,
+ count(*) FILTER (WHERE o.identity_conflict) AS identity_conflict,
+ count(*) FILTER (WHERE btrim(o.activity)='') AS unclassified,
+ count(*) FILTER (WHERE btrim(o.name) IN ('','Denominação não indicada')) AS unnamed")->first();
+ $coverage = array_map(fn ($value) => (int) $value, (array) $counts);
+ $this->reviewStatus($base, $filters['status']);
+ if (! empty($filters['observation_id'])) {
+ $base->where('o.id', $filters['observation_id']);
+ }
+ if (! empty($filters['q'])) {
+ $term = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], mb_strtolower(Str::ascii(trim($filters['q']))));
+ $base->whereRaw("translate(lower(concat_ws(' ',o.name,o.province,o.district,o.cae,o.activity)),'áàâãéêíóôõúç','aaaaeeiooouc') LIKE ? ESCAPE '\\'", ['%'.$term.'%']);
+ }
+ $total = (clone $base)->count();
+ $filters['page'] = min($filters['page'], max(1, (int) ceil($total / 25)));
+ $rows = $base->orderBy('o.source_hash')->orderBy('o.sheet')->orderBy('o.row_number')->orderBy('o.id')
+ ->offset(($filters['page'] - 1) * 25)->limit(25)
+ ->get(['o.id', 'o.name', 'o.province', 'o.district', 'o.territory_id', 'o.territory_resolution', 'o.cae', 'o.activity', 'o.sector',
+ 'o.source_date', 'o.sheet', 'o.row_number', 'o.source_hash', 'o.identity_conflict', 'o.duplicate_of',
+ 's.name as source_name', 's.period as source_period', 's.imported_at', 'territory.name as canonical_territory', 'territory.location_type as canonical_type']);
+
+ return ['installed' => true, 'filters' => $filters, 'sources' => $sources, 'coverage' => $coverage, 'rows' => $rows,
+ 'total' => $total, 'per_page' => 25, 'limitations' => self::LIMITATIONS,
+ 'status' => $total ? 'Observações administrativas para conferência; não são empresas únicas nem prova de actividade actual.' : 'Informação insuficiente nesta base e nestes filtros.'];
+ });
+ }
+
+ private function reviewStatus(Builder $query, string $status): void
+ {
+ match ($status) {
+ 'unmapped' => $query->whereNull('o.territory_id'),
+ 'ambiguous' => $query->where('o.territory_resolution', 'ambiguous'),
+ 'territory_unavailable' => $query->whereNotNull('o.territory_id')->whereNull('territory.id'),
+ 'identity_conflict' => $query->where('o.identity_conflict', true),
+ 'repeated' => $query->whereNotNull('o.duplicate_of'),
+ 'unclassified' => $query->whereRaw("btrim(o.activity)=''"),
+ 'unnamed' => $query->whereRaw("btrim(o.name) IN ('','Denominação não indicada')"),
+ default => $query,
+ };
+ }
+
/** Resolve server-side source lineage; a caller cannot fabricate an internal observation.
* @param array $input
* @return array
diff --git a/app/Services/ProductExperiments.php b/app/Services/ProductExperiments.php
new file mode 100644
index 00000000..d6d0071a
--- /dev/null
+++ b/app/Services/ProductExperiments.php
@@ -0,0 +1,307 @@
+ */
+ public function catalogue(User $actor): array
+ {
+ abort_unless($actor->can('manage-portal'), 403);
+ $today = CarbonImmutable::now('UTC')->toDateString();
+ $report = $this->metrics->report($actor, ['from' => $today, 'to' => $today]);
+
+ return ['definition_version' => $report['definition_version'], 'services' => $report['services'], 'items' => array_map(fn ($m) => Arr::only($m, ['id', 'title', 'unit', 'source', 'limits']), $report['metrics'])];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function listing(User $actor, array $input): array
+ {
+ abort_unless($actor->can('manage-portal'), 403);
+ $v = Validator::make($input, ['page' => 'nullable|integer|min:1', 'state' => ['nullable', Rule::in(array_keys(config('product-experiments.states')))]])->validate();
+ $base = ['installed' => $this->available(), 'states' => config('product-experiments.states'), 'filters' => ['state' => $v['state'] ?? '']];
+ if (! $base['installed']) {
+ return [...$base, 'items' => [], 'page' => 1, 'pages' => 1, 'total' => 0];
+ }
+ $q = DB::table('product_experiments as p')->join('product_experiment_revisions as r', fn ($join) => $join->on('r.experiment_id', '=', 'p.id')->on('r.version', '=', 'p.version'))
+ ->when(! empty($v['state']), fn ($q) => $q->where('p.state', $v['state']));
+ $total = (clone $q)->count();
+ $pages = max(1, (int) ceil($total / 25));
+ $page = min((int) ($v['page'] ?? 1), $pages);
+ $items = $q->orderByDesc('p.updated_at')->orderBy('p.id')->forPage($page, 25)->get(['p.id', 'p.version', 'p.state', 'p.updated_at', 'r.snapshot'])->map(function ($row) {
+ $snapshot = $this->decode($row->snapshot);
+
+ return ['id' => $row->id, 'version' => (int) $row->version, 'state' => $row->state, 'at' => $row->updated_at, 'title' => $snapshot['values']['title'], 'hypothesis' => $snapshot['values']['hypothesis']];
+ })->all();
+
+ return [...$base, 'items' => $items, 'page' => $page, 'pages' => $pages, 'total' => $total];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function view(User $actor, ?string $id, array $input = []): array
+ {
+ abort_unless($actor->can('manage-portal'), 403);
+ $v = Validator::make($input, ['revision' => 'nullable|integer|min:1', 'history_before' => 'nullable|integer|min:1'])->validate();
+ $base = ['installed' => $this->available(), 'id' => $id, 'states' => config('product-experiments.states'), 'changeKinds' => config('product-experiments.change_kinds'), 'decisions' => config('product-experiments.decisions'), 'labels' => config('product-experiments.fields'), 'catalogue' => $this->catalogue($actor)];
+ if ($id === null) {
+ return [...$base, 'currentVersion' => 0, 'historical' => false, 'document' => null, 'values' => $this->defaults(), 'history' => [], 'historyNext' => null];
+ }
+ abort_unless($base['installed'], 503, 'O registo de experiências ainda não está disponível neste destino.');
+ $row = DB::table('product_experiments')->where('id', $id)->firstOrFail();
+ $revision = (int) ($v['revision'] ?? $row->version);
+ $selected = DB::table('product_experiment_revisions')->where('experiment_id', $id)->where('version', $revision)->firstOrFail();
+ $history = DB::table('product_experiment_revisions')->where('experiment_id', $id)->when(! empty($v['history_before']), fn ($q) => $q->where('version', '<', $v['history_before']))->orderByDesc('version')->limit(26)->get(['version', 'created_at', 'snapshot']);
+ $next = $history->count() > 25 ? (int) $history[24]->version : null;
+ $document = $this->decode($selected->snapshot);
+ $historical = $revision !== (int) $row->version;
+ $vocabulary = $historical ? $document['vocabulary'] : config('product-experiments');
+
+ return [...$base, 'states' => $vocabulary['states'], 'changeKinds' => $vocabulary['change_kinds'], 'decisions' => $vocabulary['decisions'], 'labels' => $vocabulary['fields'], 'currentVersion' => (int) $row->version, 'historical' => $historical, 'document' => $document, 'values' => $document['values'], 'historyNext' => $next,
+ 'history' => $history->take(25)->map(function ($r) {
+ $s = $this->decode($r->snapshot);
+
+ return ['version' => (int) $r->version, 'at' => $r->created_at, 'actor' => $s['actor']['name'], 'state' => $s['values']['state'], 'reason' => $s['reason']];
+ })->all()];
+ }
+
+ /** @return array */
+ private function defaults(): array
+ {
+ $values = [];
+ foreach (config('product-experiments.fields') as $key => $label) {
+ if (! is_string($key)) {
+ throw new \LogicException('Experiment field identifiers must be strings.');
+ }
+ $values[$key] = '';
+ }
+
+ return [...$values, 'state' => 'draft'];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function save(User $actor, ?string $id, array $input): array
+ {
+ abort_unless($actor->can('manage-portal'), 403);
+ abort_unless($this->available(), 503, 'O registo de experiências ainda não está disponível neste destino.');
+ $v = Validator::make($input, ['version' => ['required', 'integer', $id === null ? 'in:0' : 'min:1'], 'operation_key' => 'required|uuid',
+ 'reason' => [Rule::requiredIf($id !== null || ($input['values']['state'] ?? null) === 'cancelled'), 'nullable', 'string', 'min:3', 'max:3000'],
+ 'values' => ['required', 'array:'.implode(',', array_keys(config('product-experiments.fields')))], 'values.*' => 'nullable|string|max:5000',
+ 'values.state' => ['required', Rule::in(array_keys(config('product-experiments.states')))],
+ 'values.change_kind' => ['nullable', Rule::in(array_keys(config('product-experiments.change_kinds')))],
+ 'values.decision' => ['nullable', Rule::in(array_keys(config('product-experiments.decisions')))],
+ 'values.title' => 'nullable|string|max:200', 'values.reference' => 'nullable|string|max:1500',
+ 'values.indicator_id' => 'nullable|string|max:100', 'values.indicator_unit' => 'nullable|string|max:100',
+ 'values.period_from' => 'nullable|date_format:Y-m-d', 'values.period_to' => 'nullable|date_format:Y-m-d',
+ 'values.observed_from' => 'nullable|date_format:Y-m-d', 'values.observed_to' => 'nullable|date_format:Y-m-d',
+ 'confirm_plan_change' => 'sometimes|boolean', 'confirm_observation_plan' => 'sometimes|boolean', 'refresh_indicator' => 'sometimes|boolean', 'attach_report' => 'sometimes|boolean', 'remove_report' => 'sometimes|boolean',
+ 'indicator_definition_version' => 'nullable|string|max:100'])->validate();
+ $values = $this->defaults();
+ foreach ($v['values'] as $key => $value) {
+ $values[$key] = trim($value ?? '');
+ }
+ $this->validateValues($values);
+ $command = ['version' => (int) $v['version'], 'operation_key' => $v['operation_key'], 'reason' => trim($v['reason'] ?? ''), 'values' => $values, 'indicator_definition_version' => $v['indicator_definition_version'] ?? null];
+ foreach (['confirm_plan_change', 'confirm_observation_plan', 'refresh_indicator', 'attach_report', 'remove_report'] as $flag) {
+ $command[$flag] = (bool) ($v[$flag] ?? false);
+ }
+ $hash = $this->hash($command);
+ $existing = $id === null ? DB::table('product_experiments')->where('created_by', $actor->id)->where('creation_key', $v['operation_key'])->first() : DB::table('product_experiments')->where('id', $id)->firstOrFail();
+ if ($existing) {
+ $replay = DB::table('product_experiment_revisions')->where('experiment_id', $existing->id)->where('actor_id', $actor->id)->where('operation_key', $v['operation_key'])->first();
+ if ($replay) {
+ abort_unless(hash_equals($replay->request_hash, $hash), 409, 'Esta chave já foi usada para conteúdo diferente.');
+
+ return ['id' => $existing->id, 'version' => (int) $replay->version, 'replayed' => true];
+ }
+ }
+
+ // Capture an optional operational report in its own read-only consistent transaction, before mutation.
+ $report = null;
+ if ($v['attach_report'] ?? false) {
+ if (($v['remove_report'] ?? false) || ! $values['observed_from'] || ! $values['observed_to']) {
+ throw ValidationException::withMessages(['attach_report' => 'Indique o período observado; anexar e remover o relatório são acções distintas.']);
+ }
+ $report = $this->metrics->report($actor, ['from' => $values['observed_from'], 'to' => $values['observed_to'], 'service_code' => $values['report_service']]);
+ }
+
+ return DB::transaction(function () use ($actor, $id, $v, $values, $hash, $report) {
+ if ($id === null) {
+ DB::select('select pg_advisory_xact_lock(261103, hashtext(?))', [$actor->id.':'.$v['operation_key']]);
+ $row = DB::table('product_experiments')->where('created_by', $actor->id)->where('creation_key', $v['operation_key'])->lockForUpdate()->first();
+ } else {
+ $row = DB::table('product_experiments')->where('id', $id)->lockForUpdate()->firstOrFail();
+ }
+ if ($row) {
+ $replay = DB::table('product_experiment_revisions')->where('experiment_id', $row->id)->where('actor_id', $actor->id)->where('operation_key', $v['operation_key'])->first();
+ if ($replay) {
+ abort_unless(hash_equals($replay->request_hash, $hash), 409, 'Esta chave já foi usada para conteúdo diferente.');
+
+ return ['id' => $row->id, 'version' => (int) $replay->version, 'replayed' => true];
+ }
+ abort_unless((int) $row->version === (int) $v['version'], 409, 'O registo foi alterado. Consulte a versão actual e compare os campos antes de reaplicar as suas alterações.');
+ }
+ $previous = $row ? $this->decode(DB::table('product_experiment_revisions')->where('experiment_id', $row->id)->where('version', $row->version)->value('snapshot')) : null;
+ $indicator = $previous['indicator'] ?? null;
+ if ($values['indicator_id'] === 'manual') {
+ if (($indicator['id'] ?? null) !== 'manual' || $indicator['title'] !== $values['indicator_title'] || $indicator['unit'] !== $values['indicator_unit'] || $indicator['source'] !== $values['indicator_definition']) {
+ $indicator = ['id' => 'manual', 'title' => $values['indicator_title'], 'unit' => $values['indicator_unit'], 'source' => $values['indicator_definition'], 'limits' => 'Definição declarada pelo autor; não é medição automática do portal.', 'definition_version' => config('product-experiments.version')];
+ }
+ } elseif ($values['indicator_id'] === '') {
+ $indicator = null;
+ } elseif (($indicator['id'] ?? null) !== $values['indicator_id'] || ($v['refresh_indicator'] ?? false)) {
+ $catalogue = $this->catalogue($actor);
+ if (($v['indicator_definition_version'] ?? null) !== $catalogue['definition_version']) {
+ throw ValidationException::withMessages(['indicator_definition_version' => 'A definição dos indicadores mudou. Consulte a edição actual antes de a adoptar.']);
+ }
+ $selected = null;
+ foreach ($catalogue['items'] as $candidate) {
+ if ($candidate['id'] === $values['indicator_id']) {
+ $selected = $candidate;
+ break;
+ }
+ }
+ if (! $selected) {
+ throw ValidationException::withMessages(['values.indicator_id' => 'Escolha um indicador existente ou documente um indicador próprio.']);
+ }
+ $indicator = [...$selected, 'definition_version' => $catalogue['definition_version']];
+ }
+ $plan = Arr::only($values, ['change_kind', 'reference', 'hypothesis', 'indicator_id', 'period_from', 'period_to', 'segment', 'control', 'variant', 'assignment', 'criterion', 'transparency', 'consent', 'security', 'equality', 'preserves_requirements']);
+ $planHash = $this->hash([...$plan, 'indicator' => $indicator]);
+ $registration = $previous['registration'] ?? ['first_at' => null, 'original_plan_sha256' => null, 'amendments' => 0, 'amended_after_observation' => false];
+ $changed = $registration['first_at'] !== null && $previous['plan_sha256'] !== $planHash;
+ if ($changed && ! ($v['confirm_plan_change'] ?? false)) {
+ throw ValidationException::withMessages(['confirm_plan_change' => 'O plano já foi registado. Confirme a nova versão; as observações anteriores continuam no histórico e não comprovam o plano alterado.']);
+ }
+ if ($changed) {
+ $registration['amendments']++;
+ $registration['amended_after_observation'] = $registration['amended_after_observation'] || in_array($previous['values']['state'], ['observing', 'reviewed'], true);
+ }
+ $at = CarbonImmutable::now('UTC')->format('Y-m-d\TH:i:s.uP');
+ if ($registration['first_at'] === null && in_array($values['state'], ['planned', 'observing', 'reviewed'], true)) {
+ $registration['first_at'] = $at;
+ $registration['original_plan_sha256'] = $planHash;
+ }
+ $snapshotReport = ($v['remove_report'] ?? false) ? null : ($report ?? $previous['operational_report'] ?? null);
+ $resultFields = ['observed_from', 'observed_to', 'control_result', 'variant_result', 'result', 'limitations', 'evidence', 'decision', 'decision_reason'];
+ $resultHash = $this->hash(Arr::only($values, $resultFields));
+ $observationPlan = $previous['observation_plan_sha256'] ?? null;
+ if ($previous === null || $previous['result_sha256'] !== $resultHash || ($v['confirm_observation_plan'] ?? false)) {
+ $observationPlan = $planHash;
+ }
+ if (in_array($values['state'], ['observing', 'reviewed'], true) && $observationPlan !== $planHash) {
+ throw ValidationException::withMessages(['values.result' => 'As observações permanecem ligadas ao plano anterior. Reveja o resultado e documente a sua aplicação ao plano actual antes de registar a decisão.']);
+ }
+ if ($observationPlan === $planHash) {
+ foreach (['observed_from', 'observed_to'] as $key) {
+ if ($values[$key] && ((! $values['period_from'] || ! $values['period_to']) || $values[$key] < $values['period_from'] || $values[$key] > $values['period_to'])) {
+ throw ValidationException::withMessages(['values.'.$key => 'A observação deve corresponder ao período do plano a que fica ligada.']);
+ }
+ }
+ }
+ $snapshot = ['definition_version' => config('product-experiments.version'), 'vocabulary' => Arr::only(config('product-experiments'), ['states', 'change_kinds', 'decisions', 'fields']), 'version' => (int) ($row->version ?? 0) + 1, 'at' => $at, 'actor' => ['id' => $actor->id, 'name' => $actor->name],
+ 'reason' => $v['reason'] ?? '', 'values' => $values, 'indicator' => $indicator, 'plan_sha256' => $planHash, 'registration' => $registration,
+ 'result_sha256' => $resultHash, 'observation_plan_sha256' => $observationPlan, 'operational_report' => $snapshotReport,
+ 'report_scope' => 'operational_cohort_not_experiment_arm',
+ 'observation_reaffirmed_for_plan' => (bool) ($v['confirm_observation_plan'] ?? false),
+ 'report_matches_observation' => $snapshotReport === null ? null : Arr::only($snapshotReport['filters'], ['from', 'to', 'service_code']) === ['from' => $values['observed_from'], 'to' => $values['observed_to'], 'service_code' => $values['report_service'] === '' ? null : $values['report_service']]];
+ if ($previous && $previous['values'] === $values && $previous['indicator'] === $indicator && $previous['operational_report'] === $snapshotReport && $previous['observation_plan_sha256'] === $observationPlan) {
+ return ['id' => $row->id, 'version' => (int) $row->version, 'unchanged' => true, 'replayed' => false];
+ }
+ $experiment = $row->id ?? (string) Str::uuid();
+ $revision = (string) Str::uuid();
+ if ($row === null) {
+ DB::table('product_experiments')->insert(['id' => $experiment, 'version' => 1, 'state' => $values['state'], 'created_by' => $actor->id, 'updated_by' => $actor->id, 'creation_key' => $v['operation_key'], 'created_at' => now(), 'updated_at' => now()]);
+ } else {
+ DB::table('product_experiments')->where('id', $experiment)->update(['version' => $snapshot['version'], 'state' => $values['state'], 'updated_by' => $actor->id, 'updated_at' => now()]);
+ }
+ $snapshotHash = $this->hash($snapshot);
+ DB::table('product_experiment_revisions')->insert(['id' => $revision, 'experiment_id' => $experiment, 'version' => $snapshot['version'], 'actor_id' => $actor->id, 'operation_key' => $v['operation_key'], 'request_hash' => $hash, 'snapshot_sha256' => $snapshotHash, 'snapshot' => Crypt::encryptString(json_encode($snapshot, JSON_THROW_ON_ERROR)), 'created_at' => now()]);
+ DB::table('audit_events')->insert(['source_system' => 'product-experiments', 'entity_type' => 'product_experiments', 'entity_id' => $experiment, 'actor_user_id' => $actor->id, 'action' => 'experiment_revision_recorded',
+ 'before_data' => json_encode(['version' => (int) ($row->version ?? 0), 'state' => $row->state ?? null]), 'after_data' => json_encode(['version' => $snapshot['version'], 'state' => $values['state'], 'revision_id' => $revision, 'snapshot_sha256' => $snapshotHash])]);
+
+ return ['id' => $experiment, 'version' => $snapshot['version'], 'replayed' => false];
+ });
+ }
+
+ /** @param array $values */
+ private function validateValues(array $values): void
+ {
+ $errors = [];
+ $complete = in_array($values['state'], ['planned', 'observing', 'reviewed'], true);
+ if ($complete) {
+ foreach (['title', 'change_kind', 'reference', 'hypothesis', 'indicator_id', 'period_from', 'period_to', 'segment', 'control', 'variant', 'assignment', 'criterion', 'transparency', 'consent', 'security', 'equality'] as $key) {
+ if ($values[$key] === '') {
+ $errors['values.'.$key] = 'Preencha este campo para registar o plano.';
+ }
+ }
+ if ($values['preserves_requirements'] !== 'yes') {
+ $errors['values.preserves_requirements'] = 'Uma experiência não pode reduzir transparência, consentimento, segurança ou igualdade de tratamento.';
+ }
+ if ($values['indicator_id'] === 'manual') {
+ foreach (['indicator_title', 'indicator_definition', 'indicator_unit'] as $key) {
+ if ($values[$key] === '') {
+ $errors['values.'.$key] = 'Documente o indicador próprio e a sua base de cálculo.';
+ }
+ }
+ }
+ }
+ if ($values['period_from'] && $values['period_to'] && $values['period_from'] > $values['period_to']) {
+ $errors['values.period_to'] = 'O fim não pode anteceder o início.';
+ }
+ if ($values['state'] === 'reviewed') {
+ foreach (['observed_from', 'observed_to', 'control_result', 'variant_result', 'result', 'limitations', 'evidence', 'decision', 'decision_reason'] as $key) {
+ if ($values[$key] === '') {
+ $errors['values.'.$key] = 'Documente a observação e a decisão; um resultado inconclusivo pode ser declarado com as suas limitações.';
+ }
+ }
+ }
+ foreach (['observed_from', 'observed_to'] as $key) {
+ if ($values[$key] && $values[$key] > CarbonImmutable::now('UTC')->toDateString()) {
+ $errors['values.'.$key] = 'Uma observação efectivamente realizada não pode ter data futura.';
+ }
+ }
+ if ($values['observed_from'] && $values['observed_to'] && $values['observed_from'] > $values['observed_to']) {
+ $errors['values.observed_to'] = 'O fim observado não pode anteceder o início.';
+ }
+ if ($values['state'] === 'observing' && ($values['observed_from'] === '' || $values['observed_from'] > CarbonImmutable::now('UTC')->toDateString())) {
+ $errors['values.observed_from'] = 'Indique o início efectivamente observado.';
+ }
+ if ($errors !== []) {
+ throw ValidationException::withMessages($errors);
+ }
+ }
+
+ /** @return array */
+ private function decode(string $encrypted): array
+ {
+ return json_decode(Crypt::decryptString($encrypted), true, 512, JSON_THROW_ON_ERROR);
+ }
+
+ /** @param array $value */
+ private function hash(array $value): string
+ {
+ return hash('sha256', json_encode(Arr::sortRecursive($value), JSON_THROW_ON_ERROR));
+ }
+}
diff --git a/app/Services/ProductUsageMetrics.php b/app/Services/ProductUsageMetrics.php
new file mode 100644
index 00000000..4f4d02c1
--- /dev/null
+++ b/app/Services/ProductUsageMetrics.php
@@ -0,0 +1,170 @@
+ $input
+ * @return array */
+ public function report(User $actor, array $input): array
+ {
+ abort_unless($actor->can('manage-portal'), 403);
+ $now = CarbonImmutable::now('UTC');
+ $v = Validator::make($input, ['from' => 'nullable|date_format:Y-m-d', 'to' => 'nullable|date_format:Y-m-d', 'service_code' => 'nullable|string|max:100', 'search_definition' => 'nullable|string|max:100'])->validate();
+ $from = CarbonImmutable::parse($v['from'] ?? $now->subDays(29)->toDateString(), 'UTC')->startOfDay();
+ $to = CarbonImmutable::parse($v['to'] ?? $now->toDateString(), 'UTC')->startOfDay();
+ abort_unless($from <= $to && $to <= $now->startOfDay(), 422, 'Escolha um período válido, sem datas futuras.');
+ $cutoff = $to->addDay()->min($now);
+ $service = $v['service_code'] ?? null;
+ $service = $service === '' ? null : $service;
+
+ $searchDefinition = $v['search_definition'] ?? null;
+
+ return DB::transaction(function () use ($from, $to, $cutoff, $service, $now, $searchDefinition) {
+ // Production GET owns a consistent read-only snapshot. PHPUnit may already own its rollback transaction.
+ $consistency = DB::transactionLevel() === 1 ? 'repeatable_read' : 'existing_transaction';
+ if ($consistency === 'repeatable_read') {
+ DB::statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
+ }
+ $services = Schema::hasTable('desk_service_versions') ? DB::table('desk_service_versions')->orderBy('code')->orderByDesc('version')->get(['code', 'definition', 'version'])->unique('code')->map(fn ($s) => ['code' => $s->code, 'title' => json_decode($s->definition, true)['title'] ?? $s->code, 'version' => (int) $s->version])->values()->all() : [];
+ abort_if($service !== null && ! in_array($service, array_column($services, 'code'), true), 422, 'Escolha um serviço existente, incluindo as suas versões históricas.');
+ $start = $from->format('Y-m-d H:i:s.uP');
+ $end = $cutoff->format('Y-m-d H:i:s.uP');
+ $requestSources = Schema::hasTable('desk_requests') && Schema::hasTable('desk_service_versions');
+ $eventsReady = Schema::hasTable('desk_events') && Schema::hasColumn('desk_events', 'event_order');
+ $metrics = [];
+ $coverage = ['cohort_requests' => null, 'complete_histories' => null, 'unknown_histories' => null, 'classified_returned_requests' => null, 'unclassified_returned_requests' => null, 'valid_duration_requests' => null, 'invalid_duration_requests' => null];
+
+ $createdCases = null;
+ if (Schema::hasTable('desk_cases') && ($service === null || $requestSources)) {
+ $q = DB::table('desk_cases')->where('created_at', '>=', $start)->where('created_at', '<', $end);
+ if ($service !== null) {
+ $q->whereExists(fn ($sub) => $sub->selectRaw('1')->from('desk_requests as r')->join('desk_service_versions as s', 's.id', '=', 'r.service_version_id')
+ ->whereColumn('r.case_id', 'desk_cases.id')->where('s.code', $service)->where('r.created_at', '>=', $start)->where('r.created_at', '<', $end));
+ }
+ $createdCases = $q->count();
+ }
+ $metrics[] = $this->metric('dossiers_created', 'Dossiers criados', $createdCases, 'dossiers', null, null, 'desk_cases.created_at; no segmento de serviço, exige também um pedido desse serviço criado no período.', 'Uma linha por dossier, sem somar pedidos ou inferir pessoas únicas.');
+
+ if ($requestSources) {
+ $requests = DB::table('desk_requests as r')->join('desk_service_versions as s', 's.id', '=', 'r.service_version_id')
+ ->where('r.created_at', '>=', $start)->where('r.created_at', '<', $end)->when($service !== null, fn ($q) => $q->where('s.code', $service));
+ $total = (clone $requests)->count();
+ $coverage = ['cohort_requests' => $total, 'complete_histories' => 0, 'unknown_histories' => $total, 'classified_returned_requests' => 0, 'unclassified_returned_requests' => 0, 'valid_duration_requests' => 0, 'invalid_duration_requests' => 0];
+ $submitted = $returned = $reasonKnown = $reasonUnknown = $errorDocuments = $unsubmitted = $durationCount = $durationInvalid = 0;
+ $durationSum = 0.0;
+ if ($eventsReady) {
+ $requests->select(['r.id', 'r.case_id', 'r.version', 'r.created_at', 'r.updated_at'])->orderBy('r.id')->chunk(100, function ($batch) use ($end, &$coverage, &$submitted, &$returned, &$reasonKnown, &$reasonUnknown, &$errorDocuments, &$unsubmitted, &$durationCount, &$durationInvalid, &$durationSum) {
+ $events = DB::table('desk_events')->whereIn('request_id', $batch->pluck('id'))->where('created_at', '<', $end)->orderBy('event_order')
+ ->select(['id', 'request_id', 'version', 'action', 'created_at', 'event_order'])
+ ->selectRaw("CASE WHEN action = 'request_returned' THEN payload ELSE NULL END AS classification_payload")->get()->groupBy('request_id');
+ foreach ($batch as $request) {
+ $history = $events->get($request->id);
+ if ($history === null) {
+ continue;
+ }
+ $versions = $history->pluck('version')->map(fn ($version) => (int) $version)->unique();
+ $max = $versions->max() ?? 0;
+ $created = $history->contains(fn ($event) => $event->action === 'draft_created' && (int) $event->version === 1);
+ $currentAtCutoff = $request->updated_at === null || CarbonImmutable::parse($request->updated_at)->lt(CarbonImmutable::parse($end));
+ if (! $created || $max === 0 || $versions->min() !== 1 || $versions->count() !== $max || ($currentAtCutoff && $max !== (int) $request->version)) {
+ continue;
+ }
+ $coverage['complete_histories']++;
+ $first = $history->firstWhere('action', 'submitted');
+ if ($first === null) {
+ $unsubmitted++;
+
+ continue;
+ }
+ $submitted++;
+ $elapsed = CarbonImmutable::parse($request->created_at)->diffInSeconds(CarbonImmutable::parse($first->created_at), false);
+ if ($elapsed >= 0) {
+ $durationCount++;
+ $durationSum += $elapsed;
+ } else {
+ $durationInvalid++;
+ }
+ $returns = $history->filter(fn ($event) => $event->action === 'request_returned' && $event->event_order > $first->event_order);
+ if ($returns->isEmpty()) {
+ continue;
+ }
+ $returned++;
+ $unknown = $bad = false;
+ foreach ($returns as $event) {
+ try {
+ $category = $this->desk->decode($event->classification_payload)['return_reason_code'] ?? 'unspecified';
+ } catch (\Throwable) {
+ $category = 'unspecified';
+ }
+ $known = in_array($category, ['validation_error', 'missing_documents', 'other'], true);
+ $unknown = $unknown || ! $known;
+ $bad = $bad || in_array($category, ['validation_error', 'missing_documents'], true);
+ }
+ if ($bad) {
+ $errorDocuments++;
+ $reasonKnown++;
+ } elseif ($unknown) {
+ $reasonUnknown++;
+ } else {
+ $reasonKnown++;
+ }
+ }
+ });
+ }
+ $complete = $coverage['complete_histories'];
+ $coverage = [...$coverage, 'unknown_histories' => $total - $complete, 'classified_returned_requests' => $reasonKnown, 'unclassified_returned_requests' => $reasonUnknown, 'valid_duration_requests' => $durationCount, 'invalid_duration_requests' => $durationInvalid];
+ $metrics[] = $this->metric('requests_created', 'Pedidos criados', $total, 'pedidos', null, null, 'desk_requests.created_at e versão do serviço ligada ao pedido.', 'Coorte de pedidos criados no período; inclui cancelamentos. Não são pessoas únicas.');
+ $metrics[] = $this->metric('submission_rate', 'Pedidos com primeira submissão observada', $complete > 0 ? round(100 * $submitted / $complete, 2) : null, '%', $submitted, $complete, 'Primeiro evento submitted por pedido com draft_created v1 e versões contíguas até ao corte.', 'Apenas o subconjunto com historial completo; reenvios não aumentam o numerador. Não mede aprovação.', $total > $complete ? 'partial' : null);
+ $metrics[] = $this->metric('return_rate', 'Pedidos submetidos que tiveram devolução', $submitted > 0 ? round(100 * $returned / $submitted, 2) : null, '%', $returned, $submitted, 'Pelo menos um request_returned posterior à primeira submissão, até ao corte.', 'Mesmo pedido conta uma vez, ainda que devolvido/reenviado várias vezes. Inclui qualquer motivo.', $total > $complete ? 'partial' : null);
+ $metrics[] = $this->metric('error_document_return_rate', 'Devoluções por erro ou documentação em falta', $submitted > 0 && $reasonUnknown === 0 ? round(100 * $errorDocuments / $submitted, 2) : null, '%', $errorDocuments, $submitted, 'Categoria explícita no evento de devolução: validation_error ou missing_documents.', 'Motivo livre não é classificado por palavras. Devoluções históricas sem categoria podem impedir uma taxa exacta; casos com causa explicitamente comprovada contam uma vez.', $reasonUnknown > 0 || $total > $complete ? 'partial' : null);
+ $metrics[] = $this->metric('first_submission_seconds', 'Tempo do rascunho até à primeira submissão', $durationCount > 0 ? round($durationSum / $durationCount, 1) : null, 'segundos', null, $durationCount, 'Média de first(submitted.created_at) − desk_requests.created_at, com ordem e intervalo não negativo.', 'Não é tempo de criação do projecto, cronómetro do navegador ou SLA. Intervalos negativos ficam fora da média e são identificados.', $durationInvalid > 0 || $total > $complete ? 'partial' : null);
+ $metrics[] = $this->metric('not_submitted', 'Pedidos ainda sem submissão observada', $eventsReady && ($complete > 0 || $total === 0) ? $unsubmitted : null, 'pedidos', $unsubmitted, $complete, 'Pedidos com historial completo e sem submitted até ao corte.', 'Não classificar estes rascunhos/cancelamentos como abandono.', $total > $complete ? 'partial' : null);
+ } else {
+ foreach (['requests_created' => 'Pedidos criados', 'submission_rate' => 'Pedidos com primeira submissão observada', 'return_rate' => 'Pedidos submetidos que tiveram devolução', 'error_document_return_rate' => 'Devoluções por erro ou documentação em falta', 'first_submission_seconds' => 'Tempo até à primeira submissão', 'not_submitted' => 'Pedidos ainda sem submissão observada'] as $id => $label) {
+ $metrics[] = $this->metric($id, $label, null, '', null, null, 'Fonte do Balcão não instalada neste destino.', 'Sem fonte disponível, não apresentar zero.');
+ }
+ }
+ foreach (['company_comparison_saved' => ['saved_comparison', 'Dossiers com comparação guardada'], 'investment_guide_saved' => ['saved_guide', 'Dossiers com referência de guia guardada']] as $action => [$id, $label]) {
+ $count = null;
+ if ($eventsReady) {
+ $q = DB::table('desk_events')->where('action', $action)->where('created_at', '>=', $start)->where('created_at', '<', $end);
+ if ($service !== null) {
+ $q->whereExists(fn ($sub) => $sub->selectRaw('1')->from('desk_requests as r')->join('desk_service_versions as s', 's.id', '=', 'r.service_version_id')->whereColumn('r.case_id', 'desk_events.case_id')->where('s.code', $service)->where('r.created_at', '>=', $start)->where('r.created_at', '<', $end));
+ }
+ $count = $q->distinct()->count('case_id');
+ }
+ $metrics[] = $this->metric($id, $label, $count, 'dossiers', null, null, 'desk_events.action; case_id distinto no período, com segmento de pedidos quando seleccionado.', 'Versões/repetições de um mesmo dossier contam uma vez. Não mede consultas públicas ou pessoas únicas.');
+ }
+ $search = $this->searchMetrics->report($from->toDateString(), $to->toDateString(), $service, $searchDefinition);
+ $searchSource = 'Contadores diários UTC por canal/edição de recolha, lidos no snapshot do relatório. Edição '.$search['definition_version'].'.';
+ $searchLimits = $service === null ? 'Só respostas registadas; não mede pessoas, pesquisas únicas ou toda a utilização do portal. Sem registos não é zero.' : 'Sem associação comprovada à coorte do serviço seleccionado; não calcular para este filtro.';
+ $metrics[] = $this->metric('recorded_search_responses', 'Respostas de pesquisa registadas', $search['responses'], 'respostas', null, null, $searchSource, $searchLimits, $search['responses'] === null ? 'unmeasured' : 'partial');
+ $metrics[] = $this->metric('recorded_zero_search_responses', 'Respostas de pesquisa sem resultados principais', $search['zero_responses'], 'respostas', null, null, $searchSource, $searchLimits, $search['responses'] === null ? 'unmeasured' : 'partial');
+ $metrics[] = $this->metric('recorded_zero_search_rate', 'Taxa sem resultados entre respostas registadas', $search['zero_rate'], '%', $search['zero_responses'], $search['responses'], $searchSource, $searchLimits, $search['responses'] === null ? 'unmeasured' : 'partial');
+ $report = ['definition_version' => config('product-metrics.version'), 'generated_at' => $now->format('Y-m-d\TH:i:s.uP'),
+ 'filters' => ['from' => $from->toDateString(), 'to' => $to->toDateString(), 'service_code' => $service, 'search_definition' => $search['definition_version']], 'timezone' => 'UTC', 'observed_before' => $cutoff->format('Y-m-d\TH:i:s.uP'),
+ 'services' => $services, 'coverage' => $coverage, 'metrics' => $metrics, 'unmeasured' => config('product-metrics.unmeasured'), 'read_consistency' => $consistency, 'search' => $search,
+ 'limits' => ['Contagens de dossiers, pedidos, respostas HTTP e pessoas não são somáveis.', 'As taxas do Balcão referem-se à coorte de pedidos com historial verificável; a taxa de pesquisa tem como base as respostas registadas. Não são um funil geral do portal.', 'Eventos do Balcão usam o corte temporal indicado; pesquisas usam contagens diárias no snapshot da leitura, com o dia actual parcial e sem corte por fracção de segundo.', 'A leitura usa as permissões existentes. Os contadores de pesquisa não guardam termos, valores de filtros, IP, cookies, utilizadores ou identificadores de visitantes.', 'O fingerprint identifica o conteúdo deste relatório, não certifica a veracidade dos registos de origem.']];
+ $report['fingerprint'] = hash('sha256', json_encode($report, JSON_THROW_ON_ERROR));
+
+ return $report;
+ });
+ }
+
+ /** @return array */
+ private function metric(string $id, string $title, int|float|null $value, string $unit, ?int $numerator, ?int $denominator, string $source, string $limits, ?string $state = null): array
+ {
+ return ['id' => $id, 'title' => $title, 'value' => $value, 'unit' => $unit, 'numerator' => $numerator, 'denominator' => $denominator,
+ 'state' => $state ?? ($value === null ? 'unmeasured' : 'observed'), 'source' => $source, 'limits' => $limits];
+ }
+}
diff --git a/app/Services/PublicBusinessLocations.php b/app/Services/PublicBusinessLocations.php
new file mode 100644
index 00000000..4667e4a8
--- /dev/null
+++ b/app/Services/PublicBusinessLocations.php
@@ -0,0 +1,57 @@
+available()
+ ? 'l.public_source_reference AS location_source_reference, l.source_date AS location_source_date'
+ : 'NULL::text AS location_source_reference, NULL::date AS location_source_date';
+ }
+
+ public function disclosed(): Builder
+ {
+ $query = DB::table('existing_business_locations as l')->where('l.is_public', true);
+ foreach (['province_id' => ['province', 'district', 'admin_post', 'locality', 'exact'],
+ 'district_id' => ['district', 'admin_post', 'locality', 'exact'],
+ 'admin_post_id' => ['admin_post', 'locality', 'exact'], 'locality_id' => ['locality', 'exact']] as $field => $precisions) {
+ $query->where(fn (Builder $scope) => $scope->whereNotIn('l.precision_level', $precisions)->orWhereNull('l.'.$field)
+ ->orWhereIn('l.'.$field, app(InvestmentGeography::class)->publicReferences()->select('id')));
+ }
+
+ return $query;
+ }
+
+ public function primary(): Builder
+ {
+ return $this->disclosed()->where('l.is_primary', true);
+ }
+
+ public function points(): Builder
+ {
+ // Nested CASE is intentional: ST_X/ST_Y must never receive a polygon or collection.
+ return $this->primary()->where('l.precision_level', 'exact')
+ ->select('l.existing_business_id', 'l.updated_at as location_recorded_at')
+ ->selectRaw($this->sourceProjection())
+ ->selectRaw("CASE WHEN GeometryType(l.geom)='POINT' AND ST_IsValid(l.geom) AND NOT ST_IsEmpty(l.geom) AND ST_SRID(l.geom)=4326
+ THEN CASE WHEN ST_X(l.geom) BETWEEN -180 AND 180 AND ST_Y(l.geom) BETWEEN -90 AND 90 THEN l.geom END END AS point");
+ }
+
+ /** @param list $ids */
+ public function matchingArea(array $ids): Builder
+ {
+ return $this->disclosed()->where(function (Builder $query) use ($ids): void {
+ $query->whereIn('l.province_id', $ids)
+ ->orWhere(fn (Builder $level) => $level->whereIn('l.precision_level', ['district', 'admin_post', 'locality', 'exact'])->whereIn('l.district_id', $ids))
+ ->orWhere(fn (Builder $level) => $level->whereIn('l.precision_level', ['admin_post', 'locality', 'exact'])->whereIn('l.admin_post_id', $ids))
+ ->orWhere(fn (Builder $level) => $level->whereIn('l.precision_level', ['locality', 'exact'])->whereIn('l.locality_id', $ids));
+ });
+ }
+}
diff --git a/app/Services/PublicSearchMetrics.php b/app/Services/PublicSearchMetrics.php
new file mode 100644
index 00000000..7fa212ff
--- /dev/null
+++ b/app/Services/PublicSearchMetrics.php
@@ -0,0 +1,144 @@
+ $filters */
+ public function candidate(Request $request, string $channel, int $total, array $filters): void
+ {
+ if (! config('search-metrics.enabled') || ! array_key_exists($channel, config('search-metrics.channels')) || $total < 0) {
+ return;
+ }
+ if (! $request->isMethod('GET') || $request->integer('page', 1) !== 1) {
+ return;
+ }
+ foreach ($filters as $key => $value) {
+ if (! is_string($key)) {
+ continue;
+ }
+ if (in_array($key, config('search-metrics.presentation_keys'), true) || ! $request->query->has($key)) {
+ continue;
+ }
+ if ($value === null || $value === '' || $value === [] || $value === false || (is_string($value) && trim($value) === '')) {
+ continue;
+ }
+ $request->attributes->set(self::ATTRIBUTE, ['channel' => $channel, 'empty' => $total === 0]);
+
+ return;
+ }
+ }
+
+ public function record(string $channel, bool $empty): void
+ {
+ if (! config('search-metrics.enabled') || ! array_key_exists($channel, config('search-metrics.channels'))) {
+ return;
+ }
+ try {
+ // A savepoint also protects an existing request transaction if collection fails.
+ DB::transaction(function () use ($channel, $empty) {
+ $settings = DB::selectOne("SELECT current_setting('lock_timeout') AS old_lock, current_setting('statement_timeout') AS old_statement, (SELECT setting::bigint FROM pg_settings WHERE name='lock_timeout') AS lock_ms, (SELECT setting::bigint FROM pg_settings WHERE name='statement_timeout') AS statement_ms");
+ $lock = $this->budget('capture_lock_timeout_ms', 100);
+ $statement = $this->budget('capture_statement_timeout_ms', 300);
+ if ($settings->lock_ms > 0) {
+ $lock = min($lock, $settings->lock_ms);
+ }
+ if ($settings->statement_ms > 0) {
+ $statement = min($statement, $settings->statement_ms);
+ }
+ DB::selectOne("SELECT set_config('lock_timeout',?,true), set_config('statement_timeout',?,true)", [$lock.'ms', $statement.'ms']);
+ if (Schema::hasTable('product_search_counts') && Schema::hasTable('product_search_definitions')) {
+ $at = CarbonImmutable::now('UTC');
+ $definition = $this->definition();
+ $hash = hash('sha256', json_encode(Arr::sortRecursive($definition), JSON_THROW_ON_ERROR));
+ DB::table('product_search_definitions')->insertOrIgnore(['version' => $definition['version'], 'sha256' => $hash, 'definition' => json_encode($definition, JSON_THROW_ON_ERROR), 'created_at' => $at->format('Y-m-d H:i:s.uP')]);
+ if (DB::table('product_search_definitions')->where('version', $definition['version'])->value('sha256') !== $hash) {
+ throw new \LogicException('search_definition_conflict');
+ }
+ DB::statement(<<<'SQL'
+INSERT INTO product_search_counts(day,channel,definition_version,responses,zero_responses,first_recorded_at,last_recorded_at)
+VALUES(?,?,?,1,?,?,?)
+ON CONFLICT(day,channel,definition_version) DO UPDATE SET
+ responses=product_search_counts.responses+1,
+ zero_responses=product_search_counts.zero_responses+EXCLUDED.zero_responses,
+ first_recorded_at=LEAST(product_search_counts.first_recorded_at,EXCLUDED.first_recorded_at),
+ last_recorded_at=GREATEST(product_search_counts.last_recorded_at,EXCLUDED.last_recorded_at)
+SQL, [$at->toDateString(), $channel, config('search-metrics.version'), $empty ? 1 : 0, $at->format('Y-m-d H:i:s.uP'), $at->format('Y-m-d H:i:s.uP')]);
+ }
+ // Successful nested transactions must restore the caller's settings explicitly.
+ // On error, rollback to the savepoint restores both settings automatically.
+ DB::selectOne("SELECT set_config('lock_timeout',?,true), set_config('statement_timeout',?,true)", [$settings->old_lock, $settings->old_statement]);
+ });
+ } catch (\Throwable $error) {
+ // Never log the exception message/SQL, request, terms, headers or actor.
+ try {
+ Log::warning('product-search-metrics-unavailable', ['channel' => $channel, 'definition_version' => config('search-metrics.version'), 'exception_class' => $error::class]);
+ } catch (\Throwable) {
+ // Logging failure must not replace the already-produced search response either.
+ }
+ }
+ }
+
+ /** Called inside the authorised report snapshot. Daily aggregates have their own time basis.
+ * @return array */
+ public function report(string $from, string $to, ?string $service, ?string $requestedVersion): array
+ {
+ $installed = Schema::hasTable('product_search_counts') && Schema::hasTable('product_search_definitions');
+ $registered = $installed ? DB::table('product_search_definitions')->orderBy('version')->get()->keyBy('version') : null;
+ $current = $this->definition();
+ $version = $requestedVersion === null || $requestedVersion === '' ? $current['version'] : $requestedVersion;
+ $available = array_values(array_unique([...($registered?->pluck('version')->all() ?? []), $current['version']]));
+ if (! in_array($version, $available, true)) {
+ throw ValidationException::withMessages(['search_definition' => 'Escolha uma edição de recolha existente.']);
+ }
+ $stored = $registered?->get($version);
+ $definition = $stored ? json_decode($stored->definition, true, 512, JSON_THROW_ON_ERROR) : $current;
+ $rows = $installed && $service === null ? DB::table('product_search_counts')->where('definition_version', $version)->whereBetween('day', [$from, $to])->orderBy('day')->orderBy('channel')->get() : null;
+ $channels = [];
+ foreach ($definition['channels'] as $code => $label) {
+ $selected = $rows?->where('channel', $code);
+ $known = $selected !== null && $selected->isNotEmpty();
+ $count = $known ? $selected->sum('responses') : null;
+ $zeros = $known ? $selected->sum('zero_responses') : null;
+ $channels[] = ['id' => $code, 'label' => $label, 'responses' => $count, 'zero_responses' => $zeros, 'zero_rate' => $count > 0 ? round(100 * $zeros / $count, 2) : null,
+ 'first_recorded_at' => $known ? $selected->min('first_recorded_at') : null, 'last_recorded_at' => $known ? $selected->max('last_recorded_at') : null,
+ 'definition_versions' => $selected?->pluck('definition_version')->unique()->values()->all() ?? []];
+ }
+ $known = $rows !== null && $rows->isNotEmpty();
+ $responses = $known ? $rows->sum('responses') : null;
+ $zeros = $known ? $rows->sum('zero_responses') : null;
+
+ return ['installed' => $installed, 'enabled_now' => (bool) config('search-metrics.enabled'), 'applicable' => $service === null,
+ 'from' => $from, 'to' => $to, 'timezone' => 'UTC', 'read_at' => DB::selectOne('select statement_timestamp() AS at')->at,
+ 'definition_version' => $version, 'available_definitions' => $available, 'definition' => $definition, 'definition_conflict_now' => $stored !== null && $version === $current['version'] && $stored->sha256 !== hash('sha256', json_encode(Arr::sortRecursive($current), JSON_THROW_ON_ERROR)),
+ 'responses' => $responses, 'zero_responses' => $zeros, 'zero_rate' => $responses > 0 ? round(100 * $zeros / $responses, 2) : null,
+ 'channels' => $channels, 'exclusions' => $definition['exclusions'], 'completeness' => 'unverified_best_effort',
+ 'temporal_basis' => 'daily_aggregate_at_report_snapshot',
+ 'limits' => ['São respostas de primeira página com critérios explícitos, não pessoas ou pesquisas únicas.', 'Sem linhas no período significa ausência de registos de medição, não zero pesquisas.', 'A recolha não bloqueia a pesquisa; falhas de recolha podem deixar respostas por contar. A taxa refere-se apenas às respostas registadas.', 'Contagens por dia UTC são lidas no snapshot do relatório; o dia actual é parcial e não permite um corte por fracção de segundo.', 'Um filtro de serviço do Balcão não se aplica a estes catálogos públicos; nesse caso, os valores ficam sem cálculo.', 'As sugestões relacionadas não alteram o total principal usado para classificar uma resposta sem resultados.']];
+ }
+
+ /** @return array */
+ private function definition(): array
+ {
+ return ['version' => config('search-metrics.version'), 'channels' => config('search-metrics.channels'), 'presentation_keys' => config('search-metrics.presentation_keys'), 'exclusions' => config('search-metrics.exclusions'),
+ 'unit' => 'successful_first_page_http_search_response', 'zero' => 'primary_result_total_equals_zero', 'privacy' => 'daily_channel_counts_only_no_terms_filters_identifiers_or_visitors'];
+ }
+
+ private function budget(string $key, int $default): int
+ {
+ $value = filter_var(config('search-metrics.'.$key), FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 5000]]);
+
+ return $value === false ? $default : $value;
+ }
+}
diff --git a/app/Services/TechnicalIncidentHandling.php b/app/Services/TechnicalIncidentHandling.php
new file mode 100644
index 00000000..a2148d69
--- /dev/null
+++ b/app/Services/TechnicalIncidentHandling.php
@@ -0,0 +1,138 @@
+stateFor($reference);
+ } catch (HttpExceptionInterface $error) {
+ if ($error->getStatusCode() !== 503) {
+ throw $error;
+ }
+
+return null;
+ }
+ }
+
+ private function events(string $reference): Builder
+ {
+ return DB::table('audit_events')->where('source_system', self::SOURCE)->where('entity_type', 'opportunity-technical-incident')->where('entity_id', $reference)->where('action', 'incident_handled');
+ }
+
+ /** Caller has already authorized the root incident.
+ * @return array{version:int,status:string,assignee_user_id:int|null,assignee_name:string|null,updated_at:string|null,resolved_at:string|null} */
+ public function stateFor(string $reference): array
+ {
+ $event = $this->events($reference)->orderByRaw("(after_data->'handling'->'version') DESC NULLS FIRST")->orderByDesc('id')->first(['after_data']);
+ if ($event === null) {
+ return ['version' => 0, 'status' => 'open', 'assignee_user_id' => null, 'assignee_name' => null, 'updated_at' => null, 'resolved_at' => null];
+ }
+ $value = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR)['handling'] ?? null;
+ abort_unless(is_array($value) && is_int($value['version'] ?? null) && $value['version'] > 0 && in_array($value['status'] ?? null, ['open', 'in_progress', 'resolved'], true)
+ && array_key_exists('assignee_user_id', $value) && ($value['assignee_user_id'] === null || (is_int($value['assignee_user_id']) && $value['assignee_user_id'] > 0))
+ && is_string($value['updated_at'] ?? null) && array_key_exists('resolved_at', $value) && ($value['resolved_at'] === null || is_string($value['resolved_at'])), 503, 'O histórico técnico não pôde ser identificado com segurança.');
+
+ return ['version' => $value['version'], 'status' => $value['status'], 'assignee_user_id' => $value['assignee_user_id'],
+ 'assignee_name' => $value['assignee_user_id'] ? User::whereKey($value['assignee_user_id'])->value('name') : null, 'updated_at' => $value['updated_at'], 'resolved_at' => $value['resolved_at']];
+ }
+
+ /** @return array */
+ public function detail(User $actor, string $reference): array
+ {
+ $root = app(OpportunityTechnicalSupport::class)->root($actor, $reference);
+ $data = json_decode($root->after_data, true, 512, JSON_THROW_ON_ERROR)['incident'];
+ $commands = [];
+ foreach ($this->events($reference)->where('actor_user_id', $actor->id)->selectRaw("after_data->'handling'->>'operation_key' AS key,after_data->'handling'->'version' AS version")->get() as $event) {
+ $version = is_string($event->version) ? json_decode($event->version, true) : $event->version;
+ if (is_string($event->key) && Str::isUuid($event->key) && is_int($version) && $version > 0) {
+ $commands[] = ['key' => $event->key, 'version' => $version];
+ }
+ }
+ $history = $this->events($reference)->leftJoin('users', 'users.id', '=', 'audit_events.actor_user_id')
+ ->orderByRaw("(after_data->'handling'->'version') DESC NULLS FIRST")->orderByDesc('audit_events.id')->paginate(10, ['audit_events.id', 'audit_events.occurred_at', 'audit_events.after_data', 'users.name as actor'], 'history_page')->withQueryString()
+ ->through(function ($event) {
+ $data = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR)['handling'] ?? [];
+ $note = null;
+ try {
+ if (is_string($data['note'] ?? null)) {
+ $note = Crypt::decryptString($data['note']);
+ }
+ } catch (DecryptException) {/* Preserve encrypted original. */
+ }
+
+ return ['id' => $event->id, 'version' => $data['version'] ?? null, 'action' => $data['command'] ?? null, 'status' => $data['status'] ?? null, 'actor' => $event->actor, 'occurred_at' => $event->occurred_at, 'note' => $note, 'note_available' => $note !== null];
+ })->toArray();
+
+ return ['incident' => ['reference' => $reference, 'operation' => $data['operation'], 'observed_version' => $data['observed_version'], 'occurred_at' => $root->occurred_at, 'error_code' => $data['error_code'], 'handling' => $this->stateFor($reference)], 'history' => $history, 'commands' => $commands, 'actorId' => $actor->id];
+ }
+
+ /** @param array $input
+ * @return array */
+ public function decide(User $actor, string $reference, array $input): array
+ {
+ abort_unless(app(OpportunityTechnicalSupport::class)->allows($actor), 403);
+ $data = Validator::make($input, ['operation_key' => 'required|uuid', 'version' => 'required|integer|min:0', 'action' => 'required|in:claim,release,note,resolve,reopen', 'note' => 'required|string|min:10|max:3000'])->validate();
+ $key = strtolower($data['operation_key']);
+ $note = trim($data['note']);
+ Validator::make(['note' => $note], ['note' => 'required|string|min:10|max:3000'])->validate();
+ $hash = hash('sha256', json_encode(['version' => (int) $data['version'], 'action' => $data['action'], 'note' => $note], JSON_THROW_ON_ERROR));
+
+ return DB::transaction(function () use ($actor, $reference, $data, $key, $note, $hash) {
+ app(OpportunityTechnicalSupport::class)->root($actor, $reference, true);
+ $receipt = $this->events($reference)->where('actor_user_id', $actor->id)->whereRaw("after_data->'handling'->>'operation_key' = ?", [$key])->first(['after_data']);
+ if ($receipt) {
+ $old = json_decode($receipt->after_data, true, 512, JSON_THROW_ON_ERROR)['handling'];
+ abort_unless(($old['hash'] ?? null) === $hash, 409, 'Esta tentativa já foi utilizada com outros dados.');
+
+ return ['reference' => $reference, 'actor_id' => $actor->id, 'operation_key' => $key, 'result_version' => $old['version'], 'replayed' => true, 'handling' => $this->stateFor($reference)];
+ }
+ $before = $this->stateFor($reference);
+ abort_unless($before['version'] === (int) $data['version'], 409, 'O incidente mudou. Compare o estado actual antes de continuar.');
+ $after = $before;
+ $action = $data['action'];
+ if ($action === 'claim') {
+ abort_if($before['status'] === 'resolved', 422, 'Reabra o incidente antes de assumir o tratamento.');
+ abort_if($before['status'] === 'in_progress' && $before['assignee_user_id'] === $actor->id, 422, 'O tratamento já está assumido por si.');
+ $after['status'] = 'in_progress';
+ $after['assignee_user_id'] = $actor->id;
+ } elseif ($action === 'release') {
+ abort_unless($before['status'] === 'in_progress', 422, 'Só um tratamento em curso pode regressar à fila.');
+ $after['status'] = 'open';
+ $after['assignee_user_id'] = null;
+ } elseif ($action === 'resolve') {
+ abort_if($before['status'] === 'resolved', 422, 'O incidente já está resolvido.');
+ $after['status'] = 'resolved';
+ $after['resolved_at'] = now()->toIso8601String();
+ } elseif ($action === 'reopen') {
+ abort_unless($before['status'] === 'resolved', 422, 'Só um incidente resolvido pode ser reaberto.');
+ $after['status'] = 'open';
+ $after['assignee_user_id'] = null;
+ $after['resolved_at'] = null;
+ }
+ $after['version']++;
+ $after['updated_at'] = now()->toIso8601String();
+ unset($after['assignee_name']);
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'correlation_id' => $reference, 'source_system' => self::SOURCE, 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $reference, 'actor_user_id' => $actor->id, 'action' => 'incident_handled', 'data_classification' => 'restricted',
+ 'before_data' => json_encode(['handling' => array_diff_key($before, ['assignee_name' => true])], JSON_THROW_ON_ERROR), 'after_data' => json_encode(['handling' => [...$after, 'operation_key' => $key, 'hash' => $hash, 'command' => $action, 'note' => Crypt::encryptString($note)]], JSON_THROW_ON_ERROR)]);
+
+ return ['reference' => $reference, 'actor_id' => $actor->id, 'operation_key' => $key, 'result_version' => $after['version'], 'replayed' => false, 'handling' => $this->stateFor($reference)];
+ });
+ }
+}
diff --git a/app/Services/TechnicalSupportProfileSchema.php b/app/Services/TechnicalSupportProfileSchema.php
new file mode 100644
index 00000000..cc773e9d
--- /dev/null
+++ b/app/Services/TechnicalSupportProfileSchema.php
@@ -0,0 +1,40 @@
+where('migration', self::MIGRATION)->exists();
+ $constraint = $table ? DB::selectOne("SELECT pg_get_constraintdef(c.oid) AS definition,c.convalidated AS validated FROM pg_constraint c JOIN pg_class t ON t.oid=c.conrelid JOIN pg_namespace n ON n.oid=t.relnamespace WHERE n.nspname='public' AND t.relname='portal_role_assignments' AND c.conname='portal_role_name' AND c.contype='c'") : null;
+ $state = $table ? 'unrecognised' : 'absent';
+ if ($constraint && $constraint->validated === true && is_string($constraint->definition)) {
+ preg_match_all("/'([^']+)'/", $constraint->definition, $matches);
+ $roles = $matches[1];
+ sort($roles);
+ $shape = preg_replace(["/'[a-z_]+'/", '/::character varying(?:\[\])?/', '/::text(?:\[\])?/', '/\s+/', '/[()]/'], ['?', '', '', '', ''], $constraint->definition);
+ $base = ['auditor', 'promoter', 'publisher', 'validator'];
+ $support = ['auditor', 'promoter', 'publisher', 'technical_support', 'validator'];
+ if ($shape === 'CHECKrole=ANYARRAY['.implode(',', array_fill(0, count($roles), '?')).']') {
+ if ($roles === $base) {
+ $state = 'base';
+ } elseif ($roles === $support) {
+ $state = 'support';
+ }
+ }
+ }
+
+ return ['has_table' => $table, 'ledger' => $ledger, 'state' => $state, 'installed' => $ledger && $state === 'support',
+ 'consistent' => (! $table && ! $ledger) || ($state === 'base' && ! $ledger) || ($state === 'support' && $ledger), 'repairable' => $ledger && $state === 'base',
+ 'fingerprint' => hash('sha256', json_encode([$constraint?->definition, $constraint?->validated], JSON_THROW_ON_ERROR))];
+ }
+}
diff --git a/app/Services/VerifiedDocumentBinary.php b/app/Services/VerifiedDocumentBinary.php
index b8e3d6d4..53183298 100644
--- a/app/Services/VerifiedDocumentBinary.php
+++ b/app/Services/VerifiedDocumentBinary.php
@@ -50,7 +50,7 @@ class VerifiedDocumentBinary
}
/** The general document route must not bypass the opportunity's current authorization. */
- private function authorizeOpportunityAttachment(\stdClass $document): void
+ public function authorizeOpportunityAttachment(\stdClass $document): void
{
$links = collect();
foreach (['opportunity_documents', 'opportunity_images'] as $table) {
diff --git a/app/Services/VirtualDesk.php b/app/Services/VirtualDesk.php
index 7b9c48a0..bddd44b1 100644
--- a/app/Services/VirtualDesk.php
+++ b/app/Services/VirtualDesk.php
@@ -56,6 +56,55 @@ class VirtualDesk
return $case;
}
+ public function assertOpen(\stdClass $case): void
+ {
+ abort_if($case->closed_at, 409, 'Dossier encerrado. Os registos guardados continuam disponíveis para consulta.');
+ }
+
+ /** @return array */
+ public function caseActivity(\stdClass $case): array
+ {
+ return ['open_requests' => DB::table('desk_requests')->where('case_id', $case->id)->whereNotIn('status', ['closed', 'cancelled'])->count(),
+ 'open_tasks' => Schema::hasColumn('tasks', 'desk_case_id') ? DB::table('tasks')->where('desk_case_id', $case->id)->whereNull('deleted_at')->whereNotIn('status', ['done', 'cancelled'])->count() : null,
+ 'pending_payments' => Schema::hasTable('desk_payments') ? DB::table('desk_payments')->whereIn('request_id', DB::table('desk_requests')->where('case_id', $case->id)->select('id'))->whereIn('status', ['pending', 'internal_issue'])->count() : null];
+ }
+
+ /** @param array $input
+ * @return array
+ */
+ public function changeCaseState(User $actor, string $id, array $input): array
+ {
+ $data = Validator::make($input, ['version' => 'required|integer|min:1', 'state' => 'required|in:open,closed', 'reason' => 'required|string|min:3|max:5000', 'client_key' => 'required|uuid'])->validate();
+ $data['version'] = (int) $data['version'];
+
+ return DB::transaction(function () use ($actor, $id, $data) {
+ $case = $this->case($actor, $id, true, true);
+ abort_unless((int) $case->user_id === $actor->id, 403, 'Só o dono registado do dossier pode encerrá-lo ou reabri-lo.');
+ $replayed = false;
+ foreach (DB::table('desk_events')->where('case_id', $id)->where('action', 'case_state_changed')->get(['actor_id', 'payload']) as $event) {
+ $saved = $this->decode($event->payload);
+ if (($saved['client_key'] ?? null) === $data['client_key']) {
+ abort_unless((int) $event->actor_id === $actor->id && ($saved['operation'] ?? null) === $data, 409, 'Esta operação já foi registada com outros dados.');
+ $replayed = true;
+ break;
+ }
+ }
+ if (! $replayed) {
+ abort_unless((int) $case->version === $data['version'], 409, 'O dossier foi actualizado. Confira a versão actual antes de continuar.');
+ $closed = $data['state'] === 'closed';
+ abort_if(($case->closed_at !== null) === $closed, 409, 'O dossier já se encontra nesse estado. Actualize a página.');
+ $before = ['version' => (int) $case->version, 'closed_at' => $case->closed_at];
+ $activity = $this->caseActivity($case);
+ DB::table('desk_cases')->where('id', $id)->update(['closed_at' => $closed ? now() : null, 'version' => $case->version + 1, 'updated_at' => now()]);
+ $case = DB::table('desk_cases')->where('id', $id)->firstOrFail();
+ $this->event($case, $actor, 'case_state_changed', ['client_key' => $data['client_key'], 'operation' => $data, 'reason' => $data['reason'], 'before' => $before, 'after' => ['version' => (int) $case->version, 'closed_at' => $case->closed_at], 'activity' => $activity,
+ 'scope' => 'owner_availability_decision_no_child_status_changes_or_official_approval']);
+ }
+
+ return ['id' => $id, 'version' => (int) $case->version, 'closed_at' => $case->closed_at, 'replayed' => $replayed];
+ });
+ }
+
public function request(User $actor, string $id, bool $ownerOnly = false, bool $lock = false): \stdClass
{
$request = DB::table('desk_requests')->where('id', $id)->when($lock, fn ($q) => $q->lockForUpdate())->first();
@@ -177,22 +226,33 @@ class VirtualDesk
return DB::transaction(function () use ($actor, $caseId, $serviceId, $clientKey, $opportunity) {
$case = $this->case($actor, $caseId, true, true);
abort_if($case->closed_at, 409, 'Dossier encerrado.');
- $service = DB::table('desk_service_versions')->where('id', $serviceId)->where('status', 'published')->first();
- abort_unless($service !== null, 422, 'Versão do serviço indisponível para novos pedidos.');
$existing = DB::table('desk_requests')->where('case_id', $caseId)->where('client_key', $clientKey)->first();
if ($existing) {
abort_unless($existing->service_version_id === $serviceId, 409);
return $existing;
}
+ // Serialize publication and creation against the same edition selection.
+ DB::select('select pg_advisory_xact_lock(261008, 2)');
+ $service = DB::table('desk_service_versions')->where('id', $serviceId)->where('status', 'published')->first();
+ abort_unless($service !== null, 422, 'Versão do serviço indisponível para novos pedidos.');
+ $current = app(DeskServiceAvailability::class)->current()->where('code', $service->code)->first();
+ if (! $current || $current->id !== $serviceId) {
+ throw ValidationException::withMessages(['service_version_id' => 'A versão escolhida não está actualmente disponível para novos pedidos. Actualize a lista e confira o formulário aplicável; os pedidos anteriores mantêm a sua versão.']);
+ }
$id = (string) Str::uuid();
$base = $this->decode($case->payload);
$serviceFields = json_decode($service->definition, true)['fields'];
$payload = Arr::only(['title' => $case->title, 'description' => $base['investment']['objective'] ?? ''], array_keys($serviceFields));
+ foreach (array_keys($payload) as $key) {
+ if ($serviceFields[$key]['type'] === 'consent') {
+ unset($payload[$key]);
+ }
+ }
if (isset($serviceFields['regime']['options']['unknown'])) {
$payload['regime'] = 'unknown';
}
- if (isset($serviceFields['description']) && config('investor-path.enabled') && $case->simulation_id && (int) $case->user_id === $actor->id) {
+ if (isset($serviceFields['description']) && $serviceFields['description']['type'] !== 'consent' && config('investor-path.enabled') && $case->simulation_id && (int) $case->user_id === $actor->id) {
$draftRequest = Request::create('/');
$draftRequest->setUserResolver(fn () => $actor);
$draft = app(SimulationFormDrafts::class)->find($case->simulation_id, $draftRequest);
@@ -210,7 +270,7 @@ class VirtualDesk
}
$payload = app(InvestmentConsumerScope::class)->bind($actor, $caseId, $payload);
foreach (['territory_id' => 'territory_id', 'location_source' => 'location_source', 'title' => 'title', 'description' => 'description', 'sector' => 'sector', 'province_id' => 'province_id', 'district_id' => 'district_id', 'admin_post_id' => 'admin_post_id', 'locality_id' => 'locality_id'] as $field => $source) {
- if (isset($serviceFields[$field],$mapped[$source]) && (empty($payload[$field]) || in_array($field, ['title', 'description'], true) && $context['revision'] > 0)
+ if (isset($serviceFields[$field],$mapped[$source]) && $serviceFields[$field]['type'] !== 'consent' && (empty($payload[$field]) || in_array($field, ['title', 'description'], true) && $context['revision'] > 0)
&& Validator::make(['value' => $mapped[$source]], ['value' => $this->fieldRules($serviceFields[$field], false)])->passes()) {
$payload[$field] = $mapped[$source];
}
@@ -269,7 +329,25 @@ class VirtualDesk
* @return array */
public function validateFields(array $payload, array $definition, bool $submitting): array
{
- $rules = ['payload' => ['required', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'])],
+ return $this->validatedPayload($payload, $definition, $submitting, false);
+ }
+
+ /** Incomplete text/number formats can be recovered, but never submitted through this path.
+ * @param array $payload
+ * @param array $definition
+ * @return array */
+ public function checkpointFields(array $payload, array $definition): array
+ {
+ return $this->validatedPayload($payload, $definition, false, true);
+ }
+
+ /** @param array $payload
+ * @param array $definition
+ * @return array */
+ private function validatedPayload(array $payload, array $definition, bool $submitting, bool $checkpoint): array
+ {
+ $messages = [];
+ $rules = ['payload' => ['present', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'])],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
@@ -278,13 +356,30 @@ class VirtualDesk
foreach ($definition['fields'] as $key => $field) {
$active = $this->fieldApplies((string) $key, $definition['fields'], $payload);
$required = $submitting && ($field['required'] ?? false) && $active;
- $rules['payload.'.$key] = $this->fieldRules($field, $required);
+ $rules['payload.'.$key] = $this->fieldRules($field, $required, $checkpoint);
+ if ($field['type'] === 'multiselect') {
+ $rules['payload.'.$key.'.*'] = ['required', 'string', 'distinct:strict', Rule::in(array_map('strval', array_keys($field['options'])))];
+ }
+ if ($field['type'] === 'attachment') {
+ $rules['payload.'.$key.'.*'] = ['required', 'string', 'uuid', 'distinct:strict'];
+ $messages['payload.'.$key.'.required'] = 'Seleccione pelo menos um documento em «'.$field['label'].'».';
+ $messages['payload.'.$key.'.max'] = 'Seleccione no máximo '.$field['max_files'].' ficheiro(s) em «'.$field['label'].'».';
+ foreach (['array', 'list'] as $rule) {
+ $messages['payload.'.$key.'.'.$rule] = 'Seleccione os documentos da lista em «'.$field['label'].'».';
+ }
+ foreach (['uuid', 'string', 'distinct'] as $rule) {
+ $messages['payload.'.$key.'.*.'.$rule] = 'Seleccione cada documento autorizado apenas uma vez em «'.$field['label'].'».';
+ }
+ }
}
- $validated = Validator::make(['payload' => $payload], $rules)->validate()['payload'];
+ $validated = Validator::make(['payload' => $payload], $rules, $messages)->validate()['payload'];
foreach ($definition['fields'] as $key => $field) {
if ($field['type'] === 'select' && isset($validated[$key])) {
$validated[$key] = (string) $validated[$key];
}
+ if (in_array($field['type'], ['multiselect', 'attachment'], true) && is_array($validated[$key] ?? null)) {
+ sort($validated[$key], SORT_STRING);
+ }
if ($field['type'] === 'territory' && ! empty($validated[$key])) {
if (! app(InvestmentGeography::class)->publicReferences()->where('id', $validated[$key])->exists()) {
throw ValidationException::withMessages(['payload.'.$key => 'Seleccione uma localização disponível no cadastro territorial.']);
@@ -302,11 +397,21 @@ class VirtualDesk
/** @param array $field
* @return list */
- private function fieldRules(array $field, bool $required): array
+ private function fieldRules(array $field, bool $required, bool $checkpoint = false): array
{
+ if ($checkpoint && in_array($field['type'], ['number', 'date', 'email', 'url'], true)) {
+ return ['nullable', function (string $attribute, mixed $value, \Closure $fail): void {
+ if (! is_string($value) && ! is_int($value) && ! is_float($value)) {
+ $fail('Conserve apenas texto ou um número neste campo do rascunho.');
+ }
+ }, 'max:1000'];
+ }
+
return [$required ? 'required' : 'nullable', ...match ($field['type']) {
'number' => ['numeric', 'decimal:0,2', 'min:'.($field['min'] ?? 0), 'max:999999999999'], 'date' => ['date_format:Y-m-d'],
'select' => [Rule::in(array_keys($field['options']))], 'territory' => ['uuid'],
+ 'multiselect' => ['array', 'list', 'max:100'], 'consent' => ['string', Rule::in(['accepted', 'declined'])],
+ 'attachment' => ['array', 'list', 'max:'.$field['max_files']],
'email' => ['string', 'email', 'max:1000'], 'url' => ['string', 'url:http,https', 'max:1000'],
default => ['string', 'max:'.($field['type'] === 'textarea' ? 15000 : 1000)],
}];
@@ -326,7 +431,10 @@ class VirtualDesk
}
$parent = $field['when']['field'];
$answer = $payload[$parent] ?? null;
- if (! is_scalar($answer) || (string) $answer !== $field['when']['equals']) {
+ $matches = ($field['when']['operator'] ?? 'equals') === 'contains'
+ ? is_array($answer) && in_array($field['when']['equals'], $answer, true)
+ : is_scalar($answer) && (string) $answer === $field['when']['equals'];
+ if (! $matches) {
return false;
}
$ancestors[$key] = true;
@@ -349,9 +457,13 @@ class VirtualDesk
{
$findings = [];
$fields = $this->applicableFields($payload, $definition);
- $financeApplies = isset($fields['investment_amount'], $fields['own_finance'], $fields['other_finance']);
+ $financeApplies = count(array_filter(['investment_amount', 'own_finance', 'other_finance'], fn ($key) => ($fields[$key]['type'] ?? null) === 'number')) === 3;
$amounts = array_map(function ($key) use ($payload) {
- $value = (string) ($payload[$key] ?? '');
+ $raw = $payload[$key] ?? null;
+ if (! is_string($raw) && ! is_int($raw) && ! is_float($raw)) {
+ return null;
+ }
+ $value = (string) $raw;
if (! preg_match('/^\d{1,12}(?:\.\d{1,2})?$/', $value)) {
return null;
}
@@ -376,7 +488,7 @@ class VirtualDesk
/** @param array $input */
public function save(User $actor, string $id, array $input, bool $submit = false): \stdClass
{
- $data = Validator::make($input, ['version' => 'required|integer|min:1', 'payload' => 'required|array', 'consent' => $submit ? 'accepted' : 'nullable|boolean', 'reason' => 'nullable|string|max:3000', 'context_revision' => 'nullable|integer|min:0', 'context_reviewed' => 'nullable|boolean',
+ $data = Validator::make($input, ['version' => 'required|integer|min:1', 'payload' => 'present|array', 'consent' => $submit ? 'accepted' : 'nullable|boolean', 'reason' => 'nullable|string|max:3000', 'context_revision' => 'nullable|integer|min:0', 'context_reviewed' => 'nullable|boolean',
'tool_prefill' => 'nullable|array:draft_id,draft_version,snapshot_sha256', 'tool_prefill.draft_id' => 'required_with:tool_prefill|uuid',
'tool_prefill.draft_version' => 'required_with:tool_prefill|integer|min:1', 'tool_prefill.snapshot_sha256' => 'required_with:tool_prefill|string|size:64'])->validate();
@@ -397,6 +509,7 @@ class VirtualDesk
}
}
$payload = $this->validateFields($data['payload'], $this->definition($request), $submit);
+ $fieldAttachments = app(DeskAttachments::class)->snapshot($request, $payload, $this->definition($request), $submit);
if ($request->status !== 'returned' || in_array('context_opportunity', json_decode($request->editable_fields ?? '[]', true), true)) {
$payload = app(InvestmentConsumerScope::class)->bind($actor, $request->case_id, $payload, $submit);
}
@@ -415,10 +528,19 @@ class VirtualDesk
throw ValidationException::withMessages(['payload.investment_amount' => $findings[0]['explanation']]);
}
$case = $this->case($actor, $request->case_id, true, true);
+ abort_if($case->closed_at, 409, 'Dossier encerrado. As respostas guardadas continuam disponíveis para consulta.');
if ($submit || ($data['context_reviewed'] ?? false)) {
app(InvestorContextConsumers::class)->assertReviewed($actor, $case->id, $data, app(InvestorContextConsumers::class)->requestRevision($request));
}
- $snapshot = ['investment_context' => ['revision' => app(InvestorContext::class)->state($case)['revision']], 'payload' => $payload, 'service_version_id' => $request->service_version_id, 'documents' => DB::table('desk_documents as link')->join('documents as d', 'd.id', '=', 'link.document_id')->where('link.case_id', $case->id)->where(fn ($q) => $q->whereNull('link.request_id')->orWhere('link.request_id', $id))->get(['link.document_id', 'd.sha256', 'd.version_no', 'link.source_reference'])->all(), 'findings' => $findings, 'consent' => $submit, 'source' => config('virtual-desk.source')];
+ $declarations = [];
+ if ($submit) {
+ foreach ($this->definition($request)['fields'] as $key => $field) {
+ if ($field['type'] === 'consent' && $this->fieldApplies($key, $this->definition($request)['fields'], $payload) && in_array($payload[$key] ?? null, ['accepted', 'declined'], true)) {
+ $declarations[$key] = ['label' => $field['label'], 'statement' => $field['statement'], 'statement_sha256' => hash('sha256', $field['statement']), 'answer' => $payload[$key], 'actor_id' => $actor->id, 'declared_at' => now()->toIso8601String(), 'service_version_id' => $request->service_version_id];
+ }
+ }
+ }
+ $snapshot = ['investment_context' => ['revision' => app(InvestorContext::class)->state($case)['revision']], 'payload' => $payload, 'service_version_id' => $request->service_version_id, 'field_declarations' => $declarations, 'field_attachments' => $fieldAttachments, 'documents' => DB::table('desk_documents as link')->join('documents as d', 'd.id', '=', 'link.document_id')->where('link.case_id', $case->id)->where(fn ($q) => $q->whereNull('link.request_id')->orWhere('link.request_id', $id))->get(['link.document_id', 'd.sha256', 'd.version_no', 'link.source_reference'])->all(), 'findings' => $findings, 'consent' => $submit, 'source' => config('virtual-desk.source')];
DB::table('desk_revisions')->insert(['request_id' => $id, 'version' => $request->version, 'snapshot' => $this->encode(['payload' => $this->decode($request->payload), 'status' => $request->status, 'submitted_snapshot' => $request->submitted_snapshot ? $this->decode($request->submitted_snapshot) : null])]);
$updates = ['payload' => $this->encode($payload), 'version' => $request->version + 1, 'updated_at' => now()];
if ($submit) {
@@ -442,11 +564,13 @@ class VirtualDesk
/** @param array $data */
public function transition(User $actor, string $id, array $data): \stdClass
{
- $data = Validator::make($data, ['version' => 'required|integer|min:1', 'status' => ['required', Rule::in(array_keys(config('virtual-desk.request_states')))], 'reason' => 'required|string|min:3|max:5000', 'editable_fields' => 'nullable|array', 'editable_fields.*' => 'string|max:100'])->validate();
+ $data = Validator::make($data, ['version' => 'required|integer|min:1', 'status' => ['required', Rule::in(array_keys(config('virtual-desk.request_states')))], 'reason' => 'required|string|min:3|max:5000', 'editable_fields' => 'nullable|array', 'editable_fields.*' => 'string|max:100',
+ 'return_reason_code' => ['exclude_unless:status,returned', 'nullable', Rule::in(array_keys(config('product-metrics.return_reasons')))]])->validate();
return DB::transaction(function () use ($actor, $id, $data) {
$request = $this->request($actor, $id, false, true);
- $case = $this->case($actor, $request->case_id);
+ $case = $this->case($actor, $request->case_id, false, true);
+ $this->assertOpen($case);
abort_unless($request->version === (int) $data['version'], 409);
$cancel = $data['status'] === 'cancelled';
if ($cancel) {
@@ -464,7 +588,12 @@ class VirtualDesk
abort_if(array_diff($editable, [...array_keys($this->definition($request)['fields']), 'country', 'declared_origin_country_code']) !== [], 422);
DB::table('desk_requests')->where('id', $id)->update(['status' => $data['status'], 'version' => $request->version + 1, 'editable_fields' => json_encode($editable), 'closed_at' => in_array($data['status'], ['closed', 'cancelled'], true) ? now() : null, 'updated_at' => now()]);
$request = DB::table('desk_requests')->where('id', $id)->firstOrFail();
- $this->event($case, $actor, 'request_'.$data['status'], ['reason' => $data['reason'], 'editable_fields' => $editable], $request);
+ $classification = [];
+ if ($data['status'] === 'returned') {
+ $code = $data['return_reason_code'] ?? 'unspecified';
+ $classification = ['return_reason_code' => $code, 'return_reason_label' => config('product-metrics.return_reasons.'.$code), 'return_reason_definition' => config('product-metrics.version')];
+ }
+ $this->event($case, $actor, 'request_'.$data['status'], ['reason' => $data['reason'], 'editable_fields' => $editable, ...$classification], $request);
return $request;
});
@@ -475,14 +604,20 @@ class VirtualDesk
{
$data = Validator::make($data, ['version' => 'required|integer|min:1', 'stage' => ['required', Rule::in(array_keys(config('virtual-desk.steps')))],
'status' => ['required', Rule::in(array_keys(config('virtual-desk.step_states')))], 'reason' => 'required|string|min:3|max:3000',
- 'evidence' => 'nullable|string|max:5000', 'document_id' => 'nullable|uuid', 'valid_until' => 'nullable|date_format:Y-m-d', 'exception' => 'nullable|boolean'])->validate();
+ 'evidence' => 'nullable|string|max:5000', 'document_id' => 'nullable|uuid', 'document_link_id' => 'nullable|uuid', 'valid_until' => 'nullable|date_format:Y-m-d', 'exception' => 'nullable|boolean'])->validate();
return DB::transaction(function () use ($actor, $id, $data) {
$case = $this->case($actor, $id, false, true);
abort_unless($this->owns($actor, $case) || app(ScopedPortalAdministration::class)->deskCaseDecision($actor, $case->id), 403);
+ $this->assertOpen($case);
abort_unless((int) $case->version === (int) $data['version'], 409);
$workflow = json_decode($case->workflow, true, 512, JSON_THROW_ON_ERROR);
$current = $workflow[$data['stage']];
+ if ($data['document_link_id'] ?? null) {
+ $link = DB::table('desk_documents')->where('case_id', $id)->where('id', $data['document_link_id'])->first();
+ abort_unless($link && (! ($data['document_id'] ?? null) || $data['document_id'] === $link->document_id), 422, 'Seleccione um suporte associado a este dossier.');
+ $data['document_id'] = $link->document_id;
+ }
$decision = in_array($data['status'], ['completed', 'not_applicable'], true);
if ($decision) {
abort_unless(app(ScopedPortalAdministration::class)->deskCaseDecision($actor, $case->id) && ! $this->owns($actor, $case, false), 403, 'Conclusão documental exige revisão interna por outra pessoa autorizada.');
@@ -495,7 +630,9 @@ class VirtualDesk
}
}
if ($data['document_id'] ?? null) {
- $document = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->where('d.id', $data['document_id'])->whereNull('d.deleted_at')->first(['d.status', 'd.malware_scan_status', 'd.sha256', 'd.malware_scanned_sha256', 'l.valid_until']);
+ $document = DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->where('d.id', $data['document_id'])
+ ->when($data['document_link_id'] ?? null, fn ($q, $linkId) => $q->where('l.id', $linkId))->whereNull('d.deleted_at')->orderBy('l.created_at')->orderBy('l.id')
+ ->first(['d.status', 'd.malware_scan_status', 'd.sha256', 'd.malware_scanned_sha256', 'l.id as link_id', 'l.source_reference', 'l.stage', 'l.valid_until']);
abort_unless($document !== null, 422);
if ($decision) {
abort_unless($document->status === 'active' && $document->malware_scan_status === 'clean' && trim($document->sha256) === $document->malware_scanned_sha256 && (! $document->valid_until || $document->valid_until >= now()->toDateString()), 422, 'Documento ainda não consultável ou expirado.');
@@ -521,6 +658,7 @@ class VirtualDesk
} while ($changed);
}
$workflow[$data['stage']] = [...$current, 'status' => $data['status'], 'evidence' => $data['evidence'] ?? null, 'document_id' => $data['document_id'] ?? null,
+ 'document_link_id' => $document->link_id ?? null, 'document_source' => isset($document) ? ['source_reference' => $document->source_reference, 'stage' => $document->stage, 'valid_until' => $document->valid_until] : null,
'valid_until' => $data['valid_until'] ?? null, 'reason' => $data['reason'], 'reviewed_by' => $actor->id, 'updated_at' => now()->toIso8601String()];
DB::table('desk_cases')->where('id', $id)->update(['workflow' => json_encode($workflow), 'version' => $case->version + 1, 'updated_at' => now()]);
$case = DB::table('desk_cases')->where('id', $id)->firstOrFail();
@@ -535,7 +673,8 @@ class VirtualDesk
{
$id = (string) Str::uuid();
$version = $request->version ?? $case->version;
- DB::table('desk_events')->insert(['id' => $id, 'case_id' => $case->id, 'request_id' => $request->id ?? null, 'actor_id' => $actor->id, 'action' => $action, 'version' => $version, 'payload' => $this->encode($payload)]);
+ // Use the server event time, not PostgreSQL now() (which is fixed at the enclosing transaction start).
+ DB::table('desk_events')->insert(['id' => $id, 'case_id' => $case->id, 'request_id' => $request->id ?? null, 'actor_id' => $actor->id, 'action' => $action, 'version' => $version, 'payload' => $this->encode($payload), 'created_at' => now()]);
DB::table('audit_events')->insert(['source_system' => 'virtual-desk', 'entity_type' => $request ? 'desk_requests' : 'desk_cases', 'entity_id' => $request->id ?? $case->id, 'actor_user_id' => $actor->id, 'action' => $action,
'after_data' => json_encode(['event_id' => $id, 'event_version' => 1, 'version' => $version, 'case_id' => $case->id, 'source_hash' => config('virtual-desk.source.sha256')])]);
$recipients = [(int) $case->user_id];
diff --git a/app/Services/VirtualDeskInstallation.php b/app/Services/VirtualDeskInstallation.php
index 86966510..85fc1ed0 100644
--- a/app/Services/VirtualDeskInstallation.php
+++ b/app/Services/VirtualDeskInstallation.php
@@ -37,6 +37,9 @@ class VirtualDeskInstallation
sort($files);
$files = [...$files, ...PortalProfileAccess::fingerprintFiles()];
+ $files = [...$files, app_path('Services/DeskServiceEditor.php'), app_path('Services/DeskServiceAvailability.php'),
+ app_path('Http/Controllers/DeskServiceEditorController.php'), resource_path('js/components/desk-service-history.tsx'),
+ database_path('migrations/2026_11_03_010000_desk_service_effective_dates.php')];
return hash('sha256', json_encode(array_map(fn ($file) => hash_file('sha256', $file), $files), JSON_THROW_ON_ERROR));
}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index f7f6d9a3..4cdcf610 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -1,6 +1,7 @@
withMiddleware(function (Middleware $middleware): void {
+ $middleware->append(CollectPublicSearchMetrics::class);
$middleware->encryptCookies(except: ['appearance', 'sidebar_state', EnsureSimulationRecoveryCookie::NAME]);
$middleware->web(append: [
diff --git a/config/bvm-admission-guide.php b/config/bvm-admission-guide.php
new file mode 100644
index 00000000..87856ef8
--- /dev/null
+++ b/config/bvm-admission-guide.php
@@ -0,0 +1,101 @@
+ ['source' => $source, 'reference' => $reference, 'page' => $page];
+$item = static fn (string $id, string $text, array $citations, string $kind = 'requirement'): array => ['id' => $id, 'text' => $text, 'citations' => $citations, 'kind' => $kind];
+$cm = static fn (string $reference, int $page): array => $cite('cmvm', $reference, $page);
+$ad = static fn (string $reference, int $page): array => $cite('admission', $reference, $page);
+$sm = static fn (string $reference, int $page): array => $cite('second', $reference, $page);
+$tm = static fn (string $reference, int $page): array => $cite('third', $reference, $page);
+$all = ['official_shares', 'official_bonds', 'second_shares', 'second_bonds', 'third_shares'];
+$shares = ['official_shares', 'second_shares', 'third_shares'];
+$bonds = ['official_bonds', 'second_bonds'];
+$minimum = static fn (string $id, array $citations, string $relationship = ''): array => [...$item($id, $relationship.' Montante mínimo do período por obter. O exemplar de 2024 termina em 31/03/2025; não fornece um mínimo actual para esta preparação. Conferir o regulamento anual com a BVM ou o operador.', [...$citations, $cite('minimums_historical', 'Âmbito temporal; válido até 31/03/2025', 1)], 'gap'), 'value' => null, 'unit' => 'MZN'];
+
+return [
+ 'slug' => 'bolsa', 'version' => 'bvm-admission-2026-11-03-v1', 'title' => 'Preparar a admissão à Bolsa de Valores de Moçambique', 'reviewed_on' => '2026-11-03',
+ 'selection_label' => 'Que segmento e tipo de valor pretende preparar?', 'selection_hint' => 'Sem selecção, consulte os cinco percursos. Pode compará-los; o pedido real deve identificar o segmento e o tipo de valor. A selecção não confirma admissibilidade.', 'cards_title' => 'Requisitos por segmento e tipo de valor',
+ 'eligibility_title' => 'Intervenientes e decisões', 'preparation_title' => 'Etapas e encaminhamento',
+ 'scope' => 'Guião de preparação para acções e obrigações empresariais no Mercado de Cotações Oficiais e no Segundo Mercado, e acções no Terceiro Mercado. Identifica a redacção consultada e as lacunas. O portal não apresenta pedidos à BVM, não opera em bolsa e não concede admissão, registo ou financiamento.',
+ 'sources' => [
+ 'cmvm' => ['title' => 'Código do Mercado de Valores Mobiliários', 'url' => 'https://www.bvm.co.mz/documentos/codigo_mercado_valores_mobiliarios.pdf', 'edition' => 'DL 4/2009: exemplar BVM, aprovação do Conselho em 02/06/2009; data de publicação de 24/07/2009 identificada no DL 1/2022. Ler com as alterações abaixo.', 'locator' => 'Arts. 4, 60–70, 82–89 e 146–147; 68 páginas PDF', 'consulted_on' => '2026-11-03', 'sha256' => '5f576381eb42ffe3f64ab9848b5cfb61956dc123a87d3feb48d4f2ce5faf112e'],
+ 'commercial_2022' => ['title' => 'DL 1/2022 — Código Comercial republicado e alterações ao CMVM', 'url' => 'https://tsrm.gov.mz/wp-content/uploads/2025/10/Dec_Lei_1_2022.pdf', 'edition' => 'BR 99, I Série, 3.º Suplemento, 25/05/2022', 'locator' => 'Art. 4 do diploma; arts. 8 e 52 do CMVM alterados; art. 444 do Código Comercial', 'consulted_on' => '2026-11-03', 'sha256' => '8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f'],
+ 'admission' => ['title' => 'BVM — Processo de admissão à cotação', 'url' => 'https://www.bvm.co.mz/documentos/regulamentos/reg_processo_de_admissao_a_cotacao.pdf', 'edition' => 'Regulamento 1/GPCABVM/2010, 27/05/2010; exemplar BVM de 28 páginas', 'locator' => 'Arts. 2–8; Anexos A/B (documentos), C/D (prospectos)', 'consulted_on' => '2026-11-03', 'sha256' => '7cc5dddf65ef655f5f9e738d616d4c1ed51ba852f04b80f9eae668890d84022a'],
+ 'second' => ['title' => 'BVM — Segundo Mercado', 'url' => 'https://www.bvm.co.mz/documentos/legislacao/regulamento_segundo_mercado.pdf', 'edition' => 'Regulamento 2/GPCABVM/2010, 28/05/2010; exemplar BVM de 13 páginas', 'locator' => 'Arts. 1–8; Anexos A/B dos prospectos', 'consulted_on' => '2026-11-03', 'sha256' => 'c1bb9ba196e9f6d49a96b5857d687482d1f58bb7a9d5fd5d6e9d348c2a89ce92'],
+ 'third' => ['title' => 'BVM — Terceiro Mercado', 'url' => 'https://www.bvm.co.mz/documentos/regulamentos/RegulamentoTerceiroMercado.pdf', 'edition' => 'Regulamento 04/2021, 25/11/2021; revoga o 04/2019; seis páginas conferidas visualmente', 'locator' => 'Arts. 1–10; não reutilizar os prazos do regulamento revogado', 'consulted_on' => '2026-11-03', 'sha256' => 'a56adb4a8f91ff22dea870fa0c5b3f4c4faf5281ecbca8a7dc6d76248b03a340'],
+ 'central' => ['title' => 'Central de Valores Mobiliários — criação e funcionamento', 'url' => 'https://www.bvm.co.mz/documentos/central/CVM-Central_Valores_Mobiliarios.pdf', 'edition' => 'Decreto 25/2006, 23/08/2006; base institucional, sem substituir procedimentos posteriores', 'locator' => 'Arts. 1–2 do decreto; arts. 1–2 do regulamento anexo', 'consulted_on' => '2026-11-03', 'sha256' => '81e9a9d251fb7304fbe06ae769a652374142b22a8524ea00549d63247e9ea474'],
+ 'minimums_historical' => ['title' => 'BVM — Montantes mínimos de 2024 (histórico)', 'url' => 'https://www.bvm.co.mz/documentos/Montantes_Minimos_Admissao_Cotacao_2024.pdf', 'edition' => 'Regulamento 01/GPCABVM/2024, 27/03/2024; período terminado', 'locator' => 'Preâmbulo; válido até 31/03/2025. Não aplicado como mínimo de 2026.', 'consulted_on' => '2026-11-03', 'valid_until' => '2025-03-31', 'sha256' => '3cfbb7a55d2be4d1a01be7b249d10a940224537c5c868c98a7a7ef1d7a1e72e4'],
+ ],
+ 'requirements' => [
+ $item('legal_form', 'Conferir a constituição, estatutos, legitimidade do requerente e situação jurídica da emissão. As acções de sociedade por acções simplificada não podem ser registadas na CVM nem cotadas em Bolsa.', [$cm('Arts. 60(1)(a–b), 61(1), 67 e 84', 30), $cite('commercial_2022', 'Código Comercial, art. 444', 63)]),
+ $item('nominative', 'Usar valores nominativos. A redacção de 2022 não permite novas emissões ao portador; as referências antigas dos anexos devem ser lidas com essa alteração.', [$cite('commercial_2022', 'DL 1/2022, art. 4: nova redacção do art. 8 do CMVM', 1)]),
+ $item('annual_amount', 'O montante anual aplicável e o preçário actual ainda não foram recuperados. Esta lacuna não é um valor zero e não impede guardar a preparação; deve ser esclarecida com a BVM/operador para o pedido real.', [$cm('Arts. 60(1)(c), 61(2)(a), 86(a), 87(a) e 100', 30)], 'gap'),
+ ],
+ 'instruments' => [
+ 'official_shares' => ['title' => 'Mercado de Cotações Oficiais — acções', 'description' => 'Pedido de acções no MCO; condições cumulativas, sujeito à apreciação da BVM.', 'risks' => ['A admissão não garante a viabilidade ou o valor futuro da empresa.', 'Dispensas excepcionais dependem da BVM; não são aplicadas pelo portal.'], 'prepare' => [], 'sources' => ['cmvm', 'admission'], 'requirements' => [
+ $minimum('official_shares_minimum', [$cm('Art. 60(1)(c)', 30)]),
+ $item('official_reports', 'Relatórios de gestão e contas anuais dos dois exercícios anteriores. A derrogação excepcional desta condição é da BVM, com informação suficiente para os investidores.', [$cm('Art. 60(1)(d) e (2)', 30)]),
+ $item('official_dispersion', 'Livre negociação, todas as acções emitidas da mesma categoria e dispersão suficiente até à admissão. O art. 60(3) presume suficiência com 15% ou, em alternativa, 250.000 acções e regular funcionamento do mercado.', [$cm('Art. 60(1)(e–g) e (3)', 30)]),
+ $item('official_finances', 'Apresentar situação económico-financeira adequada e preparar o prospecto de acções.', [$cm('Art. 60(1)(h)', 30), $ad('Art. 7(9); Anexo C', 7)]),
+ ]],
+ 'official_bonds' => ['title' => 'Mercado de Cotações Oficiais — obrigações', 'description' => 'Pedido de dívida empresarial; a emissão e a admissão são actos distintos.', 'risks' => ['Conferir as condições de reembolso e pagamento de juros; admissão não é garantia de pagamento.'], 'prepare' => [], 'sources' => ['cmvm', 'admission'], 'requirements' => [
+ $minimum('official_bonds_minimum', [$cm('Art. 61(2)(a)', 30)]),
+ $item('bond_baseline', 'Aplicar, com adaptações, as condições legais, contas anteriores, livre negociação, categoria e adequação financeira remetidas pelo art. 61(1); comprovar capital e juros através de análise prudente.', [$cm('Art. 61(1–2), remetendo ao art. 60', 30)]),
+ $item('bond_conversion', 'Nas obrigações convertíveis ou com direito a acções, conferir a admissão anterior ou simultânea das acções. A autorização excepcional do art. 61(4) depende da BVM e da informação necessária.', [$cm('Art. 61(3–4)', 30)]),
+ $item('bond_prospectus', 'Preparar o prospecto de obrigações segundo o Anexo D e a instrução do Anexo B.', [$ad('Art. 4; art. 7(10); Anexos B e D', 13)]),
+ ]],
+ 'second_shares' => ['title' => 'Segundo Mercado — acções', 'description' => 'Segmento de entidades nacionais, com adaptações ao MCO; nacionalidade do emitente é distinta da dos seus investidores.', 'risks' => ['Não confundir uma exigência reduzida com dispensa geral de documentos ou de informação.'], 'prepare' => [], 'sources' => ['cmvm', 'second', 'admission'], 'requirements' => [
+ $minimum('second_shares_minimum', [$cm('Art. 86(a)', 39)], 'O mínimo anual não deve ser inferior a um quarto do mínimo do MCO para acções.'),
+ $item('second_age', 'Existência jurídica de um ano, não derrogável, com relatório de gestão e contas de pelo menos nove meses de actividade.', [$cm('Art. 86(b)', 40)]),
+ $item('second_dispersion', 'Dispersão de pelo menos 5% do capital subscrito representado pela categoria; demais condições do art. 60 com as modificações do art. 86.', [$cm('Arts. 84 e 86(c)', 40)]),
+ $item('second_share_prospectus', 'Publicar prospecto aprovado; usar o Anexo A do Regulamento do Segundo Mercado para o seu conteúdo, distinguindo-o do Anexo A de instrução documental.', [$sm('Art. 3 e Anexo A', 2), $ad('Art. 4 e Anexo A', 10)]),
+ ]],
+ 'second_bonds' => ['title' => 'Segundo Mercado — obrigações', 'description' => 'Dívida de entidades nacionais, com condições próprias do art. 87.', 'risks' => ['Conferir a capacidade de pagamento e as condições da emissão; redução de mínimos não garante reembolso.'], 'prepare' => [], 'sources' => ['cmvm', 'second', 'admission'], 'requirements' => [
+ $minimum('second_bonds_minimum', [$cm('Art. 87(a)', 40)], 'O mínimo anual não deve ser inferior a um quarto do mínimo do MCO para obrigações.'),
+ $item('second_bond_baseline', 'Condições do art. 61 com adaptações do art. 87; aplica-se um ano de existência jurídica e contas de pelo menos nove meses, sem derrogação desse período.', [$cm('Arts. 87(b) e 86(b)', 40)]),
+ $item('second_bond_conversion', 'Para convertíveis ou direitos a acções, conferir a cotação das acções das entidades relevantes no Segundo Mercado ou MCO, anterior ou simultânea nos termos do art. 87(c).', [$cm('Art. 87(c)', 40)]),
+ $item('second_bond_prospectus', 'Preparar o prospecto do Anexo B do Regulamento do Segundo Mercado e os documentos do Anexo B do processo de admissão; os anexos têm finalidades diferentes.', [$sm('Art. 3 e Anexo B', 2), $ad('Art. 4 e Anexo B', 13)]),
+ ]],
+ 'third_shares' => ['title' => 'Terceiro Mercado — acções', 'description' => 'Acções de empresas constituídas ao abrigo do direito moçambicano que ainda não reúnam a totalidade das condições do MCO ou Segundo Mercado.', 'risks' => ['A passagem a outro mercado não é automática.', 'Incumprimento de requisitos ou de informação pode conduzir à exclusão.'], 'prepare' => [], 'sources' => ['third', 'admission', 'cmvm'], 'requirements' => [
+ $minimum('third_minimum', [$tm('Art. 2(1)(a): relação com mínimo do Segundo Mercado', 1)], 'O mínimo anual não deve ser inferior a 25% do estabelecido para o Segundo Mercado.'),
+ $item('third_finances', 'Evidenciar equilíbrio financeiro mínimo e resultados operacionais não negativos; demonstrações PGC-NIRF preparadas e assinadas por contabilista certificado pela OCAM.', [$tm('Art. 2(1)(b)', 2)]),
+ $item('third_entry_audit', 'Dispensa de apresentação de contas auditadas no momento do pedido. Não é dispensa permanente de informação financeira ou de todos os documentos do processo.', [$tm('Art. 2(1)(c) e art. 8', 2)], 'exception'),
+ $item('third_entry_dispersion', 'Dispensa de dispersão no momento do pedido. Posteriormente, promover a conformidade no horizonte de até dois anos; uma prorrogação excepcional por mais um ano exige fundamentação, sem extensão automática pelo portal.', [$tm('Art. 2(1)(d), (2–5) e art. 5(1)', 2)], 'exception'),
+ $item('third_dispersion', 'Na dispersão posterior contam accionistas com participação individual não superior a 5%; soma mínima de 15% ou 5% para MCO ou Segundo Mercado, respectivamente, com apreciação da BVM.', [$tm('Art. 5(2)', 4)]),
+ $item('third_reporting', 'Apresentar demonstrações e relatório de evolução semestrais. A falta de informação pode levar à exclusão.', [$tm('Art. 6(1–3)', 4)]),
+ $item('third_transition', 'A BVM aprecia a passagem ao MCO/Segundo Mercado quando os requisitos estiverem preenchidos. Terminado o prazo aplicável sem os alcançar, o regulamento prevê exclusão.', [$tm('Art. 2(4–6)', 3)]),
+ ]],
+ ],
+ 'documents' => [
+ ['id' => 'corporate_documents', 'title' => 'Deliberações, estatutos e certidão', 'text' => 'Reutilizar cópias actualizadas da deliberação da emissão, estatutos e registo da entidade, capital e órgãos. Não pedir nova introdução de dados já documentados.', 'paths' => $all, 'citations' => [$ad('Anexo A, 1–3; Anexo B, 1', 10)]],
+ ['id' => 'accounts', 'title' => 'Relatórios, contas, fiscalização e publicações', 'text' => 'Conferir o período de contas exigido pelo segmento escolhido e as respectivas publicações; preservar o período efectivamente utilizado.', 'paths' => $all, 'citations' => [$ad('Anexo A, 4–6; Anexo B, 1', 10), $cm('Arts. 60(1)(d), 61(1), 86(b) e 87(b)', 30)]],
+ ['id' => 'third_signed_accounts', 'title' => 'Demonstrações financeiras assinadas por contabilista certificado', 'text' => 'Para a entrada no Terceiro Mercado, demonstrações PGC-NIRF preparadas e assinadas por contabilista certificado pela OCAM. A dispensa de contas auditadas não dispensa esta preparação.', 'paths' => ['third_shares'], 'citations' => [$tm('Art. 2(1)(b–c)', 2)]],
+ ['id' => 'audit', 'title' => 'Auditoria ou certificação aplicável', 'text' => 'Conferir a auditoria independente/certificação exigida e a habilitação aplicável, lendo a designação institucional do exemplar de 2010 no seu período.', 'paths' => ['official_shares', 'official_bonds', 'second_shares', 'second_bonds'], 'citations' => [$ad('Anexo A, 5; Anexo B, 1', 10)]],
+ ['id' => 'securities', 'title' => 'Registo da emissão ou espécimes dos títulos nominativos', 'text' => 'Conferir o certificado da conta de registo, ou espécimes de títulos quando essa representação for aplicável. As formalidades operacionais actuais da CVM devem ser confirmadas no respectivo serviço.', 'paths' => $all, 'citations' => [$ad('Anexo A, 7; Anexo B, 1', 10), $cite('commercial_2022', 'Art. 4: art. 8 do CMVM', 1)]],
+ ['id' => 'ownership', 'title' => 'Detentores do capital e participações', 'text' => 'Listagem de participações e suporte da assembleia mais recente, ou informação posterior aplicável. Manter estes documentos no dossier privado.', 'paths' => $shares, 'citations' => [$ad('Anexo A, 8', 11)]],
+ ['id' => 'prospectus', 'title' => 'Projecto de prospecto conforme o segmento', 'text' => 'MCO: Anexos C/D do processo de admissão. Segundo Mercado: Anexos A/B do regulamento desse mercado. Terceiro Mercado: regras subsidiárias de admissão em tudo o que não contrariar o regulamento de 2021. Conferir dispensas específicas com a BVM.', 'paths' => $all, 'citations' => [$ad('Art. 7(9–10), Anexo A, 9, Anexo B, 1', 7), $sm('Art. 3', 2), $tm('Art. 8', 5)]],
+ ['id' => 'updated_information', 'title' => 'Declaração de actualidade das informações', 'text' => 'Conferir a declaração relativa a factos relevantes entre as contas, auditoria/prospecto e o pedido. O regulamento de 2021 não reproduz uma dispensa geral do ponto 10 do Anexo A; não importar essa exclusão de referências ao regulamento revogado.', 'paths' => $all, 'citations' => [$ad('Anexo A, 10; Anexo B, 1', 11), $tm('Arts. 8–9', 5)]],
+ ['id' => 'new_shares', 'title' => 'Se forem novas acções de categoria já cotada', 'text' => 'Conferir documentos adicionais do aumento de capital e eventuais simplificações por incorporação de reservas; não são documentos exigidos indistintamente a todos os pedidos iniciais.', 'paths' => $shares, 'citations' => [$ad('Art. 3(3), art. 8 e Anexo A, 11', 7)]],
+ ['id' => 'bond_issue', 'title' => 'Documentos específicos do empréstimo obrigacionista', 'text' => 'Registo comercial da emissão e notificação do Banco de Moçambique quando aplicáveis; datas de publicação da ficha técnica e dos factos previstos no Anexo B, 4, conforme a operação.', 'paths' => $bonds, 'citations' => [$ad('Anexo B, 2–4', 13)]],
+ ],
+ 'eligibility' => [
+ ['text' => 'Banco de Moçambique: supervisão e atribuições relativas às ofertas públicas. Registo de uma oferta e admissão à cotação são actos distintos.', 'sources' => ['cmvm'], 'citations' => [$cm('Art. 4, incluindo n.º 2(e); arts. 146–147 para venda/troca públicas', 4)]],
+ ['text' => 'BVM: apreciação e decisão de admissão, suspensão e exclusão; o operador patrocina o pedido e é o interlocutor do processo. O portal apenas prepara e conserva referências.', 'sources' => ['cmvm', 'admission'], 'citations' => [$cm('Arts. 67–69 e 85', 32), $ad('Arts. 2 e 6', 1)]],
+ ['text' => 'Central de Valores Mobiliários (CVM): serviço de registo e controlo, gerido pela BVM. Não é um regulador separado nem deve ser confundido com organismos estrangeiros com a mesma sigla.', 'sources' => ['central'], 'citations' => [$cite('central', 'Arts. 1–2 do decreto e art. 2 do regulamento anexo', 1)]],
+ ['text' => 'Terceiro Mercado: a BVM concede a admissão mediante audição das instituições parceiras enumeradas no regulamento. A audição não é uma aprovação automática por esses parceiros ou pelo portal.', 'sources' => ['third'], 'citations' => [$tm('Art. 3', 3)]],
+ ],
+ 'preparation' => [
+ ['title' => '1. Conferir emitente, emissão e segmento', 'text' => 'Reutilizar os dados e documentos do dossier. Distinguir emitente nacional/estrangeiro da nacionalidade dos investidores; conferir autorizações especiais apenas quando aplicáveis.', 'responsible' => 'Emitente, com o operador e assessoria competente', 'sources' => ['cmvm', 'commercial_2022'], 'citations' => [$cm('Arts. 31–34, 60–64 e 84', 20)]],
+ ['title' => '2. Organizar o pedido através de operador', 'text' => 'Conferir a habilitação actual do operador e acordar o patrocínio. Preparar requerimento, instrução documental e prospecto; as comunicações seguem o operador.', 'responsible' => 'Emitente/requerente e operador de bolsa', 'sources' => ['admission'], 'citations' => [$ad('Arts. 2–4', 1)]],
+ ['title' => '3. Apresentar e responder a esclarecimentos', 'text' => 'A apresentação real é feita fora do portal pelo operador. Conservar referência, documentos e versões; a BVM pode pedir elementos e alterações ao prospecto.', 'responsible' => 'Operador e BVM; emitente fornece elementos', 'sources' => ['admission'], 'citations' => [$ad('Arts. 2 e 5', 4)]],
+ ['title' => '4. Registar a decisão externa', 'text' => 'O CMVM prevê notificação até 30 dias após o pedido ou após os elementos complementares solicitados. Não converter isso em aprovação por silêncio ou prazo automático do portal.', 'responsible' => 'BVM comunica ao operador', 'sources' => ['cmvm', 'admission'], 'citations' => [$cm('Art. 69(1)', 33), $ad('Art. 6', 4)]],
+ ['title' => '5. Publicação e formalidades antes da negociação', 'text' => 'Conferir aprovação/publicação do prospecto e registos operacionais. O art. 70(3) refere publicação até oito dias antes do início das transacções; há dispensas e regras próprias a conferir. Guardar não publica nem regista na CVM.', 'responsible' => 'Emitente, operador e BVM/CVM', 'sources' => ['cmvm', 'admission', 'central'], 'citations' => [$cm('Art. 70(1–5)', 33), $ad('Art. 7', 5)]],
+ ['title' => '6. Acompanhar obrigações de permanência', 'text' => 'Conservar informação e evidências no percurso existente. Para o Terceiro Mercado, acompanhar a informação semestral e o horizonte de conformidade de dois anos, com eventual prorrogação excepcional fundamentada de um ano.', 'responsible' => 'Emitente, operador e BVM', 'sources' => ['cmvm', 'second', 'third'], 'citations' => [$cm('Arts. 73–81', 34), $sm('Art. 4', 2), $tm('Arts. 2, 5 e 6', 2)]],
+ ],
+ 'next' => ['Guardar esta edição no dossier e ligar os documentos já existentes.', 'Esclarecer os montantes e encargos actuais com a BVM e o operador antes do pedido real.', 'Usar o operador para o encaminhamento real; conservar no percurso financeiro as referências e decisões externas documentadas.'],
+ 'handoffs' => [
+ ['title' => 'Consultar a BVM para preparar o encaminhamento pelo operador', 'url' => 'https://www.bvm.co.mz/empresas/0/0', 'note' => 'Canal oficial de informação para empresas; conferir a habilitação actual do operador e os requisitos do pedido.'],
+ ['title' => 'Consultar os serviços e intervenientes da CVM', 'url' => 'https://www.bvm.co.mz/cvm/1/0', 'note' => 'Confirmar os procedimentos operacionais actuais do registo; a preparação do dossier mantém-se no portal.'],
+ ],
+ 'limits' => ['Montantes mínimos e encargos actuais permanecem por determinar; nenhum valor histórico é convertido em mínimo de 2026.', 'O guião não codifica todos os procedimentos operacionais da CVM, incluindo o regulamento de 2025 referido no portal oficial; confirmar o exemplar e as formalidades actuais com o serviço.', 'Fundos públicos/equiparados, unidades de participação e outros valores têm regimes próprios (CMVM arts. 58–59 e 62). Não lhes aplicar automaticamente os documentos empresariais deste guião.', 'Valores estrangeiros exigem conferência dos arts. 33, 63–64 e normas aplicáveis. Segundo e Terceiro Mercado têm âmbito nacional do emitente; isto não exclui automaticamente investidores estrangeiros numa entidade moçambicana.', 'A base de 2009 é lida com as alterações de 2022 identificadas. As fontes e redacções constam de cada requisito; condições especiais e alterações posteriores não abrangidas devem ser conferidas no pedido real.'],
+];
diff --git a/config/company-comparison.php b/config/company-comparison.php
new file mode 100644
index 00000000..9be4593f
--- /dev/null
+++ b/config/company-comparison.php
@@ -0,0 +1,30 @@
+ 'company-comparison-20261102-v1',
+ 'source' => [
+ 'title' => 'Código Comercial — Decreto-Lei n.º 1/2022, de 25 de Maio',
+ 'edition' => 'BR n.º 99, I Série, 3.º Suplemento, páginas 786 (83–158)',
+ 'issued_on' => '2022-05-25', 'consulted_on' => '2026-11-02',
+ 'url' => 'https://tsrm.gov.mz/wp-content/uploads/2025/10/Dec_Lei_1_2022.pdf',
+ 'sha256' => '8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f',
+ ],
+ 'questions' => [
+ 'purpose' => ['label' => 'O que pretende preparar?', 'options' => ['unknown' => 'Ainda por definir', 'new' => 'Uma nova empresa ou sociedade', 'representation' => 'Representação de uma sociedade estrangeira existente', 'cooperation' => 'Cooperação entre entidades existentes']],
+ 'participants' => ['label' => 'Quantos titulares, sócios ou accionistas estão previstos?', 'options' => ['unknown' => 'Ainda não sei', 'one' => 'Um', 'several' => 'Mais de um']],
+ 'participation' => ['label' => 'Como pretende organizar as participações?', 'options' => ['unknown' => 'Ainda por definir', 'quotas' => 'Em quotas', 'shares' => 'Em acções', 'work' => 'Quero comparar a contribuição em trabalho']],
+ 'capital' => ['label' => 'O capital e as contribuições já estão definidos?', 'options' => ['unknown' => 'Ainda não sei', 'defined' => 'Definidos para discussão', 'to_define' => 'Por definir']],
+ 'management' => ['label' => 'Que aspectos da gestão pretende esclarecer?', 'options' => ['unknown' => 'Ainda por definir', 'participants' => 'Poderes dos sócios e regras de deliberação', 'appointed' => 'Nomeação e mandato da administração', 'both' => 'Ambos os aspectos']],
+ 'responsibility' => ['label' => 'Pretende comparar regimes de responsabilidade limitada?', 'options' => ['unknown' => 'Ainda por definir', 'limited' => 'Sim', 'review' => 'Preciso de esclarecer a responsabilidade']],
+ 'listing' => ['label' => 'Pretende negociar acções em Bolsa?', 'options' => ['unknown' => 'Ainda não sei', 'yes' => 'Sim', 'no' => 'Não']],
+ 'regulated' => ['label' => 'A actividade tem regras profissionais ou sectoriais próprias?', 'options' => ['unknown' => 'Ainda não confirmei', 'yes' => 'Sim', 'no' => 'Não identifiquei regras específicas']],
+ 'preferred' => ['label' => 'Que alternativa quer aprofundar?', 'options' => ['unknown' => 'Ainda sem preferência', 'individual' => 'Empresário individual', 'collective' => 'Sociedade em nome colectivo limitada', 'quotas' => 'Sociedade por quota', 'anonymous' => 'Sociedade anónima', 'simplified' => 'Sociedade por acções simplificada']],
+ ],
+ 'forms' => [
+ 'individual' => ['title' => 'Empresário individual', 'description' => 'Titular individual; o regime de responsabilidade depende do registo.', 'articles' => 'Artigos 3 e 59', 'page' => 9],
+ 'collective' => ['title' => 'Sociedade em nome colectivo de responsabilidade limitada', 'description' => 'Pelo menos dois sócios; admite contribuição em capital ou trabalho.', 'articles' => 'Artigos 67 e 262–266', 'page' => 39],
+ 'quotas' => ['title' => 'Sociedade por quota', 'description' => 'Capital em quotas; pode adoptar modalidade unipessoal.', 'articles' => 'Artigos 257–258 e 281–285', 'page' => 42],
+ 'anonymous' => ['title' => 'Sociedade anónima', 'description' => 'Capital em acções; pode adoptar modalidade unipessoal.', 'articles' => 'Artigos 257–258 e 320–322', 'page' => 47],
+ 'simplified' => ['title' => 'Sociedade por acções simplificada', 'description' => 'Uma ou mais pessoas; acções sem negociação em Bolsa.', 'articles' => 'Artigos 257 e 441–444', 'page' => 63],
+ ],
+];
diff --git a/config/investment-guides.php b/config/investment-guides.php
new file mode 100644
index 00000000..0dc79014
--- /dev/null
+++ b/config/investment-guides.php
@@ -0,0 +1,37 @@
+ require __DIR__.'/bvm-admission-guide.php',
+ 'capitalizacao' => [
+ 'slug' => 'capitalizacao', 'version' => 'capitalizacao-2026-11-02-v1', 'title' => 'Preparar a capitalização do negócio',
+ 'reviewed_on' => '2026-11-02',
+ 'scope' => 'Orientação para preparar uma conversa com financiadores. As condições dependem da contraparte, do instrumento, do contrato e das regras aplicáveis. O portal não decide elegibilidade, recomenda um investimento, oferece valores mobiliários ou assume compromissos.',
+ 'sources' => [
+ 'bni' => ['title' => 'BNI — Capital de Risco', 'url' => 'https://www.bni.co.mz/banca-de-investimento/capital-de-risco/', 'edition' => 'Página sem data editorial; exemplar consultado em 02/11/2026', 'locator' => 'Capital de Risco, dois parágrafos descritivos', 'consulted_on' => '2026-11-02', 'sha256' => 'fbeaab84c4cad22ee63e5c1dfb61ea3206333885ddd80c8001d37a3f49d2820e'],
+ 'ifc_equity' => ['title' => 'IFC — Equity Investments', 'url' => 'https://www.ifc.org/en/what-we-do/products-and-services/equity-investments', 'edition' => 'Página sem data editorial; exemplar consultado em 02/11/2026', 'locator' => 'Equity investments; IFC Nominee Directorships', 'consulted_on' => '2026-11-02', 'sha256' => 'c9e07821dfb84310ad41c4811b8c7267b880593d72b4ff2011124b986c8f9433'],
+ 'ifc_loans' => ['title' => 'IFC — Loans', 'url' => 'https://www.ifc.org/en/what-we-do/products-and-services/loans', 'edition' => 'Página sem data editorial; exemplar consultado em 02/11/2026', 'locator' => 'Loans, financiamento directo e através de intermediários', 'consulted_on' => '2026-11-02', 'sha256' => '0130c12657abfbd8c80011be213f555424abe4cfc50eae4eb444b935edf65904'],
+ 'ifc_apply' => ['title' => 'IFC — How to Apply for Financing', 'url' => 'https://www.ifc.org/en/what-we-do/products-and-services/how-to-apply-for-financing', 'edition' => 'Página sem data editorial; exemplar consultado em 02/11/2026', 'locator' => 'Eligibility; Investment Proposals, pontos 1–7', 'consulted_on' => '2026-11-02', 'sha256' => 'fa6faed394591dcf6afff76bc7e4fff539d4a3587ca1b303a08f863759dd3437'],
+ 'debt_equity' => ['title' => 'Chase for Business — Debt vs. Equity Financing', 'url' => 'https://www.chase.com/business/knowledge-center/grow/debt-vs-equity-financing', 'edition' => 'Artigo educativo: conceitos gerais, sem importar regras dos EUA para Moçambique; consulta 02/11/2026', 'locator' => 'What is debt financing?; What is equity financing?', 'consulted_on' => '2026-11-02', 'sha256' => 'baeb5424bfdadcb011787404fbc4ddc39cab560593232e4799bc93abff4f61bf'],
+ ],
+ 'instruments' => [
+ 'equity' => ['title' => 'Capital próprio e entrada de sócios', 'description' => 'O investidor adquire uma participação e partilha os resultados. Conferir avaliação, participação após a entrada e direitos de decisão.', 'risks' => ['Diluição das participações e partilha de controlo e resultados.', 'O valor e o retorno podem ser inferiores ao esperado; não há retorno garantido.'], 'prepare' => ['Estrutura actual e proposta das participações.', 'Termos de governação e distribuição de resultados para discussão.'], 'sources' => ['ifc_equity', 'debt_equity']],
+ 'private_equity' => ['title' => 'Private equity e capital de desenvolvimento', 'description' => 'Participação no capital de empresas não cotadas. O BNI descreve participações temporárias e capital de desenvolvimento; a sua oferta não é uma regra geral de elegibilidade.', 'risks' => ['Negociar avaliação, poderes de decisão e condições de saída.', 'A saída pode depender de um comprador e das condições acordadas.'], 'prepare' => ['Plano de crescimento, equipa e necessidades de financiamento.', 'Proposta de avaliação e horizonte de saída a negociar.'], 'sources' => ['bni', 'ifc_equity', 'debt_equity']],
+ 'debt' => ['title' => 'Dívida e empréstimos', 'description' => 'Financiamento com obrigações de reembolso nos termos acordados. Conferir juros, moeda, garantias, vencimentos e restrições contratuais.', 'risks' => ['As prestações podem ser exigíveis mesmo com resultados abaixo do previsto.', 'Conferir risco cambial, custo total e consequências de incumprimento.'], 'prepare' => ['Fluxos de caixa e capacidade de reembolso em diferentes cenários.', 'Dívidas, garantias e condições existentes a conferir com a contraparte.'], 'sources' => ['ifc_loans', 'debt_equity']],
+ 'hybrid' => ['title' => 'Instrumentos híbridos e convertíveis', 'description' => 'Podem combinar características de dívida e capital. A IFC refere empréstimos convertíveis, participativos e acções preferenciais; cada contrato exige análise própria.', 'risks' => ['Conferir conversão, prioridade, remuneração e eventual diluição.', 'Não presumir que um instrumento reúne as vantagens de dívida e capital sem os respectivos riscos.'], 'prepare' => ['Termos de conversão, prioridades e direitos propostos.', 'Impacto em participações, decisões e pagamentos nos cenários acordados.'], 'sources' => ['ifc_equity']],
+ ],
+ 'eligibility' => [
+ ['text' => 'Confirmar com cada entidade sectores, território, fase do negócio, dimensão, instrumento e documentação aceites. Os exemplos seguintes pertencem às entidades citadas.', 'sources' => ['bni', 'ifc_apply']],
+ ['text' => 'O BNI descreve fundos dirigidos a investidores qualificados e empresas com potencial de crescimento e gestão profissional. Isto não equivale a aprovação de uma empresa ou investidor pelo portal.', 'sources' => ['bni']],
+ ['text' => 'A IFC apresenta critérios técnicos, económicos, ambientais e sociais e distingue financiamento directo de intermediação para empresas menores. A documentação e a decisão são da IFC; estes critérios não são aplicados automaticamente a outros financiadores.', 'sources' => ['ifc_apply']],
+ ],
+ 'preparation' => [
+ ['title' => 'Definir o pedido', 'text' => 'Resumo do projecto, finalidade do financiamento, montante e calendário pretendidos. Reutilize o dossier e os pressupostos já registados.', 'sources' => ['ifc_apply']],
+ ['title' => 'Conferir promotores e gestão', 'text' => 'Historial, informação financeira e organização da gestão; identificar informação em falta sem a inventar.', 'sources' => ['ifc_apply']],
+ ['title' => 'Preparar a viabilidade', 'text' => 'Mercado, vendas, custos, recursos técnicos e impactos ambientais e sociais. Identificar pressupostos e cenários adversos.', 'sources' => ['ifc_apply']],
+ ['title' => 'Organizar documentos e condições', 'text' => 'Plano de negócio, demonstrações e projecções financeiras, estrutura de financiamento e termos a discutir. A lista final deve ser confirmada com a entidade destinatária.', 'sources' => ['ifc_apply']],
+ ['title' => 'Conferir regras e negociação', 'text' => 'Regulação aplicável, entrada e repatriamento de capital quando relevantes, direitos, garantias e condições da operação. Registar as questões para análise competente.', 'sources' => ['ifc_apply', 'ifc_equity']],
+ ],
+ 'next' => ['Conferir os dados e documentos no mesmo dossier.', 'Discutir com a contraparte o instrumento e os termos adequados à operação.', 'Guardar a proposta e as decisões documentadas nos passos financeiros existentes. Guardar este guia não submete um pedido nem conclui essas etapas.'],
+ 'limits' => ['Os exemplos de produtos não confirmam disponibilidade, preço, aceitação ou adequação a um caso concreto.', 'A admissão à Bolsa tem requisitos próprios. Este guia não avalia segmentos, mínimos ou admissibilidade à cotação.', 'Não são calculados retorno, avaliação, diluição, taxas, benefícios fiscais ou probabilidade de aprovação neste guia.'],
+ ],
+];
diff --git a/config/product-experiments.php b/config/product-experiments.php
new file mode 100644
index 00000000..8f675588
--- /dev/null
+++ b/config/product-experiments.php
@@ -0,0 +1,17 @@
+ 'product-experiments-2026-11-03-v1',
+ 'states' => ['draft' => 'Rascunho', 'planned' => 'Plano registado', 'observing' => 'Observação declarada', 'reviewed' => 'Resultado e decisão registados', 'cancelled' => 'Cancelado'],
+ 'change_kinds' => ['journey' => 'Jornada', 'content' => 'Conteúdo', 'form' => 'Formulário', 'campaign' => 'Campanha'],
+ 'decisions' => ['adopt' => 'Adoptar', 'continue' => 'Continuar a observar', 'revise' => 'Reformular', 'reject' => 'Não adoptar', 'inconclusive' => 'Inconclusivo'],
+ 'fields' => [
+ 'title' => 'Título', 'state' => 'Estado do registo', 'change_kind' => 'Tipo de alteração', 'reference' => 'Referência e versão da alteração',
+ 'hypothesis' => 'Hipótese', 'indicator_id' => 'Indicador', 'indicator_title' => 'Nome do indicador próprio', 'indicator_definition' => 'Definição e fórmula do indicador próprio', 'indicator_unit' => 'Unidade do indicador próprio',
+ 'period_from' => 'Início previsto (UTC)', 'period_to' => 'Fim previsto (UTC)', 'segment' => 'Segmento e critérios de inclusão',
+ 'control' => 'Situação de controlo', 'variant' => 'Alteração em comparação', 'assignment' => 'Método de comparação e distribuição', 'criterion' => 'Critério de avaliação',
+ 'transparency' => 'Como se preserva a transparência', 'consent' => 'Como se preserva o consentimento', 'security' => 'Como se preserva a segurança', 'equality' => 'Como se preserva a igualdade de tratamento', 'preserves_requirements' => 'Preservação dos quatro requisitos',
+ 'observed_from' => 'Início observado (UTC)', 'observed_to' => 'Fim observado (UTC)', 'control_result' => 'Resultado observado no controlo', 'variant_result' => 'Resultado observado na variante',
+ 'result' => 'Síntese do resultado', 'limitations' => 'Limitações e diferenças entre grupos', 'evidence' => 'Referências das evidências utilizadas', 'decision' => 'Decisão declarada', 'decision_reason' => 'Fundamento da decisão', 'report_service' => 'Serviço do relatório de contexto',
+ ],
+];
diff --git a/config/product-metrics.php b/config/product-metrics.php
new file mode 100644
index 00000000..1d890aca
--- /dev/null
+++ b/config/product-metrics.php
@@ -0,0 +1,26 @@
+ 'product-usage-2026-11-03-v3',
+ 'return_reasons' => [
+ 'unspecified' => 'Ainda sem classificação',
+ 'validation_error' => 'Erro nos dados preenchidos',
+ 'missing_documents' => 'Documentação em falta',
+ 'other' => 'Outro motivo',
+ ],
+ 'unmeasured' => [
+ ['id' => 'acquisition', 'title' => 'Aquisição e visitas', 'reason' => 'Não existe uma fonte de visitas/campanhas com cobertura e unidade definidas. Contas ou pedidos não representam visitas.'],
+ ['id' => 'activation', 'title' => 'Activação de utilizadores', 'reason' => 'Falta uma definição de coorte e evento de activação; criar um dossier não prova, por si, a activação de uma pessoa.'],
+ ['id' => 'search', 'title' => 'Cobertura de pesquisa ainda incompleta', 'reason' => 'Há contagens diárias anónimas das respostas de primeira página nos canais instrumentados. As restantes pesquisas, identificação de pessoas/pesquisas únicas e cobertura integral não estão demonstradas; a taxa usa apenas as respostas registadas.'],
+ ['id' => 'public_comparison', 'title' => 'Comparações em consulta pública', 'reason' => 'Só há evidência das comparações explicitamente guardadas no dossier; consultas públicas não são medidas.'],
+ ['id' => 'qualification', 'title' => 'Qualificação, reuniões, diligência e propostas', 'reason' => 'Os registos CRM exigem correspondência individual de estados, datas e âmbito antes de compor um funil. Estados de colecções diferentes não são somados.'],
+ ['id' => 'confirmed_investment', 'title' => 'Investimento confirmado', 'reason' => 'Interesse, proposta, pedido aceite ou guia guardado não comprovam investimento realizado. Falta uma fonte canónica do acto confirmado.'],
+ ['id' => 'journey_completion', 'title' => 'Investidores que concluem o roteiro', 'reason' => 'É necessário conservar aplicabilidade e estados por versão do percurso. Encerrar um dossier ou pedido não demonstra conclusão de todas as etapas aplicáveis.'],
+ ['id' => 'project_submission', 'title' => 'Tempo entre criação do projecto e submissão completa', 'reason' => 'A criação de um pedido do Balcão não equivale à criação do projecto. O indicador disponível mede apenas rascunho do pedido até à primeira submissão comprovada.'],
+ ['id' => 'stage_time', 'title' => 'Tempo por etapa', 'reason' => 'Faltam regras de início/fim, interrupções e reabertura por etapa para comparar períodos sem inventar uma duração.'],
+ ['id' => 'abandonment', 'title' => 'Abandono de formulários', 'reason' => 'Um rascunho sem submissão não prova abandono. Não existe observação de saída ou regra de abandono definida.'],
+ ['id' => 'satisfaction', 'title' => 'Satisfação e pedidos de suporte', 'reason' => 'Não existe uma amostra/resposta de satisfação ou ligação de suporte com denominador que sustente este indicador.'],
+ ['id' => 'aftercare', 'title' => 'Utilização após o investimento', 'reason' => 'É necessária ligação a investimento confirmado e eventos posteriores observáveis; não inferir a partir de leitura do dossier.'],
+ ['id' => 'experiments', 'title' => 'Experiências controladas e decisões', 'reason' => 'O registo manual versionado de planos, observações e decisões está disponível. A atribuição de grupos, execução das alterações e ligação automática dos eventos de cada variante ainda não estão implementadas; o relatório operacional não comprova o efeito de uma experiência.', 'href' => '/management/product-experiments'],
+ ],
+];
diff --git a/config/search-metrics.php b/config/search-metrics.php
new file mode 100644
index 00000000..a8efe59f
--- /dev/null
+++ b/config/search-metrics.php
@@ -0,0 +1,30 @@
+ env('PRODUCT_SEARCH_METRICS_ENABLED', true),
+ 'version' => 'public-search-responses-2026-11-03-v1',
+ // Technical collection budgets, not an operational SLA or a business deadline.
+ 'capture_lock_timeout_ms' => env('PRODUCT_SEARCH_LOCK_TIMEOUT_MS', 100),
+ 'capture_statement_timeout_ms' => env('PRODUCT_SEARCH_STATEMENT_TIMEOUT_MS', 300),
+ 'channels' => [
+ 'opportunities_page' => 'Oportunidades — página',
+ 'opportunities_api' => 'Oportunidades — API e respectivo alias',
+ 'education_page' => 'Oportunidades de educação — página',
+ 'businesses' => 'Negócios existentes',
+ 'documents' => 'Biblioteca documental pública',
+ 'partnerships' => 'Parcerias públicas',
+ 'portfolio' => 'Carteira de projectos, clusters e corredores',
+ 'zones' => 'Zonas de investimento',
+ 'sector_content' => 'Conteúdos sectoriais',
+ ],
+ 'presentation_keys' => ['page', 'per_page', 'view', 'sort'],
+ 'exclusions' => [
+ 'Consultas sem critério de pesquisa explícito não são pesquisas medidas.',
+ 'Paginação após a primeira página, HEAD, pré-carregamento e respostas sem sucesso não são contados.',
+ 'Sugestões automáticas, mapas, referências de filtros, exportações e consultas administrativas/privadas não fazem parte desta série.',
+ 'Outras pesquisas, incluindo fontes de financiamento e correspondências internas de educação, ainda não estão instrumentadas.',
+ 'Actualizações e repetições de uma primeira página contam como novas respostas; cache no navegador/CDN pode não passar pela aplicação.',
+ 'Sem identificação de visitantes, não se distinguem pessoas, bots ou pesquisas únicas.',
+ 'A recolha também é omitida quando o pedido envia DNT: 1 ou Sec-GPC: 1.',
+ ],
+];
diff --git a/database/migrations/2026_11_02_230000_education_declaration_drafts.php b/database/migrations/2026_11_02_230000_education_declaration_drafts.php
new file mode 100644
index 00000000..19fc22fb
--- /dev/null
+++ b/database/migrations/2026_11_02_230000_education_declaration_drafts.php
@@ -0,0 +1,38 @@
+uuid('id')->primary();
+ $table->foreignId('owner_user_id')->constrained('users')->restrictOnDelete();
+ $table->uuid('client_key');
+ $table->string('kind', 20);
+ $table->unsignedInteger('version_no')->default(1);
+ $table->text('payload');
+ $table->text('reference_snapshot')->nullable();
+ $table->string('state', 20)->default('draft');
+ $table->foreignUuid('demand_id')->nullable()->constrained('labour_demands')->restrictOnDelete();
+ $table->foreignUuid('capacity_id')->nullable()->constrained('training_capacities')->restrictOnDelete();
+ $table->timestampsTz();
+ $table->unique(['owner_user_id', 'client_key']);
+ $table->index(['owner_user_id', 'kind', 'updated_at']);
+ });
+ DB::statement("ALTER TABLE education_declaration_drafts ADD CONSTRAINT education_draft_state CHECK (version_no>0 AND kind IN ('demands','capacities') AND ((state='draft' AND demand_id IS NULL AND capacity_id IS NULL) OR (state='submitted' AND ((kind='demands' AND demand_id IS NOT NULL AND capacity_id IS NULL) OR (kind='capacities' AND capacity_id IS NOT NULL AND demand_id IS NULL)))))");
+ DB::statement("ALTER TABLE education_declaration_drafts ADD CONSTRAINT education_draft_snapshot CHECK ((state='draft' AND reference_snapshot IS NULL) OR (state='submitted' AND reference_snapshot IS NOT NULL))");
+ }
+
+ public function down(): void
+ {
+ if (DB::table('education_declaration_drafts')->exists()) {
+ throw new RuntimeException('Preserve education drafts and submission references before rollback.');
+ }
+ Schema::drop('education_declaration_drafts');
+ }
+};
diff --git a/database/migrations/2026_11_03_000000_existing_business_location_sources.php b/database/migrations/2026_11_03_000000_existing_business_location_sources.php
new file mode 100644
index 00000000..0da3009c
--- /dev/null
+++ b/database/migrations/2026_11_03_000000_existing_business_location_sources.php
@@ -0,0 +1,27 @@
+text('public_source_reference')->nullable();
+ $table->date('source_date')->nullable();
+ $table->string('source_system', 80)->nullable();
+ $table->unsignedInteger('source_payload_version')->nullable();
+ });
+ }
+
+ public function down(): void
+ {
+ if (DB::table('existing_business_locations')->whereNotNull('public_source_reference')->orWhereNotNull('source_date')->orWhereNotNull('source_system')->orWhereNotNull('source_payload_version')->exists()) {
+ throw new RuntimeException('Preserve business location sources before rollback.');
+ }
+ Schema::table('existing_business_locations', fn (Blueprint $table) => $table->dropColumn(['public_source_reference', 'source_date', 'source_system', 'source_payload_version']));
+ }
+};
diff --git a/database/migrations/2026_11_03_010000_desk_service_effective_dates.php b/database/migrations/2026_11_03_010000_desk_service_effective_dates.php
new file mode 100644
index 00000000..51d8c6cf
--- /dev/null
+++ b/database/migrations/2026_11_03_010000_desk_service_effective_dates.php
@@ -0,0 +1,24 @@
+ $table->date('effective_from')->nullable());
+ DB::statement('CREATE INDEX desk_service_effective_idx ON desk_service_versions (code,effective_from DESC,version DESC) WHERE status=\'published\'');
+ }
+
+ public function down(): void
+ {
+ if (DB::table('desk_service_versions')->whereNotNull('effective_from')->exists()) {
+ throw new RuntimeException('Preserve service effective dates before rollback.');
+ }
+ DB::statement('DROP INDEX desk_service_effective_idx');
+ Schema::table('desk_service_versions', fn (Blueprint $table) => $table->dropColumn('effective_from'));
+ }
+};
diff --git a/database/migrations/2026_11_03_020000_create_product_experiments.php b/database/migrations/2026_11_03_020000_create_product_experiments.php
new file mode 100644
index 00000000..40eaf7eb
--- /dev/null
+++ b/database/migrations/2026_11_03_020000_create_product_experiments.php
@@ -0,0 +1,71 @@
+uuid('id')->primary();
+ $t->unsignedInteger('version');
+ $t->string('state');
+ $t->foreignId('created_by')->constrained('users')->restrictOnDelete();
+ $t->foreignId('updated_by')->constrained('users')->restrictOnDelete();
+ $t->uuid('creation_key');
+ $t->timestampsTz();
+ $t->unique(['created_by', 'creation_key']);
+ $t->index(['state', 'updated_at']);
+ });
+ Schema::create('product_experiment_revisions', function (Blueprint $t) {
+ $t->uuid('id')->primary();
+ $t->foreignUuid('experiment_id')->constrained('product_experiments')->restrictOnDelete();
+ $t->unsignedInteger('version');
+ $t->foreignId('actor_id')->constrained('users')->restrictOnDelete();
+ $t->uuid('operation_key');
+ $t->char('request_hash', 64);
+ $t->char('snapshot_sha256', 64);
+ $t->text('snapshot');
+ $t->timestampTz('created_at');
+ $t->unique(['experiment_id', 'version']);
+ $t->unique(['experiment_id', 'actor_id', 'operation_key'], 'product_experiment_operation_unique');
+ });
+ DB::statement("ALTER TABLE product_experiments ADD CONSTRAINT product_experiment_state CHECK(state IN ('draft','planned','observing','reviewed','cancelled'))");
+ DB::statement('ALTER TABLE product_experiments ADD CONSTRAINT product_experiment_version CHECK(version>0)');
+ DB::statement('ALTER TABLE product_experiment_revisions ADD CONSTRAINT product_experiment_revision_version CHECK(version>0)');
+ DB::statement('ALTER TABLE product_experiments ADD CONSTRAINT product_experiment_current_revision FOREIGN KEY(id,version) REFERENCES product_experiment_revisions(experiment_id,version) DEFERRABLE INITIALLY DEFERRED');
+ DB::unprepared(<<<'SQL'
+CREATE OR REPLACE FUNCTION public.product_experiment_reject_history_change() RETURNS trigger LANGUAGE plpgsql AS $$
+BEGIN
+ RAISE EXCEPTION 'Product experiment history must be preserved; record a new revision' USING ERRCODE='23514';
+END;
+$$;
+CREATE TRIGGER product_experiment_revisions_immutable BEFORE UPDATE OR DELETE OR TRUNCATE ON product_experiment_revisions FOR EACH STATEMENT EXECUTE FUNCTION public.product_experiment_reject_history_change();
+CREATE TRIGGER product_experiments_preserve BEFORE DELETE OR TRUNCATE ON product_experiments FOR EACH STATEMENT EXECUTE FUNCTION public.product_experiment_reject_history_change();
+CREATE OR REPLACE FUNCTION public.product_experiment_require_revision_advance() RETURNS trigger LANGUAGE plpgsql AS $$
+BEGIN
+ IF NEW.id IS DISTINCT FROM OLD.id OR NEW.created_by IS DISTINCT FROM OLD.created_by OR NEW.creation_key IS DISTINCT FROM OLD.creation_key OR NEW.created_at IS DISTINCT FROM OLD.created_at OR NEW.version <> OLD.version+1 THEN
+ RAISE EXCEPTION 'Product experiment updates must advance one revision and preserve origin' USING ERRCODE='23514';
+ END IF;
+ RETURN NEW;
+END;
+$$;
+CREATE TRIGGER product_experiments_revision_advance BEFORE UPDATE ON product_experiments FOR EACH ROW EXECUTE FUNCTION public.product_experiment_require_revision_advance();
+SQL);
+ }
+
+ public function down(): void
+ {
+ if (DB::table('product_experiments')->exists()) {
+ throw new RuntimeException('Preserve experiment records and audit history; reconcile a restore before rollback.');
+ }
+ DB::statement('ALTER TABLE product_experiments DROP CONSTRAINT product_experiment_current_revision');
+ Schema::dropIfExists('product_experiment_revisions');
+ Schema::dropIfExists('product_experiments');
+ DB::statement('DROP FUNCTION public.product_experiment_reject_history_change()');
+ DB::statement('DROP FUNCTION public.product_experiment_require_revision_advance()');
+ }
+};
diff --git a/database/migrations/2026_11_03_030000_create_product_search_counts.php b/database/migrations/2026_11_03_030000_create_product_search_counts.php
new file mode 100644
index 00000000..0fb7f8e6
--- /dev/null
+++ b/database/migrations/2026_11_03_030000_create_product_search_counts.php
@@ -0,0 +1,50 @@
+string('version', 100)->primary();
+ $t->char('sha256', 64);
+ $t->jsonb('definition');
+ $t->timestampTz('created_at', 6);
+ });
+ Schema::create('product_search_counts', function (Blueprint $t) {
+ $t->date('day');
+ $t->string('channel', 50);
+ $t->string('definition_version', 100);
+ $t->unsignedBigInteger('responses');
+ $t->unsignedBigInteger('zero_responses');
+ $t->timestampTz('first_recorded_at', 6);
+ $t->timestampTz('last_recorded_at', 6);
+ $t->primary(['day', 'channel', 'definition_version']);
+ $t->foreign('definition_version')->references('version')->on('product_search_definitions')->restrictOnDelete();
+ });
+ DB::statement('ALTER TABLE product_search_counts ADD CONSTRAINT product_search_counts_valid CHECK(responses>0 AND zero_responses>=0 AND zero_responses<=responses AND first_recorded_at<=last_recorded_at)');
+ DB::statement("ALTER TABLE product_search_counts ADD CONSTRAINT product_search_day_valid CHECK(day=(first_recorded_at AT TIME ZONE 'UTC')::date AND day=(last_recorded_at AT TIME ZONE 'UTC')::date)");
+ DB::unprepared(<<<'SQL'
+CREATE OR REPLACE FUNCTION public.product_search_preserve_definition() RETURNS trigger LANGUAGE plpgsql AS $$
+BEGIN
+ RAISE EXCEPTION 'Search measurement definitions are immutable; register another edition' USING ERRCODE='23514';
+END;
+$$;
+CREATE TRIGGER product_search_definitions_immutable BEFORE UPDATE OR DELETE OR TRUNCATE ON product_search_definitions FOR EACH STATEMENT EXECUTE FUNCTION public.product_search_preserve_definition();
+SQL);
+ }
+
+ public function down(): void
+ {
+ if (DB::table('product_search_counts')->exists() || DB::table('product_search_definitions')->exists()) {
+ throw new RuntimeException('Preserve collected search aggregates; reconcile a restore before rollback.');
+ }
+ Schema::dropIfExists('product_search_counts');
+ Schema::dropIfExists('product_search_definitions');
+ DB::statement('DROP FUNCTION public.product_search_preserve_definition()');
+ }
+};
diff --git a/database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php b/database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php
new file mode 100644
index 00000000..a067ac34
--- /dev/null
+++ b/database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php
@@ -0,0 +1,33 @@
+foreignUuid('request_id')->constrained('desk_requests')->restrictOnDelete();
+ $table->foreignId('actor_id')->constrained('users')->restrictOnDelete();
+ $table->unsignedInteger('version');
+ $table->unsignedInteger('request_version');
+ $table->uuid('operation_key');
+ $table->char('operation_sha256', 64);
+ $table->text('snapshot');
+ $table->timestampsTz();
+ $table->primary(['request_id', 'actor_id']);
+ });
+ DB::statement('ALTER TABLE desk_request_checkpoints ADD CONSTRAINT desk_checkpoint_versions_positive CHECK(version > 0 AND request_version > 0)');
+ }
+
+ public function down(): void
+ {
+ if (DB::table('desk_request_checkpoints')->exists()) {
+ throw new RuntimeException('Preserve recoverable private drafts before rolling back this migration.');
+ }
+ Schema::dropIfExists('desk_request_checkpoints');
+ }
+};
diff --git a/database/migrations/2026_11_03_050000_scope_desk_document_links.php b/database/migrations/2026_11_03_050000_scope_desk_document_links.php
new file mode 100644
index 00000000..817b88e0
--- /dev/null
+++ b/database/migrations/2026_11_03_050000_scope_desk_document_links.php
@@ -0,0 +1,26 @@
+ $table->dropUnique(['case_id', 'document_id']));
+ }
+
+ public function down(): void
+ {
+ if (DB::table('desk_documents')->select(['case_id', 'document_id'])->groupBy('case_id', 'document_id')->havingRaw('count(*) > 1')->exists()) {
+ throw new RuntimeException('Preserve scoped document uses before restoring the old uniqueness rule.');
+ }
+ Schema::table('desk_documents', fn (Blueprint $table) => $table->unique(['case_id', 'document_id']));
+ DB::statement('DROP INDEX desk_documents_scope_unique');
+ DB::statement('DROP INDEX desk_documents_dossier_unique');
+ }
+};
diff --git a/database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php b/database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php
new file mode 100644
index 00000000..428849d1
--- /dev/null
+++ b/database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php
@@ -0,0 +1,17 @@
+'task_creation'->>'lead_id'), (after_data->'task_creation'->>'key')) WHERE source_system='portal-crm-task-creation' AND entity_type='tasks' AND action='created'");
+ }
+
+ public function down(): void
+ {
+ DB::statement('DROP INDEX crm_task_creation_commands_unique');
+ }
+};
diff --git a/database/migrations/2026_11_03_070000_create_crm_task_preparations.php b/database/migrations/2026_11_03_070000_create_crm_task_preparations.php
new file mode 100644
index 00000000..2186f3cb
--- /dev/null
+++ b/database/migrations/2026_11_03_070000_create_crm_task_preparations.php
@@ -0,0 +1,32 @@
+foreignUuid('lead_id')->constrained('leads')->restrictOnDelete();
+ $table->foreignId('actor_id')->constrained('users')->restrictOnDelete();
+ $table->unsignedInteger('version');
+ $table->uuid('operation_key');
+ $table->char('operation_sha256', 64);
+ $table->text('snapshot');
+ $table->timestampsTz();
+ $table->primary(['lead_id', 'actor_id']);
+ });
+ DB::statement('ALTER TABLE crm_task_preparations ADD CONSTRAINT crm_task_preparation_version_positive CHECK(version > 0)');
+ }
+
+ public function down(): void
+ {
+ if (DB::table('crm_task_preparations')->exists()) {
+ throw new RuntimeException('Preserve private task preparations before rolling back this migration.');
+ }
+ Schema::dropIfExists('crm_task_preparations');
+ }
+};
diff --git a/database/migrations/2026_11_03_080000_add_technical_support_profile.php b/database/migrations/2026_11_03_080000_add_technical_support_profile.php
new file mode 100644
index 00000000..aa6978b4
--- /dev/null
+++ b/database/migrations/2026_11_03_080000_add_technical_support_profile.php
@@ -0,0 +1,26 @@
+environment('testing')) {
+ throw_unless(IsolatedQaDatabase::allowsSchemaChanges(), LogicException::class, 'Isolated profile QA required.');
+ } else {
+ throw_unless(config('portal_profiles.authenticated_installation') === true, LogicException::class, 'Authenticated profile installation required.');
+ }
+ DB::statement("ALTER TABLE portal_role_assignments DROP CONSTRAINT portal_role_name, ADD CONSTRAINT portal_role_name CHECK (role IN ('promoter','validator','publisher','auditor','technical_support'))");
+ }
+
+ public function down(): void
+ {
+ if (DB::table('portal_role_assignments')->where('role', 'technical_support')->exists()) {
+ throw new LogicException('Preserve existing and historical support assignments before downgrade.');
+ }
+ DB::statement("ALTER TABLE portal_role_assignments DROP CONSTRAINT portal_role_name, ADD CONSTRAINT portal_role_name CHECK (role IN ('promoter','validator','publisher','auditor'))");
+ }
+};
diff --git a/docs/investmoz/unification/local-validation-20261029.json b/docs/investmoz/unification/local-validation-20261029.json
index d46a55b9..bde7ab93 100644
--- a/docs/investmoz/unification/local-validation-20261029.json
+++ b/docs/investmoz/unification/local-validation-20261029.json
@@ -2280,5 +2280,51262 @@
"two processes per scenario; not a load test or every interleaving",
"visual, reference registry associations, incentive alerts and destination deployment pending"
]
+ },
+ "funding_alerts_increment_20261102": {
+ "recorded_at": "2026-11-02T18:33:52.260Z",
+ "status": "partial_local_qa_not_installed",
+ "requirements": [
+ "ACT-20261029-11",
+ "AUD-FUND-01",
+ "MASTER-471012ab-0124"
+ ],
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 36,
+ "passed": 36,
+ "assertions": 612,
+ "duration_ms": 154667
+ },
+ "frontend": {
+ "tests": 6,
+ "passed": 6
+ },
+ "static_checks": {
+ "phpstan": "passed",
+ "types": "passed",
+ "lint_format": "passed_without_warnings",
+ "build": "passed_with_existing_advisories",
+ "diff": "passed"
+ },
+ "logs": {
+ "funding-alerts-verified-feature-20261102.log": "030e26eb45b3cad997b2efe576d8592d2b43af9b46c0acf08314a45b5d001e1f",
+ "funding-alerts-verified-frontend-20261102.log": "a100f5bfcec262b8861f3f9f515f9e8199caaecfa5674101586d877963d22795",
+ "funding-alerts-verified-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "funding-alerts-final-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "funding-alerts-final-check-20261102.log": "ec2614673c783349c6213fe79802cfa1bad2cdb8ef0ba9258586277c7751c4b2",
+ "funding-alerts-build-20261102.log": "4eb2d28efad1d1f36360b876e82d0d061e22ff27b05e37e5819453ba90d3c0e6"
+ },
+ "source_sha256": {
+ "database/migrations/2026_11_02_220000_investment_funding_alerts.php": "c754b81c45031b7921ee079ff9057d24c53307a6fc619c8ebff8426c4f60e3c6",
+ "app/Services/InvestmentOpportunityAlerts.php": "9669b494961c11189688e42d4a3baa4ccf225489c93073234a08047d628e669c",
+ "app/Services/InvestmentWorkspace.php": "14437df3de66344d4d6276132e3b8ddd43c82b4f0582e8fbeec3a65aeefe2a21",
+ "app/Services/FundingProgrammes.php": "6f2f0db08ebf4443243ea282e7e556a92f86cc64dba10012dfcdb76cea87c510",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "4714ddea4b6f0408599f8748f2f2668f604f18ee2a61852322932a0e2f306c30",
+ "resources/js/components/opportunity-alert-preferences.tsx": "c76a36fa7e2c51081558273a828c70c93d5cd491dc8017f564b7af6a6671d550",
+ "resources/js/pages/investment/notifications.tsx": "a3f279183ea4ec4e394b5577f996f12a21c2937118072f441af30c6801fb5ae4",
+ "tests/Feature/InvestmentFundingAlertsTest.php": "5fe7e20b6f59cf09ccf380d9b723f79a87cc2859bee0fe7e34079b79775259fe",
+ "tests/Feature/InvestmentOpportunityAlertsTest.php": "084a471709fcdac83c0b2f7a945642ace09c247b494f0476b755ca2ec1685b2e",
+ "tests/frontend/opportunity-alert-preferences.test.mjs": "5ce6f27f2c681497b944e7f19e64283ae8835e3af4c9818dcaa1767d47954600"
+ },
+ "coverage": [
+ "explicit third source with preserved previous preferences",
+ "no retroactive alerts at opt-in or criteria changes",
+ "published current funding versions only",
+ "documented/unknown scope and window state filtering",
+ "immutable public notification projection and source",
+ "withdrawal/ownership checks preserve history",
+ "unavailable funding does not suspend other sources or cancellation",
+ "bounded source batches and rollback of mixed deliveries",
+ "legacy migrations and manifestation notification compatibility"
+ ],
+ "limitations": [
+ "only the portal funding catalogue; no external scraping or channels",
+ "date-only changes without new published version do not trigger notices",
+ "not every intermediate version between runs",
+ "generator concurrency, visual and destination scheduler/deployment pending"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "funding_assessment_concurrency_increment_20261102": {
+ "recorded_at": "2026-11-02T18:40:47.591Z",
+ "status": "partial_local_qa_not_installed",
+ "requirements": [
+ "AUD-FUND-01",
+ "ACT-20261029-11"
+ ],
+ "concurrency": {
+ "result": "passed",
+ "database": "funding_concurrency_20261102d_test",
+ "synthetic": true,
+ "phases": {
+ "reference": {
+ "overlap_observed": [
+ {
+ "pid": 16220,
+ "wait_event": "advisory",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 23244,
+ "wait_event": "advisory",
+ "blockers": "{22376,16220}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "id": "94213969-399e-4506-800f-6c239d2d37f5",
+ "created": true
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "id": "94213969-399e-4506-800f-6c239d2d37f5",
+ "created": false
+ }
+ }
+ ]
+ },
+ "draft": {
+ "overlap_observed": [
+ {
+ "pid": 16368,
+ "wait_event": "advisory",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 26368,
+ "wait_event": "advisory",
+ "blockers": "{22376,16368}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "id": "94213969-399e-4506-800f-6c239d2d37f5"
+ }
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "publication": {
+ "overlap_observed": [
+ {
+ "pid": 25260,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 25372,
+ "wait_event": "tuple",
+ "blockers": "{25260}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "version_id": "de829d29-20d5-43ff-a917-367a99ff4445"
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "version_id": "de829d29-20d5-43ff-a917-367a99ff4445"
+ }
+ }
+ ]
+ },
+ "interest": {
+ "overlap_observed": [
+ {
+ "pid": 18224,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 20180,
+ "wait_event": "tuple",
+ "blockers": "{18224}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "saved": true
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "saved": true
+ }
+ }
+ ]
+ },
+ "duplicate_generators": {
+ "overlap_observed": [
+ {
+ "pid": 26168,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 7148,
+ "wait_event": "tuple",
+ "blockers": "{26168}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "delivered": 1
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "delivered": 0
+ }
+ }
+ ]
+ },
+ "duplicate_preferences": {
+ "overlap_observed": [
+ {
+ "pid": 4460,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 11168,
+ "wait_event": "transactionid",
+ "blockers": "{4460}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "version": 2,
+ "enabled": true,
+ "frequency": "daily",
+ "channel": "in_app",
+ "next_run_at": "2026-11-03 18:35:53+00",
+ "criteria": [],
+ "sources": [
+ "funding"
+ ],
+ "source_statuses": {
+ "funding": true
+ },
+ "criteria_available": true
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "version": 2,
+ "enabled": true,
+ "frequency": "daily",
+ "channel": "in_app",
+ "next_run_at": "2026-11-03 18:35:53+00",
+ "criteria": [],
+ "sources": [
+ "funding"
+ ],
+ "source_statuses": {
+ "funding": true
+ },
+ "criteria_available": true
+ }
+ }
+ ]
+ },
+ "cancel_before_generator": {
+ "overlap_observed": [
+ {
+ "pid": 25716,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 25996,
+ "wait_event": "tuple",
+ "blockers": "{25716}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "version": 3,
+ "enabled": false,
+ "frequency": "daily",
+ "channel": "in_app",
+ "next_run_at": null,
+ "criteria": [],
+ "sources": [
+ "funding"
+ ],
+ "source_statuses": {
+ "funding": true
+ },
+ "criteria_available": true
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "delivered": 0
+ }
+ }
+ ]
+ },
+ "generator_before_cancel": {
+ "overlap_observed": [
+ {
+ "pid": 20736,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 27020,
+ "wait_event": "tuple",
+ "blockers": "{20736}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "delivered": 1
+ }
+ },
+ {
+ "status": "ok",
+ "result": {
+ "version": 5,
+ "enabled": false,
+ "frequency": "as_available",
+ "channel": "in_app",
+ "next_run_at": null,
+ "criteria": [],
+ "sources": [
+ "funding"
+ ],
+ "source_statuses": {
+ "funding": true
+ },
+ "criteria_available": true
+ }
+ }
+ ]
+ },
+ "withdrawal_vs_interest": {
+ "overlap_observed": [
+ {
+ "pid": 26648,
+ "wait_event": "transactionid",
+ "blockers": "{22376}"
+ },
+ {
+ "pid": 5944,
+ "wait_event": "tuple",
+ "blockers": "{26648}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "result": {
+ "withdrawn": true
+ }
+ },
+ {
+ "status": "unavailable",
+ "code": 404
+ }
+ ]
+ }
+ },
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "preservation": {
+ "programmes": 1,
+ "versions": 4,
+ "interests": 1,
+ "preserved_interest": 1,
+ "notifications": 2,
+ "funding_seen": 4,
+ "funding_delivered": 2,
+ "preferences": {
+ "version": 5,
+ "enabled": false
+ },
+ "audit": {
+ "published": 4,
+ "withdrawn": 1,
+ "reference_prepared": 1,
+ "preferences_saved": 3,
+ "preferences_cancelled": 2,
+ "interest_saved": 1,
+ "draft_saved": 5
+ }
+ },
+ "frontend": {
+ "tests": 8,
+ "passed": 8
+ },
+ "checks": {
+ "types": "passed",
+ "lint_format": "passed_without_warnings",
+ "build": "passed_with_existing_advisories",
+ "pint": "passed",
+ "diff": "passed"
+ },
+ "backend_proof": {
+ "reused": "funding_alerts_increment_20261102",
+ "tests": 36,
+ "assertions": 612,
+ "source_hashes_reconciled": true
+ },
+ "logs": {
+ "funding-alert-concurrency-20261102.log": "7179c799a3da9130fc260b94daa6c52bd6d3d82101ca223d8859f913a3d3e1e0",
+ "funding-alert-concurrency-preservation-20261102.json": "155722d6fa4a52c52dd2a519a8f4eef9c91ae97afc69c6a081c445c076f839e6",
+ "funding-assessment-frontend-20261102.log": "a54b0f590bdf05008b337ca0d24d7d096a9bd813dcb369decb220ebb47af1667",
+ "funding-assessment-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "funding-assessment-check-20261102.log": "ab972e9edbf7ff43cfc4c3e2141f9fed7101b25f4d75a3f9176abfd4347b8bb7",
+ "funding-assessment-build-20261102.log": "7ded9d4428fbf8fa901f558734c8696d5a097f51376251e1bbd89d43b4201c06"
+ },
+ "source_sha256": {
+ "tools/verify-funding-concurrency.php": "fc111dbdc80dcbd1e440fd5d8269c70ab8639fa40c4a7f19a12c0d86c68fec2f",
+ "resources/js/components/funding-criteria-assessment.tsx": "34a1cabfb18eeadfab02e57dcfbd7976cf1fea0220af92d56ad209032cfe43b7",
+ "resources/js/pages/funding/show.tsx": "5fc036b7b1557810369b26be5c65a6292ff13a6a6a14f7cd10ec20f4143b8e97",
+ "tests/frontend/funding-criteria-assessment.test.mjs": "88efd27b017e9792a77c164064c78a5451441c31b68e190bbe2b0392ef8299de"
+ },
+ "limitations": [
+ "two processes per scenario, not load or all interleavings",
+ "frontend tests are technical, not visual verification",
+ "reference registry bindings, external channels and destination deployment/scheduler pending"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "education_drafts_increment_20261102": {
+ "recorded_at": "2026-11-02T18:50:55.582Z",
+ "status": "backend_partial_local_qa_not_installed",
+ "requirement": "AUD-EDU-01",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 14,
+ "passed": 14,
+ "assertions": 291,
+ "duration_ms": 67600
+ },
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "syntax": "passed",
+ "diff": "passed",
+ "frontend": "not_changed_or_claimed"
+ },
+ "logs": {
+ "storage/logs/education-drafts-verified-feature-20261102.log": "4687be58a1d641bf68f64a384a84019370a7a3fd65fcee56e0a198e838950555",
+ "storage/logs/education-drafts-verified-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2"
+ },
+ "source_sha256": {
+ "app/Services/EducationDeclarationRules.php": "3342de5086b5e49a75682ec1eea5827afcde9f94ad30b8cb25d04ded94488210",
+ "app/Services/EducationDeclarationDrafts.php": "f6591449bc2213a1276ec1d595881f7f26ea60929fd63de16ff1d9eaf15627f7",
+ "app/Http/Controllers/EducationDeclarationDraftController.php": "0884d2b0eaeea60da4547c729c73373851256d6d0e1bf1ab5a3dc6582642c376",
+ "app/Http/Controllers/EducationController.php": "58e93a5b9f7876926e2edbb7230a551cc65e4019527c6f7ea4beb1b878b80731",
+ "database/migrations/2026_11_02_230000_education_declaration_drafts.php": "58e5bbe5ad1f613eac731e46977e9c8f35827b74854e6dbd30b13954529692df",
+ "routes/web.php": "20218ac56b5e25df680b92f8079a69c987ebe163a461ba4bb065f80aa6a2c0de",
+ "tests/Feature/EducationDeclarationDraftsTest.php": "8cc9d7870e073c252167fbb3aea7cc6c6cb6e3e4f4f4670bdbde1dfbbcb29348"
+ },
+ "coverage": [
+ "own private incomplete drafts",
+ "encrypted payload and metadata-only audit",
+ "same key and payload do not duplicate",
+ "stale edits and wrong type refused",
+ "applicable field whitelist",
+ "shared existing submission rules",
+ "single submitted declaration and independent review preserved",
+ "immutable submitted reference snapshot",
+ "rollback refuses nonempty drafts"
+ ],
+ "limitations": [
+ "interface not yet connected",
+ "remaining actor dashboards and profiles not implemented by this increment",
+ "concurrency and visual pending",
+ "not migrated in active environment"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "education_drafts_ui_increment_20261102": {
+ "recorded_at": "2026-11-02T19:09:13.560Z",
+ "requirement": "AUD-EDU-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 14,
+ "passed": 14,
+ "assertions": 333,
+ "duration_ms": 69347
+ },
+ "frontend": {
+ "tests": 5,
+ "passed": 5
+ },
+ "checks": {
+ "phpstan": "passed",
+ "types": "passed",
+ "lint_format": "passed_without_warnings",
+ "pint": "passed",
+ "build": "passed_with_existing_advisories",
+ "diff": "passed"
+ },
+ "logs": {
+ "education-drafts-ui-verified-feature-20261102.log": "6f85fc74b9083c5cfe8a853049457d6dabaa90ccfbd5a08fa507ddda88e71f50",
+ "education-drafts-ui-verified-frontend-20261102.log": "5dd4f53ec36d1152f987681e707dfa545a7e42cee1f9b143192eb367b49c6137",
+ "education-drafts-ui-verified-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "education-drafts-ui-verified-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "education-drafts-ui-check-20261102.log": "2574a349779926e6ff42251050276b7f879816a8ffd572fc7bcf1538ac424167",
+ "education-drafts-ui-build-20261102.log": "6a1e63473898dbfd348cbf95e58b6c471254dd72783cd7688982223c89325d30"
+ },
+ "source_sha256": {
+ "app/Http/Controllers/EducationController.php": "edd7771c7225f39911afc44abb5b20d3f64a363dcb12a1cc4b4c3eb17a350f30",
+ "app/Services/EducationDeclarationDrafts.php": "1e882088009ef6d96c27c69252defaf2fe80a1c0f884eb1ed21e09f1ada425c4",
+ "resources/js/pages/education/index.tsx": "21bf4d9e4a105a1aba2516eb144e143c9986198009b60afa36f3f25ed81a248f",
+ "resources/js/components/education-submitted-snapshot.tsx": "8f64fbf6c39a0166405340f68ff8acc0dd38d5eea4f994ae825faa15b8939a4a",
+ "tests/Feature/EducationDeclarationDraftsTest.php": "495fc00a3ce9ea0dffb761d6e3eb2795b6b3b5678a698ff941db2a76f01c7678",
+ "tests/frontend/education-drafts.test.mjs": "718b422c785b962d55dbcf2db9ac549010d69db83aee036c2540f01cc7dd9656"
+ },
+ "coverage": [
+ "private owner-scoped page recovery and list projection",
+ "incomplete save independent of native submission validation",
+ "same draft identity and current values on submission",
+ "blank dates, territorial path and reference IDs preserved",
+ "conflict retains current edits",
+ "submitted view reads immutable reference snapshot",
+ "no-store and encrypted Inertia history",
+ "full page render and legacy education compatibility"
+ ],
+ "limitations": [
+ "technical frontend and HTTP tests are not visual or real login acceptance",
+ "concurrent draft/submission workers pending",
+ "remaining actor profiles/dashboards and destination deployment pending"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "education_drafts_concurrency_increment_20261102": {
+ "recorded_at": "2026-11-02T19:15:13.098Z",
+ "requirement": "AUD-EDU-01",
+ "status": "partial_local_qa_not_installed",
+ "concurrency": {
+ "result": "passed",
+ "database": "education_draft_concurrency_20261102_test",
+ "synthetic": true,
+ "phases": {
+ "demands_duplicate_creation": {
+ "overlap_observed": [
+ {
+ "pid": 23564,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 26200,
+ "wait_event": "tuple",
+ "blockers": "{23564}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "5378c5eb-9acb-47db-b70e-a34be62e884c",
+ "version_no": 1,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "0706fe26e81197a5f887b9793898f796c4e2b7c64053c6e06e28422bfc88ce19"
+ },
+ {
+ "status": "ok",
+ "id": "5378c5eb-9acb-47db-b70e-a34be62e884c",
+ "version_no": 1,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "0706fe26e81197a5f887b9793898f796c4e2b7c64053c6e06e28422bfc88ce19"
+ }
+ ]
+ },
+ "demands_conflicting_edits": {
+ "overlap_observed": [
+ {
+ "pid": 16648,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 19128,
+ "wait_event": "tuple",
+ "blockers": "{16648}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "5378c5eb-9acb-47db-b70e-a34be62e884c",
+ "version_no": 2,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "0e0c8f2645e424bc14354bb71a7a47a9f16b5f5f1e14bb90b39a75e44ec4edb8"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "demands_duplicate_submission": {
+ "overlap_observed": [
+ {
+ "pid": 16624,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 14108,
+ "wait_event": "tuple",
+ "blockers": "{16624}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "5378c5eb-9acb-47db-b70e-a34be62e884c",
+ "version_no": 3,
+ "state": "submitted",
+ "record_id": "a5e0c929-2ce2-4dc6-9a2b-223839dfb049",
+ "payload_sha256": "0e0c8f2645e424bc14354bb71a7a47a9f16b5f5f1e14bb90b39a75e44ec4edb8"
+ },
+ {
+ "status": "ok",
+ "id": "5378c5eb-9acb-47db-b70e-a34be62e884c",
+ "version_no": 3,
+ "state": "submitted",
+ "record_id": "a5e0c929-2ce2-4dc6-9a2b-223839dfb049",
+ "payload_sha256": "0e0c8f2645e424bc14354bb71a7a47a9f16b5f5f1e14bb90b39a75e44ec4edb8"
+ }
+ ]
+ },
+ "demands_save_before_submit": {
+ "overlap_observed": [
+ {
+ "pid": 23252,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 6200,
+ "wait_event": "tuple",
+ "blockers": "{23252}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "9e83d0dc-fb10-4496-b248-edc343755dc2",
+ "version_no": 2,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "e78e43450e5f333df3bd8dee5827241a714929fb6a674de68a0edf0bd8073807"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "demands_submit_before_save": {
+ "overlap_observed": [
+ {
+ "pid": 25076,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 24820,
+ "wait_event": "tuple",
+ "blockers": "{25076}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "9a92c9c7-f8b2-4cb2-bab7-aface733b398",
+ "version_no": 2,
+ "state": "submitted",
+ "record_id": "75a84d92-d396-46e8-8e85-5bebd686fcb3",
+ "payload_sha256": "0e0c8f2645e424bc14354bb71a7a47a9f16b5f5f1e14bb90b39a75e44ec4edb8"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "capacities_duplicate_creation": {
+ "overlap_observed": [
+ {
+ "pid": 19696,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 23212,
+ "wait_event": "tuple",
+ "blockers": "{19696}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "045bbd4d-4e8d-40cf-81cc-d02244947311",
+ "version_no": 1,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "a284b20e991bf5e7d7820fdad0270deb0852413856d80f76f2821284638408d9"
+ },
+ {
+ "status": "ok",
+ "id": "045bbd4d-4e8d-40cf-81cc-d02244947311",
+ "version_no": 1,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "a284b20e991bf5e7d7820fdad0270deb0852413856d80f76f2821284638408d9"
+ }
+ ]
+ },
+ "capacities_conflicting_edits": {
+ "overlap_observed": [
+ {
+ "pid": 20236,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 26076,
+ "wait_event": "tuple",
+ "blockers": "{20236}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "045bbd4d-4e8d-40cf-81cc-d02244947311",
+ "version_no": 2,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "1b7e0a3c87dd98ebfb68cacdacaadb0bf6d33592070304a3db26c923b5fb8467"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "capacities_duplicate_submission": {
+ "overlap_observed": [
+ {
+ "pid": 8584,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 26836,
+ "wait_event": "tuple",
+ "blockers": "{8584}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "045bbd4d-4e8d-40cf-81cc-d02244947311",
+ "version_no": 3,
+ "state": "submitted",
+ "record_id": "93342b55-248b-4ccb-9273-c17b643cffe8",
+ "payload_sha256": "1b7e0a3c87dd98ebfb68cacdacaadb0bf6d33592070304a3db26c923b5fb8467"
+ },
+ {
+ "status": "ok",
+ "id": "045bbd4d-4e8d-40cf-81cc-d02244947311",
+ "version_no": 3,
+ "state": "submitted",
+ "record_id": "93342b55-248b-4ccb-9273-c17b643cffe8",
+ "payload_sha256": "1b7e0a3c87dd98ebfb68cacdacaadb0bf6d33592070304a3db26c923b5fb8467"
+ }
+ ]
+ },
+ "capacities_save_before_submit": {
+ "overlap_observed": [
+ {
+ "pid": 8620,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 5912,
+ "wait_event": "tuple",
+ "blockers": "{8620}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "5d692cf0-2808-4b72-aea5-dcb11e7b81e3",
+ "version_no": 2,
+ "state": "draft",
+ "record_id": null,
+ "payload_sha256": "5212ef41157b5c5a16d158a587730fda0ebfe66ae56fdbf8354ea0f45b01216d"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ },
+ "capacities_submit_before_save": {
+ "overlap_observed": [
+ {
+ "pid": 23884,
+ "wait_event": "transactionid",
+ "blockers": "{23108}"
+ },
+ {
+ "pid": 14520,
+ "wait_event": "tuple",
+ "blockers": "{23884}"
+ }
+ ],
+ "results": [
+ {
+ "status": "ok",
+ "id": "e4b409ab-fd13-4f58-bf81-2645255cb8fe",
+ "version_no": 2,
+ "state": "submitted",
+ "record_id": "5a195a1d-fce5-4860-ab30-f0b59983278c",
+ "payload_sha256": "1b7e0a3c87dd98ebfb68cacdacaadb0bf6d33592070304a3db26c923b5fb8467"
+ },
+ {
+ "status": "conflict",
+ "code": 409
+ }
+ ]
+ }
+ },
+ "counts": {
+ "drafts": 6,
+ "labour_demands": 2,
+ "training_capacities": 2,
+ "submission_audits": 4
+ },
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "preservation": {
+ "drafts": 6,
+ "draft_states": {
+ "submitted": 4,
+ "draft": 2
+ },
+ "labour_demands": 2,
+ "training_capacities": 2,
+ "independent_review_not_bypassed": 4,
+ "snapshots": 4,
+ "valid_owned_links": 4,
+ "audit": {
+ "draft_saved": 10,
+ "draft_submitted": 4
+ }
+ },
+ "reused": {
+ "receipt": "education_drafts_ui_increment_20261102",
+ "feature_tests": 14,
+ "assertions": 333,
+ "frontend": 5,
+ "source_hashes_reconciled": true
+ },
+ "checks": {
+ "pint": "passed",
+ "syntax": "passed",
+ "diff": "passed",
+ "guards": "wrong environment and nonempty target refused without resets"
+ },
+ "logs": {
+ "education-draft-concurrency-20261102.log": "5e7afc6d9232825dfcf63d32bc52d95fc485e50fe14f67e37cc53c009b35ef11",
+ "education-draft-concurrency-preservation-20261102.json": "0dbb46c055469303b13f8de574f40926d1180f7ece1c5ce9e3a5be234f772c64",
+ "education-draft-concurrency-guard-environment-20261102.log": "73ba65ecd056c1a2261d4e659ed38160650fd117135c2e9e4983c10f3d982de5",
+ "education-draft-concurrency-guard-existing-20261102.log": "bcfdd95824c0cafc853a8f7be1883451d8882ed393c97f314241c6f8c106ed5e"
+ },
+ "source_sha256": {
+ "tools/verify-education-draft-concurrency.php": "4e34e211f048ef3d9d9fd7668b3a1c84adb46bcd12358eb5d8bf7a8d22d86050"
+ },
+ "limitations": [
+ "two processes per scenario, not load or all interleavings",
+ "no visual or real user acceptance",
+ "remaining profiles/dashboards and destination deployment pending"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "business_proximity_increment_20261102": {
+ "recorded_at": "2026-11-02T19:29:22.100Z",
+ "requirement": "AUD-MARKET-01",
+ "status": "partial_local_qa_not_installed",
+ "feature_tests": 11,
+ "assertions": 384,
+ "frontend_tests": 10,
+ "checks": {
+ "phpstan": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "pint": "passed",
+ "build": "passed"
+ },
+ "user_search_example": {
+ "value": "plantio de algodao",
+ "existing_feature_tests": 3,
+ "revalidated": true,
+ "cultivation_and_processing_distinct": true
+ },
+ "data_policy": {
+ "public_primary_exact_points_only": true,
+ "polygons_and_private_points_excluded": true,
+ "point_coordinates_projected": false,
+ "source_dates_not_inferred": true,
+ "administrative_precision_respected": true
+ },
+ "database": "isolated synthetic investmoz_test on loopback PostgreSQL 55441; existing test guards unchanged",
+ "logs": {
+ "business-proximity-final-feature-20261102.log": "02b61076abcf9329df2097f288e2182bdcd14c5f8045144f0c675bd3d8b1800b",
+ "business-proximity-final-frontend-20261102.log": "ed5d2cfbc13ded9eb0c7acec5184414c9f98931f5df35f2a462aa5d963fe51d6",
+ "business-proximity-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "business-proximity-final-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "business-proximity-final-check-20261102.log": "357d1db9afae45ca4a39f994dd76ca9672f5d0a9843626730646814b39927e6c",
+ "business-proximity-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "business-proximity-build-20261102.log": "9e2c1075dd840b0daaf9db62dc1be69d8c82df9b4b1485542209f22745d0ce23"
+ },
+ "source_sha256": {
+ "app/Services/PublicBusinessLocations.php": "0a62953996db72f1f29355c349a2d5fa668e867c4541ebfbe523344a37e5900e",
+ "app/Services/BusinessProximitySearch.php": "e72566afedc5dec25be35f051cefbf19a0d08bcb3fd6ed36f7d491ec350c3cfe",
+ "app/Http/Controllers/PublicBusinessOpportunityController.php": "62f14224aa95d30fb88dccdbeccdacd9d3ac06ba622beb74555cf4e1c46b5bc8",
+ "app/Http/Resources/PublicBusinessOpportunityResource.php": "262c6298b86deabc329859b5f2831c3f3efe7957193d5c33ffd6d6eddc3da5cf",
+ "resources/js/components/similar-businesses.tsx": "3c7ca3285a17d39f0328603574f39080ed03fd9a831e78286437f270e641828d",
+ "resources/js/pages/investment/business-marketplace.tsx": "ce67f27cc4b8e9a50d497daf08e9b8f15d00ce96ab578fbb31c19e79c41af9e2",
+ "resources/js/pages/investment/business-opportunity.tsx": "ddca3ba6a04e1cff5e38d2ccdcf0cb1900b8638b6d0398f85b8304577439329d",
+ "tests/Feature/BusinessProximitySearchTest.php": "2132060cba7f337a1aff6464c9b3788aac141334362ac0f6361bad50e030dcfd",
+ "tests/frontend/similar-businesses.test.mjs": "2188192bd707554c1de782f4e8356e3dd8726dfe51759b52a8df1112b241a973",
+ "tests/frontend/business-proximity-catalogue.test.mjs": "526194b3baf83088413c666574db08065b20734b2da04d4a04df39109b8500e5"
+ },
+ "limitations": [
+ "no demonstrated real coordinate coverage or editor intake for locations",
+ "recorded timestamp is not an original source date",
+ "no visual acceptance or destination deployment",
+ "not a road route or independently verified location"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "business_point_publication_increment_20261102": {
+ "recorded_at": "2026-11-02T19:49:39.323Z",
+ "requirement": "AUD-MARKET-01",
+ "status": "partial_local_qa_not_installed",
+ "feature_tests": 28,
+ "assertions": 677,
+ "frontend_tests": 17,
+ "checks": {
+ "phpstan": "passed; inherited rules with isolated cache after global cache directory failure",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "pint": "passed",
+ "build": "passed"
+ },
+ "workflow": "existing owner edit + independent review/approval/publication, same transaction/version lock; no new roles/routes or published-listing edit authority",
+ "preservation": [
+ "optional point fields remain encrypted and conditional",
+ "explicit path selected from existing declarations",
+ "source reused or separately identified, disclosure opt-in",
+ "unknown source dates remain unknown",
+ "stable primary UUID, secondaries unchanged, previous geometry/source in encrypted journal",
+ "legacy data unchanged without opt-in; migration rollback refuses populated source fields"
+ ],
+ "logs": {
+ "business-point-publication-final-feature-20261102.log": "7494d05f52aba540f9dabec1e8ef304c5ddade3f0cd0654fe6710466f6eda64c",
+ "business-point-publication-verified-frontend-20261102.log": "43914858bf33aa9c51a2e6f06f3104e8e644f8ec12b11d97f31950a387ad86d3",
+ "business-point-publication-isolated-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "business-point-publication-verified-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "business-point-publication-verified-check-20261102.log": "7339872280d061f2045f759ccbc246fc729285dfce429a32fa1c619217bcb471",
+ "business-point-publication-final-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "business-point-publication-verified-build-20261102.log": "f9fe59cf5fb290a0e740aa03aa0510a72c64aded385f4aa4ae29669fbf521232"
+ },
+ "source_sha256": {
+ "app/Services/BusinessPointPublication.php": "16c23999131f397ae07d1e7ff287d61d836a0ad9b417266f7f065605e3c872a6",
+ "app/Services/BusinessFormSchema.php": "97ce5b2d62aa101a77dfb3b688046d0ba22e6377f4864aa99a0ac6326523bed4",
+ "app/Services/ExistingBusinessDrafts.php": "ab22dfb444b4ed363622a998af960d09c6f2e993fc8f484e23e80a653d2e71f7",
+ "app/Services/ExistingBusinessIntake.php": "a46d9ed56bb240f59ae40afa2236784d945bf635c5a142d92152ac0195b3aec8",
+ "app/Services/PublicBusinessLocations.php": "bdc91b9f5c813245f064fcc3635ce3b467d46f404443666959bdc650784f8ed6",
+ "app/Services/BusinessProximitySearch.php": "a64e8ea02b3ae541390002c77bb68e506d72f6b508846c386433ca7fa21c89d1",
+ "app/Http/Controllers/ExistingBusinessController.php": "2638b2fc4fb3a3520a2c68f612c3efa4b0841f56cd4473be275b63ec5c132679",
+ "app/Http/Controllers/PublicBusinessOpportunityController.php": "9ac811a4cf405a5011bed8e9d72c9db2ceb26b8924059086497ee5051229fdf1",
+ "app/Http/Resources/PublicBusinessOpportunityResource.php": "45f47177c6926d30fbb4885eafe5b66a3723ddc054818d5dcaa5e85ab6f5a9bc",
+ "database/migrations/2026_11_03_000000_existing_business_location_sources.php": "9c22cebb812933d7d9d35e631f9a9fff1759b879b8adc07406229a197384d4d1",
+ "resources/js/components/business-point-summary.tsx": "57cfa820345391a16acd030a8faafdbb9cf7e4adacbba70944a2ddbd7d4a94bc",
+ "resources/js/components/similar-businesses.tsx": "1038de567e6360cce8fc6cb515a4f2f94bb41703a751b3be2e475485e9c791de",
+ "resources/js/lib/business-locations.ts": "0e37e9460e35f413200feed213d092a86c568821ab5d4866a55d2a8509eacbcf",
+ "resources/js/pages/investment/business-wizard.tsx": "60558466c6b4004ae573469e2328c253da53d30248e4d7d2db049a22861016e1",
+ "resources/js/pages/investment/business.tsx": "0e0c7f614b3ff9e7f3cb634ce52fb8959f1457569d2a2aea0e8db6485138047b",
+ "resources/js/pages/investment/business-opportunity.tsx": "580022357c27836599f0a6abf33d4cdfacb39094abef758f71c76d1144b69b82",
+ "resources/js/pages/investment/business-marketplace.tsx": "566e101f7dc06762b70507d6431b4b1fe0e84cfc96209d38943dc8cd1c89d14e",
+ "tests/Feature/BusinessPointPublicationTest.php": "86b33025261336c1e54fc4567fa38db9e36f87bf5f37f19e6ef031b61b855b0f",
+ "tests/frontend/business-point-publication.test.mjs": "a4354139c2d8f280e1d77a6d3043581515f15b1dfff54d76da7c8831cae72792"
+ },
+ "limitations": [
+ "synthetic QA only; no real coverage or browser visual proof",
+ "migration/build not installed at destination",
+ "declared point/territory is not certified spatial correspondence",
+ "existing workflow for changing published listings unchanged"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "desk_effective_dates_increment_20261102": {
+ "recorded_at": "2026-11-02T20:11:54.041Z",
+ "requirement": "AUD-CHECKLIST-01",
+ "status": "partial_local_qa_not_installed",
+ "feature_tests": 21,
+ "assertions": 314,
+ "frontend_tests": 9,
+ "checks": {
+ "phpstan": "passed; isolated cache, original inherited rules",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "pint": "passed",
+ "build": "passed"
+ },
+ "selection": "latest reached effective date, then highest version for that date; undated historical fallback; publication timestamp respected",
+ "compatibility": [
+ "request FK and answers/snapshots retained",
+ "idempotent old request creation before edition validation",
+ "implicit and explicit publication intent distinguished",
+ "initial-template JSONB key-order comparison canonicalized",
+ "calendar passage alone cannot create duplicate unchanged forms",
+ "legacy immediate route supported; future scheduling requires the additive migration",
+ "catalogue/case/path/create share one selector"
+ ],
+ "logs": {
+ "desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200"
+ },
+ "source_sha256": {
+ "app/Services/DeskServiceAvailability.php": "7ec1e41f2f4ecb9c00501a5aeb47248012e44663d7f5772df17128b990d9b12f",
+ "app/Services/DeskServiceEditor.php": "4f7db7ce167244e73463748d9fa025ea26848a38b17193dd41fd4abaf2022f42",
+ "app/Services/VirtualDesk.php": "6715275d5937cfe0cf35cb9f50ca7d775192d4ee8965caa08ff927d0bdeeb791",
+ "app/Services/InvestorPath.php": "90bbbe50d8672eea375fe20c11d20a69f5edb329d4487087eadfaa8e8dcdc063",
+ "app/Services/VirtualDeskInstallation.php": "bf05cb8c9e20282ca8eb7b5230a64d31594242e3e1ebf016a051fa8860fcad55",
+ "app/Http/Controllers/DeskServiceEditorController.php": "b56687e857d2f679ea1772ace493925ae811ce880bb1e81c56cbb714086b9aa0",
+ "app/Http/Controllers/VirtualDeskController.php": "b62aa8e06d89f209320039a5be076c34622e72f5ee04d0a9ddefbb249cb5797c",
+ "app/Http/Controllers/VirtualDeskInstallationController.php": "9a7a7d04e78ebb44905511bf91c4b3409ab246491aa5e1bce8c86693efea7766",
+ "database/migrations/2026_11_03_010000_desk_service_effective_dates.php": "dbc7b1da1f25be4d0bb85bd599e39fd4008e9a568c7b6a26d3211dfec941c73d",
+ "resources/js/pages/desk/service-editor.tsx": "c775987778c4c1d6edb4658690c45d7dd8cd997e0e5822117e813ddffc349209",
+ "resources/js/components/desk-service-history.tsx": "6d5cec32b9ba08fd0ca77fe182aa3e052b76ec2476f9933d0b98d1ba29f91d18",
+ "resources/js/pages/desk/catalogue.tsx": "65d8441842ea525c4d22c3e6f36f4cb62e5d3c36a891846966663f3a9abfcab1",
+ "resources/js/pages/desk/case.tsx": "0df6760df6b35657996a2b98a097587517b7270743704dfd43b6229a485d139a",
+ "resources/js/pages/desk/request.tsx": "ebe36d853c63c4d79b8536e540a0d34cd294eef8abfcc13e27f7276843dd1988",
+ "tests/Feature/DeskServiceEffectiveDatesTest.php": "6648667a13beefad11e6375c69a82fc26fd9d59ba9cab3a67766abbe030d0a6d",
+ "tests/frontend/desk-effective-dates.test.mjs": "c4f6f9eee887aac3b7c891a43750dc10d88ed5ec5a6ac66d3464c9ba53eb4682"
+ },
+ "limitations": [
+ "synthetic QA and directed regression only",
+ "no browser visual proof or destination migration/install",
+ "other checklist types/contexts still pending",
+ "internal workflow, not official licence/homologation; current portal calendar is stated in preview"
+ ],
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "education_draft_requirement_reconciliation_20261102": {
+ "recorded_at": "2026-11-02T20:33:32.140Z",
+ "requirement": "AUD-EDU-02",
+ "also_tracked_by": "AUD-EDU-01",
+ "status": "partial_local_existing_proofs_reused",
+ "verified_source_hashes": {
+ "app/Http/Controllers/EducationController.php": "edd7771c7225f39911afc44abb5b20d3f64a363dcb12a1cc4b4c3eb17a350f30",
+ "app/Services/EducationDeclarationDrafts.php": "1e882088009ef6d96c27c69252defaf2fe80a1c0f884eb1ed21e09f1ada425c4",
+ "resources/js/pages/education/index.tsx": "21bf4d9e4a105a1aba2516eb144e143c9986198009b60afa36f3f25ed81a248f",
+ "resources/js/components/education-submitted-snapshot.tsx": "8f64fbf6c39a0166405340f68ff8acc0dd38d5eea4f994ae825faa15b8939a4a",
+ "tests/Feature/EducationDeclarationDraftsTest.php": "495fc00a3ce9ea0dffb761d6e3eb2795b6b3b5678a698ff941db2a76f01c7678",
+ "tests/frontend/education-drafts.test.mjs": "718b422c785b962d55dbcf2db9ac549010d69db83aee036c2540f01cc7dd9656"
+ },
+ "reused_receipts": [
+ "education_drafts_ui_increment_20261102",
+ "education_drafts_concurrency_increment_20261102"
+ ],
+ "feature_tests": 14,
+ "assertions": 333,
+ "frontend_tests": 5,
+ "concurrency_scenarios": 10,
+ "new_tests": 0,
+ "application_changes": 0,
+ "active_writes": 0,
+ "remaining": [
+ "visual proof",
+ "destination installation",
+ "other profiles/dashboards tracked under EDU03/01"
+ ]
+ },
+ "proactive_supply_review_increment_20261102": {
+ "recorded_at": "2026-11-02T20:38:04.739Z",
+ "requirement": "AUD-ESTABLISHMENT-01",
+ "status": "partial_local_qa_not_installed",
+ "feature_tests": 9,
+ "assertions": 138,
+ "frontend_tests": 6,
+ "reused_accepted_delivery": {
+ "path": "docs/investmoz/unification/proactive-supply-git-delivery-20261028.json",
+ "sha256": "e076200870612c3e98a2d2e6aa4bf881ad15166666dd11727c7ac3bf54a6a595",
+ "observations_historical": 361464,
+ "not_unique_companies": true
+ },
+ "checks": {
+ "phpstan": "passed; original inherited rules with private cache",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "pint": "passed",
+ "build": "passed"
+ },
+ "preservation": {
+ "database": "proactive_investment_20261027_test",
+ "port": 55441,
+ "tables": [
+ {
+ "table": "desk_cases",
+ "count": 0,
+ "checksum": "d41d8cd98f00b204e9800998ecf8427e"
+ },
+ {
+ "table": "documents",
+ "count": 1,
+ "checksum": "dae9912a8e9f5afdac1c8feff24defb4"
+ },
+ {
+ "table": "geo_locations",
+ "count": 1921,
+ "checksum": "286e697d3c231a5c42929f5ae9842349"
+ },
+ {
+ "table": "opportunities",
+ "count": 1,
+ "checksum": "49652269953149d5a703e9434fabf5e6"
+ },
+ {
+ "table": "organizations",
+ "count": 1,
+ "checksum": "733ca6e7b1ed7c0c60781e0878c2a27e"
+ },
+ {
+ "table": "portal_resources",
+ "count": 0,
+ "checksum": "d41d8cd98f00b204e9800998ecf8427e"
+ },
+ {
+ "table": "proactive_supply_observations",
+ "count": 0,
+ "checksum": "d41d8cd98f00b204e9800998ecf8427e"
+ },
+ {
+ "table": "proactive_supply_sources",
+ "count": 0,
+ "checksum": "d41d8cd98f00b204e9800998ecf8427e"
+ },
+ {
+ "table": "projects",
+ "count": 0,
+ "checksum": "d41d8cd98f00b204e9800998ecf8427e"
+ },
+ {
+ "table": "sectors",
+ "count": 1,
+ "checksum": "a540dc2c8cc547871d458993f8a789dd"
+ },
+ {
+ "table": "users",
+ "count": 1,
+ "checksum": "358661f9b923c35ad24eca2b41c8d46a"
+ }
+ ],
+ "all_eleven_row_counts_and_checksums_equal": true,
+ "test_data_rolled_back": true,
+ "sequence_counters_not_asserted": true
+ },
+ "logs_sha256": {
+ "proactive-supply-review-final-feature-20261102.log": "47f395d9fc0c0e34663f86da6edcf2570c5fa004b457762498fda1b749eb6c18",
+ "proactive-supply-review-final-frontend-20261102.log": "15c9f2e8bdded6d98b02fc165fb7310028a32e39db328f21d79bd2d35993ccfb",
+ "proactive-supply-review-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "proactive-supply-review-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "proactive-supply-review-check-20261102.log": "30985e0423a40c688dc3af8f048770e86257afb22c47ae880e16af88ad4f76ff",
+ "proactive-supply-review-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "proactive-supply-review-build-20261102.log": "db6750de18599456ee086ac717b7d46d09044db37052013cb29a1eba47283c5a",
+ "proactive-supply-review-preservation-before-20261102.json": "8a6c991fe328243f003aac3912c000a031be2623771b7ee879563a953ec9dc8c",
+ "proactive-supply-review-preservation-after-20261102.json": "8a6c991fe328243f003aac3912c000a031be2623771b7ee879563a953ec9dc8c"
+ },
+ "source_sha256": {
+ "app/Services/ProactiveSupply.php": "a65d7d5022d050e62e5cf018929891ad32aaccd6ae46aab85f7989f59d97b25c",
+ "app/Http/Controllers/ProactiveSupplyController.php": "298f060a82f042b789ddc03cb5abf70a99ebd14c2085571aaae541a677ad82b4",
+ "routes/web.php": "2f70812a1486adacac7674d744993d154ebe9298d662907fad94410fa1d80e18",
+ "resources/js/pages/management/proactive-supply-review.tsx": "9b5f549affe44d1440d1b0a2078f7bade4a716ad953360fb4df507d0a012b1e2",
+ "resources/js/components/proactive-supply.tsx": "63b6982e43b9dc72fa55134827af76de06c9d26470f0633d81c83fc72e207e1f",
+ "tests/Feature/ProactiveSupplyReviewTest.php": "607713d73f296f0d75ca0d148516e12bfafbc01566a360babde07c623f71a1d5",
+ "tests/frontend/proactive-supply-review.test.mjs": "609ec605ee52e77edd464c86854f918b283ec3eb7cff7b2b25548e7aaf043a6e"
+ },
+ "limitations": [
+ "readonly review; no entity merge or geographic decision",
+ "legacy suite fixture lacks its expected sectors in current QA; original failure retained, no global green claim",
+ "synthetic QA only; browser visual and new destination installation pending",
+ "other entity-reconciliation/formats still partial",
+ "historical counts not a current destination inventory"
+ ],
+ "active_writes": 0,
+ "migrations": 0,
+ "source_reimports": 0,
+ "external_messages": 0
+ },
+ "primary_module_views_reconciliation_20261102": {
+ "recorded_at": "2026-11-02T20:48:19.831Z",
+ "requirements": [
+ "AUD-FUND-01",
+ "AUD-EDU-01",
+ "AUD-EDU-02",
+ "AUD-EDU-03"
+ ],
+ "status": "existing_local_proofs_reconciled_not_installed",
+ "source_sha256": {
+ "app/Http/Controllers/EducationController.php": "edd7771c7225f39911afc44abb5b20d3f64a363dcb12a1cc4b4c3eb17a350f30",
+ "app/Services/EducationDeclarationDrafts.php": "1e882088009ef6d96c27c69252defaf2fe80a1c0f884eb1ed21e09f1ada425c4",
+ "resources/js/pages/education/index.tsx": "21bf4d9e4a105a1aba2516eb144e143c9986198009b60afa36f3f25ed81a248f",
+ "resources/js/components/education-submitted-snapshot.tsx": "8f64fbf6c39a0166405340f68ff8acc0dd38d5eea4f994ae825faa15b8939a4a",
+ "tests/Feature/EducationDeclarationDraftsTest.php": "495fc00a3ce9ea0dffb761d6e3eb2795b6b3b5678a698ff941db2a76f01c7678",
+ "tests/frontend/education-drafts.test.mjs": "718b422c785b962d55dbcf2db9ac549010d69db83aee036c2540f01cc7dd9656",
+ "tools/verify-funding-concurrency.php": "fc111dbdc80dcbd1e440fd5d8269c70ab8639fa40c4a7f19a12c0d86c68fec2f",
+ "resources/js/components/funding-criteria-assessment.tsx": "34a1cabfb18eeadfab02e57dcfbd7976cf1fea0220af92d56ad209032cfe43b7",
+ "resources/js/pages/funding/show.tsx": "5fc036b7b1557810369b26be5c65a6292ff13a6a6a14f7cd10ec20f4143b8e97",
+ "tests/frontend/funding-criteria-assessment.test.mjs": "88efd27b017e9792a77c164064c78a5451441c31b68e190bbe2b0392ef8299de",
+ "database/migrations/2026_11_02_220000_investment_funding_alerts.php": "c754b81c45031b7921ee079ff9057d24c53307a6fc619c8ebff8426c4f60e3c6",
+ "app/Services/InvestmentOpportunityAlerts.php": "9669b494961c11189688e42d4a3baa4ccf225489c93073234a08047d628e669c",
+ "app/Services/InvestmentWorkspace.php": "14437df3de66344d4d6276132e3b8ddd43c82b4f0582e8fbeec3a65aeefe2a21",
+ "app/Services/FundingProgrammes.php": "6f2f0db08ebf4443243ea282e7e556a92f86cc64dba10012dfcdb76cea87c510",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "4714ddea4b6f0408599f8748f2f2668f604f18ee2a61852322932a0e2f306c30",
+ "resources/js/components/opportunity-alert-preferences.tsx": "c76a36fa7e2c51081558273a828c70c93d5cd491dc8017f564b7af6a6671d550",
+ "resources/js/pages/investment/notifications.tsx": "a3f279183ea4ec4e394b5577f996f12a21c2937118072f441af30c6801fb5ae4",
+ "tests/Feature/InvestmentFundingAlertsTest.php": "5fe7e20b6f59cf09ccf380d9b723f79a87cc2859bee0fe7e34079b79775259fe",
+ "tests/Feature/InvestmentOpportunityAlertsTest.php": "084a471709fcdac83c0b2f7a945642ace09c247b494f0476b755ca2ec1685b2e",
+ "tests/frontend/opportunity-alert-preferences.test.mjs": "5ce6f27f2c681497b944e7f19e64283ae8835e3af4c9818dcaa1767d47954600"
+ },
+ "new_tests": 0,
+ "application_changes": 0,
+ "active_writes": 0,
+ "reused_receipts": [
+ "education_draft_requirement_reconciliation_20261102",
+ "funding_assessment_concurrency_increment_20261102",
+ "funding_alerts_increment_20261102"
+ ]
+ },
+ "maturity_publication_increment_20261102": {
+ "recorded_at": "2026-11-02T20:54:14.157Z",
+ "requirement": "AUD-OP-05",
+ "status": "partial_local_qa_not_installed",
+ "tests": 15,
+ "assertions": 371,
+ "current_stages": 8,
+ "historical_levels": 6,
+ "invalid_code_cases": 1,
+ "checks": {
+ "pint": "passed",
+ "phpstan": "passed; inherited rules with private cache",
+ "frontend": "unchanged; no unnecessary repeat"
+ },
+ "database": {
+ "name": "maturity_publication_20261102_test",
+ "host": "127.0.0.1",
+ "port": 55441,
+ "synthetic": true,
+ "previous_evidence_databases_reset": false
+ },
+ "source_sha256": {
+ "app/Services/OpportunityProfileWorkflow.php": "77cac85d66bbb9669eb9da65d34c0ec57e77ceba4b6b85c9d7d7e85329d562bb",
+ "app/Services/OpportunityMaturity.php": "62bfdfbcc470c66142ceb30356f33daf6a8f9777783e6c17e9fbfa0b070ee481",
+ "app/Services/OpportunityManagement.php": "bf737e8a379794b2ab0c8869228ee51df0f92609ca6f5e27857bcf6f57354c1a",
+ "tests/Feature/OpportunityCanonicalWorkflowTest.php": "c196baf64f287affe0923172e4e430fb7856e42f05f8494588cb8b48af320b23"
+ },
+ "logs_sha256": {
+ "maturity-republication-red-20261102.log": "9235d0d6930ae25fdb1fb1cc883336b0035d7e856c8984faf08bb7dc3f344706",
+ "maturity-republication-reproduction-20261102.log": "a2f6e8b9d9c1a0d168c1ec074cd4e3b7a687652eef621039efc9f7c66479efd0",
+ "maturity-optional-stage-red-20261102.log": "e686dc8263dd8a7631213f0a7eb49202254c74c4d538d07117d8e786ac9f42c4",
+ "maturity-republication-feature-20261102.log": "5e0eb8c4c8cf7982685243a4ec92acc57e0d84b2f3dbe27270650446acdbe0b8",
+ "maturity-clearing-feature-20261102.log": "4d1e0644d73cf57abe25538ac72bd7a7163f7578f9e229593830f22bb3ab0a42",
+ "maturity-clearing-complete-feature-20261102.log": "68f8b2b20c877835fba61ab51589ab39a2331af6364488d139c06bdeb294972e",
+ "maturity-republication-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "maturity-republication-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2"
+ },
+ "limitations": [
+ "internal publication and shared filter semantics; not new public/visual acceptance",
+ "legacy adoption, other categories/variants and destination delivery remain partial",
+ "synthetic policy scan metadata is not new real antimalware evidence"
+ ],
+ "active_writes": 0,
+ "external_messages": 0,
+ "migrations": 0
+ },
+ "company_comparison_increment_20261102": {
+ "recorded_at": "2026-11-02T21:20:45.496Z",
+ "requirement": "AUD-COMPANY-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 14,
+ "passed": 14,
+ "assertions": 385,
+ "duration_ms": 94618
+ },
+ "frontend_tests": 6,
+ "checks": {
+ "phpstan": "passed; inherited rules/private cache",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "official_source": {
+ "url": "https://tsrm.gov.mz/wp-content/uploads/2025/10/Dec_Lei_1_2022.pdf",
+ "edition": "BR99/2022 I Série 3.º Suplemento",
+ "sha256": "8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f",
+ "private_original": "storage/app/private/company-sources-20261102/commercial-code-republished-20220525.pdf",
+ "source_already_accepted": true,
+ "new_scan_or_library_publication_claimed": false
+ },
+ "qa": {
+ "database": "company_comparison_20261102_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "users": 0,
+ "cases": 0,
+ "organizations": 0,
+ "company_declarations": 0
+ },
+ "source_sha256": {
+ "config/company-comparison.php": "403f441cfee35afefb79afaa380debc71b632afb7c9b94d223af69a3a355a4cc",
+ "app/Services/CompanyComparison.php": "a165bc22c92cd825a02f83d07a862239a594442ee65e907ba67745f907df8906",
+ "app/Http/Controllers/CompanyComparisonController.php": "edfcb1fef24edace9de040fa413563f90572be3d33d13d4b54c114e2049f7802",
+ "app/Http/Controllers/InvestorPathController.php": "2f7109f84bd418e739c9f8bb5bca84edf2fceb8dcb3febe1cbe197a7a2d25ed5",
+ "app/Services/InvestorPath.php": "e5c4648e380d5e30035ddaecaadb70f0c6a84558b1a959530029bba8b97c6b4a",
+ "routes/investor-path.php": "3524605d3b76f057fa439a0680ca97891d1704893cf8ac9aeda6facbd225e517",
+ "resources/js/lib/company-comparison.ts": "309440000d5ef9465790d0d617fa95eedf560161763894c1a938f9e62555557e",
+ "resources/js/pages/investment/company-comparison.tsx": "dc76af17341af793a6dbac990459990f989659deed86ec24125d7b57bf24cea2",
+ "resources/js/pages/investment/profile.tsx": "1beb04704b4579f9e27635054076dc6af8e0af873e83625b87a4c1660118dcba",
+ "resources/js/pages/investor-path/index.tsx": "fdab65c82f8cd98f22464a6c5705b1f1721d8461edaae558c2c2d8b60bf4ed36",
+ "resources/js/pages/investor-path/show.tsx": "4d9bf9552ec60c2511d4b41e59e1b38527cc824e702c579c6d803fddb6aebf24",
+ "resources/js/pages/portal/services.tsx": "f00ddaebacb65c92ba09634c57780ed2a1070d5966063bafbdf53287403c7dd3",
+ "tests/Feature/CompanyComparisonTest.php": "69179271223410266bb9212a73096cad8df6054fccac5c023510117170618de3",
+ "tests/frontend/company-comparison.test.mjs": "a50ece1a43454f8328e7745424eba81dabfa2285faa65645d3e693b2109acc03"
+ },
+ "logs_sha256": {
+ "company-comparison-finalized-feature-20261102.log": "ebe5d1d04444d6430241b47a1de01f6d7ab90505a4f8343c1df1f87332cbe94a",
+ "company-comparison-finalized-frontend-20261102.log": "0558030ff987fa29827db71b2b5ea745788a3799d813a2278dc0382bb16818d8",
+ "company-comparison-finalized-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "company-comparison-finalized-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "company-comparison-finalized-check-20261102.log": "7bdeb7423ff962e518354db2ed4b4e1275e0ed80ca721a26ad07c65478725760",
+ "company-comparison-finalized-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "company-comparison-finalized-build-20261102.log": "d544e05fc262e5018ad240cdaecfb51e717ec0694604cebdbd9b308c6df78079",
+ "company-comparison-qa-preservation-20261102.json": "02ad7aaf830fbc2e9b980615ff9072f7916633a9bdd56adae37494c0ac4ef813"
+ },
+ "limitations": [
+ "synthetic policy/HTTP/frontend proofs; no real browser login or visual acceptance",
+ "base comparison of cited edition; special activities/redactions not fully encoded",
+ "AUD-COMPANY-02 specific templates not delivered by this module",
+ "two-process concurrency not newly claimed by sequential lock/version tests",
+ "destination deployment pending"
+ ],
+ "active_writes": 0,
+ "external_messages": 0,
+ "new_migrations": 0,
+ "active_migrations": 0
+ },
+ "company_preparation_increment_20261102": {
+ "recorded_at": "2026-11-02T21:47:22.039Z",
+ "requirement": "AUD-COMPANY-02",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 18,
+ "passed": 18,
+ "assertions": 343,
+ "duration_ms": 156595
+ },
+ "frontend_tests": 12,
+ "new_feature_cases": 8,
+ "new_frontend_cases": 6,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "source": {
+ "original": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/por executar/Complemento consolidado — Criação de empresas e minutas de contratos sociais.docx",
+ "sha256": "b20c6517784b6d44aa22beb67748d3f3b224f58c60a7dcb378a185669c2c543e",
+ "actual_templates_supplied": false,
+ "owner_reply": "nao tenho neste momento a url",
+ "read_only": true
+ },
+ "qa": {
+ "database": "company_preparation_20261102_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "users": 0,
+ "cases": 0,
+ "organizations": 0,
+ "company_declarations": 0,
+ "requests": 0
+ },
+ "source_sha256": {
+ "app/Services/CompanyPreparation.php": "e473813b4abffeb02c5a2f0f86f77afb9c225cf3d5d444ae992938e6129682b9",
+ "app/Http/Controllers/CompanyPreparationController.php": "87d84329c83bc6dc778a4684c49ce413975e1d920bf622fdb124f430962c6c88",
+ "routes/investor-path.php": "ac7797530ba3953e51ab4fcf1656a6992ee61d7344989fe93c6dc12d0f292b65",
+ "resources/js/lib/company-preparation.ts": "97eb37a3376213495de259a8715301384fa84e45ce7584a7d9a48f487e92a250",
+ "resources/js/pages/investment/company-preparation.tsx": "0d10c933b3757822061b94650225a76e29068dd560c5cd057a462cd192403c7b",
+ "resources/js/pages/investor-path/show.tsx": "0b540c664bdab89c60f1eef2515648c5e4be6b48daa5587b07e1f9e086072c88",
+ "tests/Feature/CompanyPreparationTest.php": "0fda15a00915392d70e7bbdefab4ab9f2976285e967327689a1925d474b7a433",
+ "tests/frontend/company-preparation.test.mjs": "8d0c6114bcdd34a6d277cbd377a2e07e51f8da655c7463c89cc66392cb7ab415"
+ },
+ "log_sha256": {
+ "company-preparation-final-feature-20261102.log": "6f07bd1c9f22e13c0fea7f017b97b7015f7ffea86ad6e8cf1f736f39b8f1e055",
+ "company-preparation-final-frontend2-20261102.log": "24aaccadd7952c9076b8a09d3b639b58f805a9950106ce284e303453fe65398a",
+ "company-preparation-final-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "company-preparation-final-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "company-preparation-final-check-20261102.log": "e01fcd44c34cf388d5fb65aebc29fc8fb40846f4907b215d9ac78cba1b341e90",
+ "company-preparation-final-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "company-preparation-final-build2-20261102.log": "1ce0dac0d9c296f361d33a177b63c494268c66446296155c0307e7e3659859c4",
+ "company-preparation-qa-preservation-20261102.json": "2f8adbcf3d6ffbc2e32b485f73156a84844da3a5d61facca63d82f44c0b42e07"
+ },
+ "limitations": [
+ "factual preparation, not contractual derivative",
+ "seven exemplars/versioned library binding pending",
+ "professional review/signature/submission/registry not implemented here",
+ "activity catalogue/licensing integration pending",
+ "no real browser/login acceptance or destination installation",
+ "no new two-process concurrency proof"
+ ],
+ "new_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0
+ },
+ "capital_guidance_increment_20261102": {
+ "recorded_at": "2026-11-02T22:03:35.648Z",
+ "requirement": "AUD-CAPITAL-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 21,
+ "passed": 21,
+ "assertions": 524,
+ "duration_ms": 159709
+ },
+ "frontend_tests": 13,
+ "new_feature_cases": 7,
+ "new_frontend_cases": 7,
+ "qa": {
+ "database": "capital_guidance_20261102_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "users": 0,
+ "cases": 0,
+ "organizations": 0,
+ "company_declarations": 0,
+ "requests": 0,
+ "row_visibility": [
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ]
+ },
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "exemplars": {
+ "bni-capital-risco.html": {
+ "url": "https://www.bni.co.mz/banca-de-investimento/capital-de-risco/",
+ "sha256": "fbeaab84c4cad22ee63e5c1dfb61ea3206333885ddd80c8001d37a3f49d2820e",
+ "private_path": "storage/app/private/capital-guidance-sources-20261102/bni-capital-risco.html",
+ "consulted_on": "2026-11-02",
+ "new_public_library_import": false
+ },
+ "ifc-equity.html": {
+ "url": "https://www.ifc.org/en/what-we-do/products-and-services/equity-investments",
+ "sha256": "c9e07821dfb84310ad41c4811b8c7267b880593d72b4ff2011124b986c8f9433",
+ "private_path": "storage/app/private/capital-guidance-sources-20261102/ifc-equity.html",
+ "consulted_on": "2026-11-02",
+ "new_public_library_import": false
+ },
+ "ifc-loans.html": {
+ "url": "https://www.ifc.org/en/what-we-do/products-and-services/loans",
+ "sha256": "0130c12657abfbd8c80011be213f555424abe4cfc50eae4eb444b935edf65904",
+ "private_path": "storage/app/private/capital-guidance-sources-20261102/ifc-loans.html",
+ "consulted_on": "2026-11-02",
+ "new_public_library_import": false
+ },
+ "ifc-apply.html": {
+ "url": "https://www.ifc.org/en/what-we-do/products-and-services/how-to-apply-for-financing",
+ "sha256": "fa6faed394591dcf6afff76bc7e4fff539d4a3587ca1b303a08f863759dd3437",
+ "private_path": "storage/app/private/capital-guidance-sources-20261102/ifc-apply.html",
+ "consulted_on": "2026-11-02",
+ "new_public_library_import": false
+ },
+ "chase-debt-equity.html": {
+ "url": "https://www.chase.com/business/knowledge-center/grow/debt-vs-equity-financing",
+ "sha256": "baeb5424bfdadcb011787404fbc4ddc39cab560593232e4799bc93abff4f61bf",
+ "private_path": "storage/app/private/capital-guidance-sources-20261102/chase-debt-equity.html",
+ "consulted_on": "2026-11-02",
+ "new_public_library_import": false
+ }
+ },
+ "source_sha256": {
+ "config/investment-guides.php": "99fa2f727e259ec3c85e74ca96be5715f0dd3156abec038aa7101c584a873fbe",
+ "app/Services/InvestmentGuides.php": "7dace026a5793118c8b222612c6a79d76241f8fb5d7a6e1af1c332902236413e",
+ "app/Http/Controllers/InvestmentGuideController.php": "204e8950da9e90a9a87c4bef61a42cbf7f969a48a4084777cb35c1baff3157a0",
+ "app/Http/Controllers/InvestorPathController.php": "7c7efecbbb0238f8143bf23d1d83e4ffdc43211d099188e0c6dae772cafdba85",
+ "routes/investor-path.php": "55a5e93e072d5a95f95fb0779f6fdb08fcf4bfcc60eea108f06475b7f094e0ca",
+ "resources/js/lib/investment-guides.ts": "3b82f6df939d322bb6a5a1f4c490d7b860fd258539f2d19f92bdf0035372a482",
+ "resources/js/pages/investment/guide.tsx": "9301c204b85f5cb2ec44032bc9bb39c023f8591d065c3a68ab86e392a4fcef6a",
+ "resources/js/pages/investor-path/index.tsx": "5def3fe1ce6bca0330c7eaa9aef6bd55f4a20e61a9296caf96dd44f0d2c63f6a",
+ "resources/js/pages/investor-path/show.tsx": "5b892dfd1a7d010b6e6995b320a788cc974af96b499a3c43357428fe1c359adc",
+ "resources/js/pages/portal/services.tsx": "928cb17c73c3b1bb453957633e22499365ce74a1f1490402a7fe84dcbb277f07",
+ "tests/Feature/InvestmentGuidesTest.php": "5f7ebf22710e7df5f1606748385a26dd63bb562283df25aef35ac9629d72b685",
+ "tests/frontend/investment-guides.test.mjs": "ff70471441c9c302de1c4e8d5a14385aecad632733a0af07f197fe599d0ccca9"
+ },
+ "logs_sha256": {
+ "capital-guidance-final-feature-20261102.log": "dae6ef47d0f519a51a5406edceb52379e66f03a7f08f2672b24b3aa31fe23eb2",
+ "capital-guidance-final-frontend-20261102.log": "892f5a8e66ad35c9c14f9c45e1d364859cd12b25f239c1b6d3fffb26a00decde",
+ "capital-guidance-final-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "capital-guidance-final-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "capital-guidance-final-check-20261102.log": "eb6a6711c9c11e13fac1f85be41fa2d98e07e9a7a93a06aad1b8136d85a69847",
+ "capital-guidance-final-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "capital-guidance-final-build2-20261102.log": "12234114bd09f840cfa4573a178fb3d4e176b1143977a1e9d97daf032b46c86f",
+ "capital-guidance-qa-preservation-20261102.json": "51f5f27db447ba65b5c52c648e6a6ac751bac08735311ad1525c17d082e0a3f6"
+ },
+ "limitations": [
+ "synthetic HTTP/frontend proofs, no real browser login/visual acceptance",
+ "destination installation pending",
+ "provider examples not universal eligibility/product availability",
+ "AUD-CAPITAL-02 admission guide not implemented by this increment",
+ "no new two-process concurrency proof"
+ ],
+ "active_writes": 0,
+ "new_migrations": 0,
+ "external_messages": 0
+ },
+ "bvm_admission_increment_20261103": {
+ "recorded_at": "2026-11-02T22:25:37.181Z",
+ "requirement": "AUD-CAPITAL-02",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 14,
+ "passed": 14,
+ "assertions": 474,
+ "duration_ms": 218278
+ },
+ "frontend_tests": 18,
+ "new_feature_cases": 7,
+ "new_frontend_cases": 5,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "qa": {
+ "database": "bvm_admission_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "users": 0,
+ "cases": 0,
+ "organizations": 0,
+ "company_declarations": 0,
+ "requests": 0,
+ "row_visibility": [
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ]
+ },
+ "originals": {
+ "market-code-2009.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/codigo_mercado_valores_mobiliarios.pdf",
+ "sha256": "5f576381eb42ffe3f64ab9848b5cfb61956dc123a87d3feb48d4f2ce5faf112e",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/market-code-2009.pdf"
+ },
+ "admission-process-2010.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/regulamentos/reg_processo_de_admissao_a_cotacao.pdf",
+ "sha256": "7cc5dddf65ef655f5f9e738d616d4c1ed51ba852f04b80f9eae668890d84022a",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/admission-process-2010.pdf"
+ },
+ "second-market-2010.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/legislacao/regulamento_segundo_mercado.pdf",
+ "sha256": "c1bb9ba196e9f6d49a96b5857d687482d1f58bb7a9d5fd5d6e9d348c2a89ce92",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/second-market-2010.pdf"
+ },
+ "third-market-2021.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/regulamentos/RegulamentoTerceiroMercado.pdf",
+ "sha256": "a56adb4a8f91ff22dea870fa0c5b3f4c4faf5281ecbca8a7dc6d76248b03a340",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/third-market-2021.pdf"
+ },
+ "minimums-2024.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/Montantes_Minimos_Admissao_Cotacao_2024.pdf",
+ "sha256": "3cfbb7a55d2be4d1a01be7b249d10a940224537c5c868c98a7a7ef1d7a1e72e4",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/minimums-2024.pdf"
+ },
+ "central-2006.pdf": {
+ "url": "https://www.bvm.co.mz/documentos/central/CVM-Central_Valores_Mobiliarios.pdf",
+ "sha256": "81e9a9d251fb7304fbe06ae769a652374142b22a8524ea00549d63247e9ea474",
+ "private_path": "storage/app/private/bvm-guide-sources-20261103/central-2006.pdf"
+ }
+ },
+ "reused_commercial_original": {
+ "path": "storage/app/private/company-sources-20261102/commercial-code-republished-20220525.pdf",
+ "sha256": "8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f"
+ },
+ "pdf_inventory": [
+ {
+ "file": "admission-process-2010.pdf",
+ "pages": 28,
+ "text_chars": [
+ 1569,
+ 2110,
+ 2030,
+ 1961,
+ 2418,
+ 2323,
+ 1956,
+ 1951,
+ 474,
+ 1936,
+ 2244,
+ 616,
+ 1077,
+ 1291,
+ 2085,
+ 2239,
+ 2262,
+ 2551,
+ 1902,
+ 1959,
+ 2362,
+ 2412,
+ 1826,
+ 1335,
+ 1907,
+ 2107,
+ 1918,
+ 855
+ ],
+ "sha256": "7cc5dddf65ef655f5f9e738d616d4c1ed51ba852f04b80f9eae668890d84022a"
+ },
+ {
+ "file": "central-2006.pdf",
+ "pages": 10,
+ "text_chars": [
+ 1726,
+ 2263,
+ 2177,
+ 2150,
+ 1931,
+ 2104,
+ 2776,
+ 2528,
+ 1993,
+ 1556
+ ],
+ "sha256": "81e9a9d251fb7304fbe06ae769a652374142b22a8524ea00549d63247e9ea474"
+ },
+ {
+ "file": "market-code-2009.pdf",
+ "pages": 68,
+ "text_chars": [
+ 1345,
+ 1696,
+ 3827,
+ 2823,
+ 3113,
+ 2936,
+ 2440,
+ 2721,
+ 2571,
+ 2911,
+ 3201,
+ 2909,
+ 2360,
+ 2584,
+ 3041,
+ 2509,
+ 2989,
+ 2689,
+ 2185,
+ 2662,
+ 2247,
+ 2331,
+ 2561,
+ 2604,
+ 2489,
+ 2111,
+ 2052,
+ 1909,
+ 2593,
+ 2979,
+ 2574,
+ 2345,
+ 2890,
+ 1864,
+ 2623,
+ 2541,
+ 2574,
+ 2062,
+ 2653,
+ 2631,
+ 2180,
+ 2288,
+ 2876,
+ 1899,
+ 2850,
+ 2364,
+ 1879,
+ 2000,
+ 3157,
+ 2306,
+ 2280,
+ 3100,
+ 2259,
+ 2937,
+ 2103,
+ 2431,
+ 1942,
+ 2326,
+ 2709,
+ 3071,
+ 3000,
+ 2972,
+ 2442,
+ 2049,
+ 2287,
+ 3122,
+ 2568,
+ 635
+ ],
+ "sha256": "5f576381eb42ffe3f64ab9848b5cfb61956dc123a87d3feb48d4f2ce5faf112e"
+ },
+ {
+ "file": "minimums-2024.pdf",
+ "pages": 2,
+ "text_chars": [
+ 0,
+ 0
+ ],
+ "sha256": "3cfbb7a55d2be4d1a01be7b249d10a940224537c5c868c98a7a7ef1d7a1e72e4"
+ },
+ {
+ "file": "second-market-2010.pdf",
+ "pages": 13,
+ "text_chars": [
+ 1716,
+ 1943,
+ 1613,
+ 321,
+ 1918,
+ 2835,
+ 3245,
+ 2849,
+ 3179,
+ 2501,
+ 2033,
+ 3118,
+ 1631
+ ],
+ "sha256": "c1bb9ba196e9f6d49a96b5857d687482d1f58bb7a9d5fd5d6e9d348c2a89ce92"
+ },
+ {
+ "file": "third-market-2021.pdf",
+ "pages": 6,
+ "text_chars": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "sha256": "a56adb4a8f91ff22dea870fa0c5b3f4c4faf5281ecbca8a7dc6d76248b03a340"
+ },
+ {
+ "file": "commercial-code-republished-20220525.pdf",
+ "pages": 76,
+ "text_chars": [
+ 5359,
+ 7475,
+ 8713,
+ 7930,
+ 7474,
+ 7710,
+ 8144,
+ 7511,
+ 7436,
+ 8079,
+ 8433,
+ 8262,
+ 9630,
+ 9120,
+ 8583,
+ 8451,
+ 8326,
+ 8280,
+ 7968,
+ 9328,
+ 9012,
+ 9331,
+ 7796,
+ 7692,
+ 8784,
+ 8475,
+ 8252,
+ 8909,
+ 7473,
+ 8679,
+ 8034,
+ 8086,
+ 8889,
+ 8082,
+ 7577,
+ 7678,
+ 7688,
+ 8040,
+ 7291,
+ 8618,
+ 8437,
+ 8057,
+ 8603,
+ 9036,
+ 7751,
+ 8232,
+ 8009,
+ 8393,
+ 7071,
+ 8213,
+ 8377,
+ 8003,
+ 7919,
+ 8844,
+ 8414,
+ 8680,
+ 8670,
+ 8317,
+ 8433,
+ 8828,
+ 7757,
+ 8089,
+ 8189,
+ 8218,
+ 8206,
+ 7849,
+ 8325,
+ 7847,
+ 7324,
+ 8131,
+ 8420,
+ 8889,
+ 8528,
+ 8024,
+ 8437,
+ 7571
+ ],
+ "sha256": "8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f"
+ }
+ ],
+ "visually_inspected_source_pages": {
+ "third-market-page-1.png": "70076963cba5248ad91067f3a23b780a308370fd3182101a8eb2f662a914cd80",
+ "third-market-page-2.png": "88cda3cbc1926c124c557371ac0227c6029ff8fcb5c302f1f8153cc4570e9539",
+ "third-market-page-3.png": "3f68a55b8c19c438855dd4d1412658c1d326dcd674624a9386416db336e40ee3",
+ "third-market-page-4.png": "4836f7655a33713fe17b069a2b814aa521e2815f7f3470f0bbeb0dbe0eff6864",
+ "third-market-page-5.png": "675e22b95c1befac13b1927a896d3cfc64baab423be6165d2075c453312f2bb2",
+ "third-market-page-6.png": "467e9d54ae667fcd1c915264c87a365dc46aabb5a5b7d628f156e5ea21d5e567",
+ "minimums-2024-page-1.png": "c54627bbf14d253f9b10a90d878c7dd7a790b39c37e7773b2c5f608d4fe2d8ab",
+ "minimums-2024-page-2.png": "6f9f5d2df2fdd8c2443e86eed34b5ecd95e2d5ce36ac94fd824c929762142b2e",
+ "market-code-2009-page-4.png": "7e1f9ee81cddf3db7c270782204108b1cd812036a6704263247e74c571093848",
+ "market-code-2009-page-30.png": "dc4ccff8cdd478f5744c1f91c0aea44d7f7b8a6ec2ddef5b80b95289407112c4",
+ "market-code-2009-page-32.png": "e58b36827bffb94fef2ae2c5bee379d2e452751b753cb67e94c66d53d2ca944e",
+ "market-code-2009-page-33.png": "62bef3f1bfec77ac672f38349fed52c959c8effc79cb5e74999e2980a2f18bb2",
+ "market-code-2009-page-40.png": "27fe878950b2a9f859da0e1c57930551a959c02a31631945519f72965bb2c957",
+ "commercial-code-republished-20220525-page-1.png": "be0b55fb73f607d4bcc64179a43dba92765cbfc943dbba79d82e9184cba2c56f",
+ "commercial-code-republished-20220525-page-63.png": "ec8f1e410960d44c5caa2fbdbbd83febce12c961a116d14f8d97d71bdbce7457",
+ "admission-process-2010-page-10.png": "25190be398382b48e40b32b8e1d96b1624ce294f74f65051a13775b1a3e7432a",
+ "admission-process-2010-page-13.png": "0a2199b247c245746f07e76150558cad8b91dfe632142ebd54b1dc88af086138",
+ "second-market-2010-page-2.png": "ab4321413e936c5507b267a73d8e9f5df08d5263813db4fd4e0d8fafc8c43445",
+ "central-2006-page-1.png": "a1db113f0e362c39aabe0961d99bcaf526fc71d928136d8fffd7ba4c991e3b71",
+ "central-2006-page-2.png": "f22d10c0c306a9e99c970c5fd4ce9a5263081b98d9d8c9d9f67000d836a54599"
+ },
+ "code_sha256": {
+ "config/bvm-admission-guide.php": "ad83d8937e684ed418726ba22605660946f77e82ed21e682ae0c033092add144",
+ "config/investment-guides.php": "2a708217b108272def3da4d1ce8d9c08238241cc599672ea548dbb2591fbdf60",
+ "resources/js/pages/investment/guide.tsx": "a67a4fa98cbb62f87c2f2652697fc2b03a831e4747acf16dcd1d7c198f589924",
+ "resources/js/pages/investor-path/show.tsx": "64f9dbdb709295bcfb53d5ca779cec086d2ffff3fefc5f40a568eb3f9cb5e3d2",
+ "resources/js/pages/portal/services.tsx": "b3fd45983917e4bc2e1e1371f1696e1de526c02554bf0d2ff96d92ef8e1f6256",
+ "tests/Feature/BvmAdmissionGuideTest.php": "a33d39e29ec7ec89ec94cf14965914f36f65839fb8c6b63fd7093f7a9ad29f0e",
+ "tests/frontend/bvm-admission-guide.test.mjs": "37c5d3219cdadaa3877530d8aff70243200aba241ad539491399cde535309729"
+ },
+ "logs_sha256": {
+ "bvm-admission-final-feature-20261103.log": "4ba728022e4765e821d1c2ee95dfe0be735863edafcdf4f37501a2435a068f36",
+ "bvm-admission-frontend-20261103.log": "555611a27a76e023fc27e885024c4b74f2c7efa5607cb4fb38f308aee5bf9a87",
+ "bvm-admission-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "bvm-admission-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "bvm-admission-check-20261103.log": "5ad845abe612c6ae4753523d8361daf5e6afa1948f8f3a6654334e046b3182e2",
+ "bvm-admission-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "bvm-admission-final-build-20261103.log": "799e84fde3e292e3cf019485b503a8134e294ed90252818ea699d7823585b162",
+ "bvm-admission-qa-preservation-20261103.json": "9d96d8fb34d00ec2300c1c958d681eb3f23bd3c43172e98a2d865a76bdf86f1a",
+ "bvm-source-extract-final-20261103.log": "921c6d7b68a9a5ba2faf75c3b8f017c513681f2bf33947e0afad21bfd4424e73"
+ },
+ "limitations": [
+ "annual admission amounts for current period not recovered; historical2024 valid only until2025-03-31",
+ "current fees and complete2025 CVM operational procedures pending",
+ "special securities/foreign cases and subsequent amendments not fully encoded",
+ "source PDF visual inspection is not real browser/login/visual acceptance",
+ "destination installation pending",
+ "no new two-process concurrency proof"
+ ],
+ "active_writes": 0,
+ "new_migrations": 0,
+ "external_messages": 0,
+ "new_public_library_imports": 0
+ },
+ "product_usage_metrics_increment_20261103": {
+ "recorded_at": "2026-11-02T22:54:41.063Z",
+ "requirement": "MASTER-e1169a77-0018",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 24,
+ "passed": 24,
+ "assertions": 338,
+ "duration_ms": 202078
+ },
+ "new_feature_cases": 7,
+ "frontend_tests": 11,
+ "new_frontend_cases": 3,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "product_usage_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "desk_cases": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_requests": 0,
+ "desk_events": 0
+ },
+ "row_visibility": [
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "read_consistency": "repeatable_read",
+ "observed_queries": 12,
+ "transaction_settings": [
+ [
+ "on",
+ "repeatable read"
+ ]
+ ],
+ "report_fingerprint": "a105c7bc4d71adcbaa90b0521b03ea561a0b33d0bbf414002a2f6ec37dc0eaeb",
+ "active_writes": 0
+ },
+ "source": {
+ "sha256": "e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e",
+ "paragraph": 420
+ },
+ "code_sha256": {
+ "config/product-metrics.php": "cee90bc391ad60e41c07897d794cdd79fd49cc94215f9fcfa920f9cec660a795",
+ "app/Services/ProductUsageMetrics.php": "4a1b69bdfe36219d8e18d7eacf4b6d77d52d52195e188fae9035eec77eea03e1",
+ "app/Services/VirtualDesk.php": "ee81e008cd7e4aa740923a24c296b04ce766632c8ce87b3c83fa46eb5bae71df",
+ "app/Http/Controllers/ProductUsageMetricsController.php": "bf591734493b64b6550a5f72b2230e054504f36accc607ddbb869aec7dcb5e4e",
+ "app/Http/Controllers/VirtualDeskController.php": "9aacdc9a64aea507c30cb655f7cbeb944d9b8ed4434cca38f8612246bcb0fa5f",
+ "routes/web.php": "46765be50d433c32660199e178bcecc82f928f42a08e50986350e8d358a05d92",
+ "resources/js/lib/product-usage.ts": "30fbcceb593cda1ffa13b584e7922652875a00ae06b400e0ae95d9fcc14c9dc8",
+ "resources/js/pages/management/product-usage.tsx": "d67f4b1df028bca6fe8e39a8910c011706bf9cb1acbb84616c83f87579b380b7",
+ "resources/js/pages/desk/request.tsx": "4de290f6174d711799461319aa799edb8b042941afc243a3ac1d1d05c1f94cd7",
+ "resources/js/pages/dashboard.tsx": "9252150706a11a2192cf410c1c7c94be44325d1275668a0bae8011dd584929f4",
+ "tests/Feature/ProductUsageMetricsTest.php": "7354d31268363f3da8b4ccb6aab1a4cd70f65a9a831061a8aa2c7a36e796d083",
+ "tests/frontend/product-usage.test.mjs": "d885cdf6663f8ece6f2fe24485ff6cf1a89765a422c5a5f99d6d61eef6375555",
+ "tests/frontend/desk-request-conditions.test.mjs": "03a4061815a3e3150a36538fa2380938230cee9e710e5c4476743faf117cbd80"
+ },
+ "logs_sha256": {
+ "product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78"
+ },
+ "active_writes": 0,
+ "new_migrations": 0,
+ "new_visitor_tracking": 0,
+ "external_messages": 0,
+ "limitations": [
+ "remaining product indicators and experiment registry not implemented",
+ "AUD-HUMAN-03 weights/baseline/pilots not defined; no success score invented",
+ "metrics over operational snapshot and verifiable-history subset, not a full visitor funnel or unique people",
+ "real browser/login/visual acceptance and destination installation pending",
+ "no new two-process concurrency proof"
+ ]
+ },
+ "product_experiments_increment_20261103": {
+ "recorded_at": "2026-11-02T23:25:51.791Z",
+ "requirement": "MASTER-e1169a77-0018",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 18,
+ "passed": 18,
+ "assertions": 271,
+ "duration_ms": 55557
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 7,
+ "new_frontend_cases": 5,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "product_experiments_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_events": 0,
+ "interest_requests": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "experiment_audit_events": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "current_revision_constraint": {
+ "condeferrable": true,
+ "condeferred": true,
+ "definition": "FOREIGN KEY (id, version) REFERENCES product_experiment_revisions(experiment_id, version) DEFERRABLE INITIALLY DEFERRED"
+ },
+ "triggers": [
+ {
+ "tgname": "product_experiment_revisions_immutable",
+ "tgenabled": "O",
+ "definition": "CREATE TRIGGER product_experiment_revisions_immutable BEFORE DELETE OR UPDATE OR TRUNCATE ON public.product_experiment_revisions FOR EACH STATEMENT EXECUTE FUNCTION product_experiment_reject_history_change()"
+ },
+ {
+ "tgname": "product_experiments_preserve",
+ "tgenabled": "O",
+ "definition": "CREATE TRIGGER product_experiments_preserve BEFORE DELETE OR TRUNCATE ON public.product_experiments FOR EACH STATEMENT EXECUTE FUNCTION product_experiment_reject_history_change()"
+ },
+ {
+ "tgname": "product_experiments_revision_advance",
+ "tgenabled": "O",
+ "definition": "CREATE TRIGGER product_experiments_revision_advance BEFORE UPDATE ON public.product_experiments FOR EACH ROW EXECUTE FUNCTION product_experiment_require_revision_advance()"
+ }
+ ],
+ "active_writes": 0,
+ "active_migrations": 0
+ },
+ "source": {
+ "sha256": "e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e",
+ "paragraph": 420
+ },
+ "code_sha256": {
+ "config/product-experiments.php": "2d97d7f982c9c880af6667be8441d8f4375f03e433a859aa4344a58abea781b0",
+ "config/product-metrics.php": "e4b5ed5cf078589a382fff58907bda1c38b421758280975b4137f12aec4de926",
+ "database/migrations/2026_11_03_020000_create_product_experiments.php": "fc85caabce7d24ab74963d343c0b49ca8fa96c0abb8566668026a9cb503f0e20",
+ "app/Services/ProductExperiments.php": "de60c935b92895e70d512866002d1c3705207e09ff04362dcd5f7cc8e271d68c",
+ "app/Http/Controllers/ProductExperimentController.php": "ca422bbf440a684505205e6f9e8fe9e0d350d3df563fbe2c9998fc57118f4fb0",
+ "routes/web.php": "26b8b71f18c392df56d37d15685a8f3ea6f6c16c221d56f6c850359e51df5e06",
+ "resources/js/lib/product-experiments.ts": "5e208a94ecfb175c2c6eceafb761325232e417f74699bffe479c06693a0db46d",
+ "resources/js/lib/product-usage.ts": "55fc612454a4a96fe597a1ee17d2bfa7aebd407e171070d3fca430cf7577c10c",
+ "resources/js/pages/management/experiments/index.tsx": "56928d6875e2fe40aaee4e2d414ff7ec8bb6002cb8460183f46dd68accef1ffa",
+ "resources/js/pages/management/experiments/edit.tsx": "34f2feee483657289f81879702d4f57e5718c62d12f7159de2f78fde6bc7dda8",
+ "resources/js/pages/management/product-usage.tsx": "fd73a211d5ffd73230b7b17a3b6ebeaa19fa7ca50a4e9850426de3d5e13b9f6c",
+ "tests/Feature/ProductExperimentsTest.php": "95150e4461aa1cadeaaab1bb14f2e486b482ef3bd0b000f251b2f4fae9f12dc4",
+ "tests/frontend/product-experiments.test.mjs": "6bb2bbc500fe5a17d29b3e845c1b811d085dafd9623e0fd8ac26dc5b1b473b48"
+ },
+ "logs_sha256": {
+ "product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35"
+ },
+ "prior_product_usage_code_deltas": {
+ "config/product-metrics.php": {
+ "previous": "cee90bc391ad60e41c07897d794cdd79fd49cc94215f9fcfa920f9cec660a795",
+ "current": "e4b5ed5cf078589a382fff58907bda1c38b421758280975b4137f12aec4de926"
+ },
+ "routes/web.php": {
+ "previous": "46765be50d433c32660199e178bcecc82f928f42a08e50986350e8d358a05d92",
+ "current": "26b8b71f18c392df56d37d15685a8f3ea6f6c16c221d56f6c850359e51df5e06"
+ },
+ "resources/js/lib/product-usage.ts": {
+ "previous": "30fbcceb593cda1ffa13b584e7922652875a00ae06b400e0ae95d9fcc14c9dc8",
+ "current": "55fc612454a4a96fe597a1ee17d2bfa7aebd407e171070d3fca430cf7577c10c"
+ },
+ "resources/js/pages/management/product-usage.tsx": {
+ "previous": "d67f4b1df028bca6fe8e39a8910c011706bf9cb1acbb84616c83f87579b380b7",
+ "current": "fd73a211d5ffd73230b7b17a3b6ebeaa19fa7ca50a4e9850426de3d5e13b9f6c"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "new_visitor_tracking": 0,
+ "limitations": [
+ "manual registry; transversal editor/change integration, actual allocation/execution and per-arm event measurement pending",
+ "evidence references and arm results are human declarations; operational snapshot is context only",
+ "remaining product indicators incomplete; no invented success score/pilots",
+ "real browser/login visual acceptance and destination installation pending",
+ "no new two-process concurrency proof"
+ ]
+ },
+ "public_search_metrics_increment_20261103": {
+ "recorded_at": "2026-11-02T23:47:45.192Z",
+ "requirement": "MASTER-e1169a77-0018",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 32,
+ "passed": 32,
+ "assertions": 501,
+ "duration_ms": 56409
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 9,
+ "new_frontend_cases": 2,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "search_metrics_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_events": 0,
+ "interest_requests": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "product_search_counts": 0,
+ "product_search_definitions": 0
+ },
+ "row_visibility": [
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "definition_trigger": {
+ "tgenabled": "O",
+ "definition": "CREATE TRIGGER product_search_definitions_immutable BEFORE DELETE OR UPDATE OR TRUNCATE ON public.product_search_definitions FOR EACH STATEMENT EXECUTE FUNCTION product_search_preserve_definition()"
+ },
+ "active_writes": 0,
+ "active_migrations": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "database": "search_metrics_concurrency_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "worker_processes": 2,
+ "workers": [
+ {
+ "result": "finished",
+ "worker": "a",
+ "pid": 16164,
+ "started_at_epoch": 1793663101.713111,
+ "finished_at_epoch": 1793663103.590321,
+ "attempts": 100,
+ "empty_attempts": 50,
+ "first_transaction_hold_ms": 300,
+ "synthetic_clock": "2026-11-02T12:00:00.123456Z"
+ },
+ {
+ "result": "finished",
+ "worker": "b",
+ "pid": 26996,
+ "started_at_epoch": 1793663101.654157,
+ "finished_at_epoch": 1793663103.574901,
+ "attempts": 100,
+ "empty_attempts": 100,
+ "first_transaction_hold_ms": 300,
+ "synthetic_clock": "2026-11-02T12:00:00.123456Z"
+ }
+ ],
+ "overlap_seconds": 1.8617901802062988,
+ "rows": [
+ {
+ "day": "2026-11-02",
+ "channel": "opportunities_api",
+ "definition_version": "public-search-responses-2026-11-03-v1",
+ "responses": 200,
+ "zero_responses": 150,
+ "first_recorded_at": "2026-11-02 12:00:00.123456+00",
+ "last_recorded_at": "2026-11-02 12:00:00.123456+00"
+ }
+ ],
+ "definitions": [
+ {
+ "version": "public-search-responses-2026-11-03-v1",
+ "sha256": "7601109c6b008819030f7d775fe6ab55b338b2ca36a16952f28f0547345ab6d4"
+ }
+ ],
+ "expected_responses": 200,
+ "expected_zero_responses": 150,
+ "active_writes": 0,
+ "real_user_acceptance": false
+ },
+ "source": {
+ "sha256": "e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e",
+ "paragraph": 420
+ },
+ "code_sha256": {
+ "config/search-metrics.php": "0fead6254803180916c2fb3851e1551ccc1ff8a1a4d875592f258d8529382af5",
+ "config/product-metrics.php": "b71947c445a1c32c0236979a9e301e26240f1ae43ef508657de42eac60dc98db",
+ "database/migrations/2026_11_03_030000_create_product_search_counts.php": "4538fd1a259d42122e301fef8ccc4968dde1af9aa2ed61e4a9520812823c5676",
+ "app/Services/PublicSearchMetrics.php": "09730864ec8999abd994603987e8315e88db148dc871e9ec092384d5115162d9",
+ "app/Services/ProductUsageMetrics.php": "f78b6210e63bbaa64003e5cad29906847be81c194c2aa84748cfa081c6606235",
+ "app/Services/ProductExperiments.php": "530adc81a008442dbbd473b5b1d750daddd2bbb6979354b3e85de2f1c4a21e55",
+ "app/Http/Middleware/CollectPublicSearchMetrics.php": "673872c1290bd6dabf10c4ee601ea704396703780880223a0142d9c91eae3dfb",
+ "bootstrap/app.php": "0cda8ed3dd87befe8c6916503d35c6a8f99ec284fc242675322d78154eac3958",
+ "app/Http/Controllers/InvestmentDiscoveryController.php": "75192c4d10e4aeb9b6cd79394b8115fdf7f1e8577ce845f3a138a94d2a4eb944",
+ "app/Http/Controllers/Api/V1/OpportunityController.php": "15ebcfe75e0101e6434eac9272a92ced785a74185a0f4f10c2806fec2dff88c1",
+ "app/Http/Controllers/PublicBusinessOpportunityController.php": "b5d6cbdbb2031f50cb2ecd927247e4376661b72a71bd86b9bef382a41c868fd3",
+ "app/Http/Controllers/InvestmentPortfolioController.php": "ed07df8842d9ef559278f97faba4d5398747632ccad2312a736094f7d1762329",
+ "app/Http/Controllers/PortalServicesController.php": "ed7c88674862385bf8497a02c2455aa0a71e4e1fab39468ad2580fe27cfeef21",
+ "app/Http/Controllers/PartnershipExchangeController.php": "2ecd1981bda0909f2303d1985e81a6a359234f1dcbe3a1d728f848418c81ce81",
+ "app/Http/Controllers/LegacyContentController.php": "1af2a4e3b663b0bda3969c597ed1db4ce30b5c2e3a78d3d71a80f68cffc06bba",
+ "app/Http/Controllers/InvestmentZoneController.php": "38f6ddd37aff8fda7eccee48433ecccd3498793d49221e61c016022d6e6a58ca",
+ "resources/js/lib/product-usage.ts": "e60b3122d4840b56650c0340e955e67c40c0dd7d897e66b37b9fa103cc708078",
+ "resources/js/components/search-usage-report.tsx": "a153727ddf7382be9c012fe70da1a479fc84f2907a24c614f59487c287b6f417",
+ "resources/js/pages/management/product-usage.tsx": "1ae6e5376462ab2c90f2e223d080b5a286443ab7ae78d5b117cd07610ee5afca",
+ "resources/js/pages/portal/privacy-policy.tsx": "1099ed73ef697b53ae733c808ab89e6e353b425745728e330ae0d869c55c6a0a",
+ "tests/Feature/PublicSearchMetricsTest.php": "fda246c99c2c1ba74e2e0c398ba0362e29b094ecc7eff1045f559f118992ed51",
+ "tests/frontend/search-usage-report.test.mjs": "51603305c1186be60ce9e691f7c92f1ea4a97df54f92c0cfed193f0502733537",
+ "tests/frontend/product-usage.test.mjs": "bcb410dd43b1b0c9bacf020b6e18a9b12e74aae8813d3a334e5bc0203d61969a"
+ },
+ "logs_sha256": {
+ "search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e"
+ },
+ "prior_registry_code_deltas": {
+ "config/product-metrics.php": {
+ "previous": "e4b5ed5cf078589a382fff58907bda1c38b421758280975b4137f12aec4de926",
+ "current": "b71947c445a1c32c0236979a9e301e26240f1ae43ef508657de42eac60dc98db"
+ },
+ "app/Services/ProductExperiments.php": {
+ "previous": "de60c935b92895e70d512866002d1c3705207e09ff04362dcd5f7cc8e271d68c",
+ "current": "530adc81a008442dbbd473b5b1d750daddd2bbb6979354b3e85de2f1c4a21e55"
+ },
+ "resources/js/lib/product-usage.ts": {
+ "previous": "55fc612454a4a96fe597a1ee17d2bfa7aebd407e171070d3fca430cf7577c10c",
+ "current": "e60b3122d4840b56650c0340e955e67c40c0dd7d897e66b37b9fa103cc708078"
+ },
+ "resources/js/pages/management/product-usage.tsx": {
+ "previous": "fd73a211d5ffd73230b7b17a3b6ebeaa19fa7ca50a4e9850426de3d5e13b9f6c",
+ "current": "1ae6e5376462ab2c90f2e223d080b5a286443ab7ae78d5b117cd07610ee5afca"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "new_visitor_identifiers": 0,
+ "external_messages": 0,
+ "limitations": [
+ "recorded first-page HTTP responses only, not people, distinct queries or full portal usage",
+ "best-effort collection can omit responses; current UTC day partial and daily snapshot differs from event cutoff",
+ "other search sources, remaining product metrics and editor/variant execution integration pending",
+ "metrics do not prove causal impact, success score or investment",
+ "real browser/login visual acceptance and destination migration pending"
+ ]
+ },
+ "desk_typed_fields_increment_20261103": {
+ "recorded_at": "2026-11-03T00:06:47.529Z",
+ "requirement": "AUD-CHECKLIST-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 27,
+ "passed": 27,
+ "assertions": 347,
+ "duration_ms": 63601
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 13,
+ "new_frontend_cases": 6,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_with_existing_nonblocking_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "desk_typed_fields_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Services/DeskServiceEditor.php": "4454614b9999c87d2d103f282839ad236cac556493706f77d59032d19b6f637b",
+ "app/Services/VirtualDesk.php": "a4017b7049f8f52a3488955010d1130449f5ffb4e72146b6e296239a96e54092",
+ "resources/js/lib/desk-field-values.ts": "9c7aafad1a742ffce1653ccafde6c06f14bf2abeccc499aaf82e10b3f8c0f7db",
+ "resources/js/lib/desk-field-visibility.ts": "958d6d0978c5f1e6688c84307ab3a9aa482d49bf660ef0910da7d74d042d272f",
+ "resources/js/components/desk-typed-choice.tsx": "50deef44aa80b26a5322a7a8b9b51ecbab5306e8ff530882a2f114c2a586aa6e",
+ "resources/js/pages/desk/request.tsx": "d6f1e9f3f4ef199eaa721daf1f2a815e920bd8385f9a021571fcc42e84c180d4",
+ "resources/js/pages/desk/service-editor.tsx": "abfbea79d55b5f20fd715e610e21e7477149047747dff4c814404d556ba54c3b",
+ "resources/views/desk/receipt-answers.blade.php": "5709d275227a136f5b2d507bdabb0d54f0725603e14daacad848bc3b30c34ff2",
+ "resources/views/desk/receipt.blade.php": "5465691a49eea52f706b26979cdbec5129d0db4d882b02a1e6af2e8becdb3278",
+ "tests/Feature/DeskTypedFieldsTest.php": "8495ea46efe0e8d237dfa60738ab9477772e6ebc6d1dc4d19589878a8ff38a57",
+ "tests/frontend/desk-typed-fields.test.mjs": "5c153e414e38a40f4da32ac4f1ab0935ef603cde5ce3f3f642df9903ce614096",
+ "tests/frontend/desk-request-conditions.test.mjs": "1fb55c80d8d59e667999f8a6f827cee94e33a18adf660729f39a14a83cd7e7d3"
+ },
+ "logs_sha256": {
+ "desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-typed-fields-prior-receipt-20261103.json",
+ "sha256": "578801cd55008f544a518c64bc8287d4891de0457133322dbfc6bbd8d17dd8b7"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e"
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "other checklist consumers and p481 criteria remain partial",
+ "general obligations, registry/publicity and sector licensing mapping remain separate",
+ "explicit save; no claim of transversal autosave",
+ "real browser/login visual acceptance and destination availability pending",
+ "documentary choices do not grant additional authority or official consent validity"
+ ]
+ },
+ "desk_checkpoint_increment_20261103": {
+ "recorded_at": "2026-11-03T00:24:01.695Z",
+ "requirement": "AUD-CHECKLIST-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 38,
+ "passed": 38,
+ "assertions": 487,
+ "duration_ms": 84386
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 21,
+ "new_frontend_cases": 8,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_with_existing_nonblocking_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "desk_checkpoint_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "database": "desk_checkpoint_concurrency_20261103_test",
+ "port": 55441,
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 27980,
+ "database_pid": 16820,
+ "started": 1793665194.229728,
+ "finished": 1793665194.50295,
+ "outcome": "saved"
+ },
+ {
+ "mode": "b",
+ "pid": 28052,
+ "database_pid": 18336,
+ "started": 1793665194.236196,
+ "finished": 1793665194.524881,
+ "outcome": "conflict"
+ }
+ ],
+ "overlap_seconds": 0.2667539119720459,
+ "checkpoint_rows": 1,
+ "checkpoint_version": 1,
+ "audit_rows": 1,
+ "main_version": 1,
+ "main_unchanged": true,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Services/VirtualDesk.php": "b94aebec5d023634f951dc585c36def82f154b140d48b07d8dd1a36c3d6a4338",
+ "app/Services/DeskRequestCheckpoints.php": "853268e043a118f005313382bb1e786b65efeedcc15f7138e1052f876ec4763a",
+ "app/Http/Controllers/DeskRequestCheckpointController.php": "8b366844edcb686bd735aa7f91318460d32754286ef555d048267c0deb446a08",
+ "database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php": "8b56e42c04fa2f541beb649d94420dfd9936357a4adbf5298b4fa3453d5e822b",
+ "routes/virtual-desk.php": "bf52aa7a254fc0e30cf0423156726ee5bec3a456a7e10cee1067035cfd4eda1e",
+ "resources/js/lib/desk-checkpoints.ts": "1c654c04a46f383713ea6a63fec44976aa922d5b2148ba7e6326ae827ad7ca8c",
+ "resources/js/components/desk-draft-recovery.tsx": "85023ce9093d29ba5cfc72b87a7f3ca7dabb65922f326ead428401f81520d129",
+ "resources/js/pages/desk/request.tsx": "a528b34bf429755f57d888977e146267ffb64b79756e8c8305fcfacc31a1e72b",
+ "resources/js/pages/portal/privacy-policy.tsx": "767a98e5d32a01033e75c2d05dd1561c2463bff0ed707d0b156013de5d343d5a",
+ "tests/Feature/DeskRequestCheckpointTest.php": "6992661606c134342c576bb01fc5440577a2382a534f2ca62c8b3d21bd3b3cf8",
+ "tests/frontend/desk-checkpoints.test.mjs": "90a153ab7634beb253b7fc3229b322d8211ab3f621d9fe1de6f2545338f76c4b",
+ "tests/frontend/desk-request-conditions.test.mjs": "b4231f9003ac21a696fffc71a967ed3a3473d4952576d4002b1a2a57df36a1fb"
+ },
+ "logs_sha256": {
+ "desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-checkpoint-prior-receipt-20261103.json",
+ "sha256": "dfade4f813ac22ae5fa6ac7a029e2593d66423bb716e8f64ed1f4f0581143a42"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b"
+ },
+ "prior_code_deltas": {
+ "desk_typed_fields_increment_20261103": {
+ "app/Services/VirtualDesk.php": {
+ "previous": "a4017b7049f8f52a3488955010d1130449f5ffb4e72146b6e296239a96e54092",
+ "current": "b94aebec5d023634f951dc585c36def82f154b140d48b07d8dd1a36c3d6a4338"
+ },
+ "resources/js/pages/desk/request.tsx": {
+ "previous": "d6f1e9f3f4ef199eaa721daf1f2a815e920bd8385f9a021571fcc42e84c180d4",
+ "current": "a528b34bf429755f57d888977e146267ffb64b79756e8c8305fcfacc31a1e72b"
+ },
+ "tests/frontend/desk-request-conditions.test.mjs": {
+ "previous": "1fb55c80d8d59e667999f8a6f827cee94e33a18adf660729f39a14a83cd7e7d3",
+ "current": "b4231f9003ac21a696fffc71a967ed3a3473d4952576d4002b1a2a57df36a1fb"
+ }
+ },
+ "public_search_metrics_increment_20261103": {
+ "resources/js/pages/portal/privacy-policy.tsx": {
+ "previous": "1099ed73ef697b53ae733c808ab89e6e353b425745728e330ae0d869c55c6a0a",
+ "current": "767a98e5d32a01033e75c2d05dd1561c2463bff0ed707d0b156013de5d343d5a"
+ }
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Balcao autosave/recovery only; other checklist consumers remain partial",
+ "current per-actor encrypted recovery buffer, not keystroke history",
+ "unconfirmed edits can be lost on explicitly confirmed navigation; no persistent browser answer store",
+ "incomplete formats are recovery only, not accepted submissions",
+ "real browser/login visual acceptance and destination migration pending"
+ ]
+ },
+ "desk_attachment_fields_increment_20261103": {
+ "recorded_at": "2026-11-03T05:02:36.701Z",
+ "requirement": "AUD-CHECKLIST-01",
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 81,
+ "passed": 81,
+ "assertions": 1110,
+ "duration_ms": 184721
+ },
+ "final_focus": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 20,
+ "passed": 20,
+ "assertions": 251,
+ "duration_ms": 96612
+ },
+ "rounds_overlap": true,
+ "feature_scope": "81-case regression before final same-dossier picker delta; final 20-case attachment suite includes those cases plus picker/source/read-only checks; counts not summed",
+ "new_feature_cases": 20,
+ "frontend_tests": 38,
+ "new_frontend_cases": 8,
+ "checks": {
+ "phpstan": "passed",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_with_existing_nonblocking_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "desk_attachments_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "scope_indexes": [
+ {
+ "relname": "desk_documents_dossier_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_dossier_unique ON public.desk_documents USING btree (case_id, document_id) WHERE (request_id IS NULL)"
+ },
+ {
+ "relname": "desk_documents_scope_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_scope_unique ON public.desk_documents USING btree (case_id, document_id, request_id) WHERE (request_id IS NOT NULL)"
+ }
+ ],
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "database": "desk_attachment_concurrency_20261103_test",
+ "port": 55441,
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 9512,
+ "database_pid": 27860,
+ "started": 1793666805.235889,
+ "finished": 1793666805.609249,
+ "outcome": "saved"
+ },
+ {
+ "mode": "b",
+ "pid": 20144,
+ "database_pid": 28352,
+ "started": 1793666805.231678,
+ "finished": 1793666805.614379,
+ "outcome": "conflict"
+ }
+ ],
+ "overlap_seconds": 0.37336015701293945,
+ "documents": 1,
+ "links": 1,
+ "physical_files": 1,
+ "document_events": 1,
+ "case_version": 2,
+ "main_version": 1,
+ "main_unchanged": true,
+ "physical_sha256_verified": true,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "befc5d2b01333168535911e3ab1973eba7a57df49c0891c8bef35a6693cc048a",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "4f78840063b421fe57c6515a2af53f57a57cf4e59354f8a6f9897cc38a418bc2",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "6711a4e7ae7d86bcfa64ea7f2c22b136d52513e7046011839ce70913f7771783",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "92ea93fcfac5811492af925374b1bd2daca609efaedcc3ac08c2cb0870d4719d",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "9a95cbdf5b9fc082994ee8e736dfd33d4f67da6f2a84b0de096759bad544156a",
+ "resources/js/pages/desk/request.tsx": "a3293b819df6c19ef66bfa97c024bddc857ac10b544b243081e7c32d4ff8751a",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "de626dcc746a9722eb5d25c2e17499be5fbe435d3978191def4e1a7dc0dd5240",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "35d0f9bcb3a24107fe91e574ce00ff546db7edf63b7e4c5b7d4d375c21715819"
+ },
+ "logs_sha256": {
+ "desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-attachments-prior-receipt-20261103.json",
+ "sha256": "24a106af00b08e1560c6c2e9b7db90a2a3995de80ec138dd2d8ea20200a27a1b"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04"
+ },
+ "prior_checkpoint_code_deltas": {
+ "app/Services/VirtualDesk.php": {
+ "previous": "b94aebec5d023634f951dc585c36def82f154b140d48b07d8dd1a36c3d6a4338",
+ "current": "befc5d2b01333168535911e3ab1973eba7a57df49c0891c8bef35a6693cc048a"
+ },
+ "app/Services/DeskRequestCheckpoints.php": {
+ "previous": "853268e043a118f005313382bb1e786b65efeedcc15f7138e1052f876ec4763a",
+ "current": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829"
+ },
+ "resources/js/components/desk-draft-recovery.tsx": {
+ "previous": "85023ce9093d29ba5cfc72b87a7f3ca7dabb65922f326ead428401f81520d129",
+ "current": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17"
+ },
+ "resources/js/pages/desk/request.tsx": {
+ "previous": "a528b34bf429755f57d888977e146267ffb64b79756e8c8305fcfacc31a1e72b",
+ "current": "a3293b819df6c19ef66bfa97c024bddc857ac10b544b243081e7c32d4ff8751a"
+ },
+ "tests/frontend/desk-checkpoints.test.mjs": {
+ "previous": "90a153ab7634beb253b7fc3229b322d8211ab3f621d9fe1de6f2545338f76c4b",
+ "current": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509"
+ },
+ "tests/frontend/desk-request-conditions.test.mjs": {
+ "previous": "b4231f9003ac21a696fffc71a967ed3a3473d4952576d4002b1a2a57df36a1fb",
+ "current": "35d0f9bcb3a24107fe91e574ce00ff546db7edf63b7e4c5b7d4d375c21715819"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Balcao attachment questions only; other checklist consumers/limits/format/error configuration remain partial",
+ "four supported MIME and existing technical ceilings retained",
+ "new picker covers same-dossier authorised sources; general legacy/cross-dossier picker remains pending",
+ "file chosen locally but not sent is not a recoverable associated support",
+ "scan states in fixtures synthetic; existing scan pipeline reused, no new real ClamAV acceptance",
+ "real browser/login visual acceptance and destination migration pending"
+ ]
+ },
+ "desk_document_reuse_increment_20261103": {
+ "recorded_at": "2026-11-03T05:17:20.329Z",
+ "requirement": "AUD-CHECKLIST-01",
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 56,
+ "passed": 56,
+ "assertions": 766,
+ "duration_ms": 298170
+ },
+ "new_feature_cases": 8,
+ "frontend_tests": 40,
+ "new_frontend_cases": 10,
+ "qa": {
+ "result": "passed",
+ "database": "desk_document_reuse_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "scope_indexes": [
+ {
+ "relname": "desk_documents_dossier_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_dossier_unique ON public.desk_documents USING btree (case_id, document_id) WHERE (request_id IS NULL)"
+ },
+ {
+ "relname": "desk_documents_scope_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_scope_unique ON public.desk_documents USING btree (case_id, document_id, request_id) WHERE (request_id IS NOT NULL)"
+ }
+ ],
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_with_existing_nonblocking_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Http/Controllers/VirtualDeskController.php": "7565f62bc71d075c32452935d8f566f8d185fb6e807062c2dd86c1220cc983ba",
+ "app/Services/VirtualDesk.php": "ea6bc291ae3462a7d6868eea4f4fc48277f5fe555558fbe5024f0a1149ef186f",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "ba47c6303d4c04b1072c112ded963a133c3af0846ec3df47bcd0313dc6771392",
+ "resources/js/pages/desk/case.tsx": "5a2aa3dcaeee3713a3fe90dcef716157e8d0243cf367e8a2468d6323adaf0faf",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "63f07756cbb9bcd62f1729f0a513035c0609306fc473562ecf077b104b6b7d6d",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a"
+ },
+ "logs_sha256": {
+ "desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-document-reuse-prior-receipt-20261103.json",
+ "sha256": "edb0792dcf75100315ef97d388be00977bdabeb72f861ed34648b8fbc1c4997d"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5"
+ },
+ "prior_attachment_code_deltas": {
+ "app/Services/VirtualDesk.php": {
+ "previous": "befc5d2b01333168535911e3ab1973eba7a57df49c0891c8bef35a6693cc048a",
+ "current": "ea6bc291ae3462a7d6868eea4f4fc48277f5fe555558fbe5024f0a1149ef186f"
+ },
+ "app/Http/Controllers/VirtualDeskController.php": {
+ "previous": "4f78840063b421fe57c6515a2af53f57a57cf4e59354f8a6f9897cc38a418bc2",
+ "current": "7565f62bc71d075c32452935d8f566f8d185fb6e807062c2dd86c1220cc983ba"
+ },
+ "resources/js/components/desk-attachment-field.tsx": {
+ "previous": "92ea93fcfac5811492af925374b1bd2daca609efaedcc3ac08c2cb0870d4719d",
+ "current": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda"
+ },
+ "tests/frontend/desk-attachments.test.mjs": {
+ "previous": "de626dcc746a9722eb5d25c2e17499be5fbe435d3978191def4e1a7dc0dd5240",
+ "current": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Catalogue covers the existing reuse authority; no broader organizational-source grant",
+ "Other document consumers and transversal parameterization remain pending",
+ "No actual browser/login acceptance; component and HTTP proofs only",
+ "No real antimalware acceptance or active destination installation",
+ "Unsent local file selection is not durable recovery"
+ ]
+ },
+ "desk_payment_evidence_increment_20261103": {
+ "recorded_at": "2026-11-03T05:31:42.823Z",
+ "requirements": [
+ "AUD-DESK-01",
+ "AUD-DESK-02"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 53,
+ "passed": 53,
+ "assertions": 721,
+ "duration_ms": 302722
+ },
+ "new_feature_cases": 8,
+ "frontend_tests": 47,
+ "new_frontend_cases": 7,
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "desk_payment_evidence_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "scope_indexes": [
+ {
+ "relname": "desk_documents_dossier_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_dossier_unique ON public.desk_documents USING btree (case_id, document_id) WHERE (request_id IS NULL)"
+ },
+ {
+ "relname": "desk_documents_scope_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_scope_unique ON public.desk_documents USING btree (case_id, document_id, request_id) WHERE (request_id IS NOT NULL)"
+ }
+ ],
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "database": "desk_payment_race_20261103_test",
+ "port": 55441,
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 12260,
+ "database_pid": 26008,
+ "started": 1793683790.568018,
+ "finished": 1793683790.981541,
+ "outcome": "saved"
+ },
+ {
+ "mode": "b",
+ "pid": 28584,
+ "database_pid": 5692,
+ "started": 1793683790.589519,
+ "finished": 1793683790.995487,
+ "outcome": "conflict"
+ }
+ ],
+ "overlap_seconds": 0.39202189445495605,
+ "payments": 1,
+ "declaration_events": 1,
+ "amount": "25.50",
+ "status": "pending",
+ "main_requests_unchanged": true,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "app/Http/Controllers/VirtualDeskController.php": "399a49d9ea5c0fa347a9a5f79cf4e81367904812b272558a6fc2d38e56db23dd",
+ "routes/virtual-desk.php": "0f2d196e1b2ade036fe35aade92215aebd19015680b396e396b920fc49379533",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "ab06a97a9f6d16a4f718cb7e33ce89e0fee9b268b3eda940ee6a9b8ab5678cc4",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc"
+ },
+ "logs_sha256": {
+ "desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-payment-evidence-prior-receipt-20261103.json",
+ "sha256": "0eb9b273ebd43eb9a2d05a7edad8e0c981010819b22579abbebd1b6cb3959d8b"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575"
+ },
+ "prior_code_deltas": {
+ "desk_document_reuse_increment_20261103": {
+ "app/Http/Controllers/VirtualDeskController.php": {
+ "previous": "7565f62bc71d075c32452935d8f566f8d185fb6e807062c2dd86c1220cc983ba",
+ "current": "399a49d9ea5c0fa347a9a5f79cf4e81367904812b272558a6fc2d38e56db23dd"
+ },
+ "routes/virtual-desk.php": {
+ "previous": "ba47c6303d4c04b1072c112ded963a133c3af0846ec3df47bcd0313dc6771392",
+ "current": "0f2d196e1b2ade036fe35aade92215aebd19015680b396e396b920fc49379533"
+ }
+ },
+ "desk_attachment_fields_increment_20261103": {
+ "app/Http/Controllers/VirtualDeskController.php": {
+ "previous": "7565f62bc71d075c32452935d8f566f8d185fb6e807062c2dd86c1220cc983ba",
+ "current": "399a49d9ea5c0fa347a9a5f79cf4e81367904812b272558a6fc2d38e56db23dd"
+ },
+ "app/Http/Controllers/VirtualDeskOperationsController.php": {
+ "previous": "6711a4e7ae7d86bcfa64ea7f2c22b136d52513e7046011839ce70913f7771783",
+ "current": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a"
+ },
+ "resources/js/components/desk-internal-operations.tsx": {
+ "previous": "9a95cbdf5b9fc082994ee8e736dfd33d4f67da6f2a84b0de096759bad544156a",
+ "current": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77"
+ },
+ "resources/js/pages/desk/request.tsx": {
+ "previous": "a3293b819df6c19ef66bfa97c024bddc857ac10b544b243081e7c32d4ff8751a",
+ "current": "ab06a97a9f6d16a4f718cb7e33ce89e0fee9b268b3eda940ee6a9b8ab5678cc4"
+ },
+ "tests/frontend/desk-request-conditions.test.mjs": {
+ "previous": "35d0f9bcb3a24107fe91e574ce00ff546db7edf63b7e4c5b7d4d375c21715819",
+ "current": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc"
+ }
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Manual internal declaration/documentary check, no bank confirmation or actual transfer",
+ "No wider reconfiguration of financial facts or approval rules",
+ "Parallel proof covers shared reference declaration; complement CAS/idempotency proven sequentially over HTTP",
+ "Legacy association metadata not reconstructed",
+ "Visual/login real and destination delivery pending; other portal criteria remain partial"
+ ]
+ },
+ "desk_closed_lifecycle_increment_20261103": {
+ "recorded_at": "2026-11-03T06:02:30.323Z",
+ "requirements": [
+ "AUD-DESK-01",
+ "AUD-DESK-02",
+ "AUD-CRM-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "owner_decision": "The registered dossier owner executes close/reopen, as explicitly instructed on 2026-11-03; current access remains required",
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 77,
+ "passed": 77,
+ "assertions": 1016,
+ "duration_ms": 624622
+ },
+ "final_focus": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 15,
+ "passed": 15,
+ "assertions": 202,
+ "duration_ms": 82458
+ },
+ "rounds_overlap": true,
+ "regression_scope": "Before final unlinked-CRM dependency guard and owner-state API; final fifteen-case focus includes both; do not sum overlapping rounds",
+ "new_feature_cases": 15,
+ "frontend_tests": 64,
+ "new_frontend_cases": 12,
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "desk_closed_lifecycle_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "scope_indexes": [
+ {
+ "relname": "desk_documents_dossier_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_dossier_unique ON public.desk_documents USING btree (case_id, document_id) WHERE (request_id IS NULL)"
+ },
+ {
+ "relname": "desk_documents_scope_unique",
+ "indisvalid": true,
+ "indisready": true,
+ "definition": "CREATE UNIQUE INDEX desk_documents_scope_unique ON public.desk_documents USING btree (case_id, document_id, request_id) WHERE (request_id IS NOT NULL)"
+ }
+ ],
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "code_sha256": {
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Services/Ai/InvestorGuidance.php": "93ed191da4131b0f2931216ac66d0153b2f8888ba01586dece2ad69ff27b6f04",
+ "app/Http/Controllers/CrmController.php": "f389ae91baa0bcc452dd7683042fd52423845b83920180fbf7f1648a1371cb38",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "ee925ef7a210f65b6ec35db7baaf3a48fcec217153d27a1d9ebb5164196dd5db",
+ "resources/js/pages/crm/types.ts": "e9adcc202dc668f16a1e152c13444437868ace10f22eae9ea2b82a558a063fc8",
+ "tests/Feature/DeskClosedLifecycleTest.php": "402e7068c897e8411a5400a73abbc65d66e76303938f3be39818668c2ed5f026",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "73cfa960b62fff56ea92309d7b3a05974f8100d5f015784721cf7c82c5469a4a",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b"
+ },
+ "logs_sha256": {
+ "desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/desk-closed-lifecycle-prior-receipt-20261103.json",
+ "sha256": "70d586129d5206f8b29ccb2355f40759d8b71f6db4e0df6c99c590dcf810bd2a"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "ea6bc291ae3462a7d6868eea4f4fc48277f5fe555558fbe5024f0a1149ef186f",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "399a49d9ea5c0fa347a9a5f79cf4e81367904812b272558a6fc2d38e56db23dd",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "ab06a97a9f6d16a4f718cb7e33ce89e0fee9b268b3eda940ee6a9b8ab5678cc4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "0f2d196e1b2ade036fe35aade92215aebd19015680b396e396b920fc49379533",
+ "resources/js/pages/desk/case.tsx": "5a2aa3dcaeee3713a3fe90dcef716157e8d0243cf367e8a2468d6323adaf0faf",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "63f07756cbb9bcd62f1729f0a513035c0609306fc473562ecf077b104b6b7d6d",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e"
+ },
+ "prior_code_deltas": {
+ "app/Services/VirtualDesk.php": {
+ "previous": "ea6bc291ae3462a7d6868eea4f4fc48277f5fe555558fbe5024f0a1149ef186f",
+ "current": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec"
+ },
+ "app/Http/Controllers/VirtualDeskController.php": {
+ "previous": "399a49d9ea5c0fa347a9a5f79cf4e81367904812b272558a6fc2d38e56db23dd",
+ "current": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d"
+ },
+ "resources/js/pages/desk/request.tsx": {
+ "previous": "ab06a97a9f6d16a4f718cb7e33ce89e0fee9b268b3eda940ee6a9b8ab5678cc4",
+ "current": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4"
+ },
+ "routes/virtual-desk.php": {
+ "previous": "0f2d196e1b2ade036fe35aade92215aebd19015680b396e396b920fc49379533",
+ "current": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7"
+ },
+ "resources/js/pages/desk/case.tsx": {
+ "previous": "5a2aa3dcaeee3713a3fe90dcef716157e8d0243cf367e8a2468d6323adaf0faf",
+ "current": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b"
+ },
+ "tests/frontend/desk-document-picker.test.mjs": {
+ "previous": "63f07756cbb9bcd62f1729f0a513035c0609306fc473562ecf077b104b6b7d6d",
+ "current": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Owner close/reopen explicitly authorised and implemented; current access and child states preserved",
+ "Owner decision: registered dossier owner executes close/reopen; no role-based substitution inferred",
+ "Sequential HTTP and component/SSR proofs, no new parallel closure or browser acceptance claimed",
+ "Visual/login real and destination delivery pending",
+ "Other portal requirements and parameterization remain partial"
+ ]
+ },
+ "crm_record_versions_increment_20261103": {
+ "recorded_at": "2026-11-03T06:26:24.575Z",
+ "requirements": [
+ "AUD-CRM-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 45,
+ "passed": 45,
+ "assertions": 594,
+ "duration_ms": 118995
+ },
+ "frontend_tests": 75,
+ "new_feature_cases": 8,
+ "new_frontend_cases": 10,
+ "race": {
+ "result": "passed",
+ "database": "crm_record_race_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 23240,
+ "database_pid": 22488,
+ "started": 1793686977.000347,
+ "finished": 1793686977.061246,
+ "outcome": "saved",
+ "lock_wait_demonstrated": true
+ },
+ {
+ "mode": "b",
+ "pid": 16948,
+ "database_pid": 24128,
+ "started": 1793686976.993859,
+ "finished": 1793686977.074358,
+ "outcome": "version_conflict",
+ "lock_wait_demonstrated": false
+ }
+ ],
+ "saved": 1,
+ "version_conflict": 1,
+ "audit_events": 1,
+ "final_version": 2,
+ "sentinel_preserved": true,
+ "scope": "PortalAudit real concurrent PostgreSQL processes; HTTP middleware tested separately."
+ },
+ "qa": {
+ "result": "passed",
+ "database": "crm_record_versions_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "existing_revision_columns": [
+ {
+ "table_name": "contacts",
+ "data_type": "integer",
+ "is_nullable": "NO",
+ "column_default": "1"
+ },
+ {
+ "table_name": "investors",
+ "data_type": "integer",
+ "is_nullable": "NO",
+ "column_default": "1"
+ },
+ {
+ "table_name": "leads",
+ "data_type": "integer",
+ "is_nullable": "NO",
+ "column_default": "1"
+ },
+ {
+ "table_name": "tasks",
+ "data_type": "integer",
+ "is_nullable": "NO",
+ "column_default": "1"
+ }
+ ],
+ "existing_triggers": [
+ {
+ "table_name": "contacts",
+ "definition": "CREATE TRIGGER imz_contacts_updated BEFORE UPDATE ON public.contacts FOR EACH ROW EXECUTE FUNCTION investmoz_set_updated_at()"
+ },
+ {
+ "table_name": "investors",
+ "definition": "CREATE TRIGGER imz_investors_updated BEFORE UPDATE ON public.investors FOR EACH ROW EXECUTE FUNCTION investmoz_set_updated_at()"
+ },
+ {
+ "table_name": "leads",
+ "definition": "CREATE TRIGGER imz_leads_updated BEFORE UPDATE ON public.leads FOR EACH ROW EXECUTE FUNCTION investmoz_set_updated_at()"
+ },
+ {
+ "table_name": "tasks",
+ "definition": "CREATE TRIGGER imz_tasks_updated BEFORE UPDATE ON public.tasks FOR EACH ROW EXECUTE FUNCTION investmoz_set_updated_at()"
+ }
+ ],
+ "updated_at_function": {
+ "definition": "CREATE OR REPLACE FUNCTION public.investmoz_set_updated_at()\n RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO 'pg_catalog', 'public'\nAS $function$\nBEGIN\n NEW.updated_at = CURRENT_TIMESTAMP;\n RETURN NEW;\nEND;\n$function$\n"
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "app/Http/Controllers/CrmController.php": "513ca5611700d54b891140d6f502825d20bedef84ca436cbbf7bd1ceab9d7db4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "resources/js/pages/crm/lead.tsx": "a264d793cb8828e967928f4adc2b1d80b70d41e5b6b3f613615f7610a52bff0e",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-crm-record-versions-20261103.php": "5cad2f241324c9e336e3d51038f74781b37dd236affc864340bd28bce4026a6a",
+ "storage/app/private/check-crm-record-versions-qa-20261103.php": "75eb40ce4d11d81a00b131d5946d279e8b58d6d11b5cbfe2b629b855f2c8c3ca",
+ "storage/app/private/crm-record-race-env-20261103.php": "eb0c986a92d7e018f37e1e51527801c93fb9616d8132e7703865be80c35f13e2",
+ "storage/app/private/crm-record-race-migrate-20261103.php": "486e7166999d873b743a88ae3aac1df884f067cf74537aa5fc498898bbc91171",
+ "storage/app/private/crm-record-race-init-20261103.php": "18adf2107c780035dd66bccfeadba68b6c9e457bb198a03428490bd354d31b35",
+ "storage/app/private/crm-record-race-worker-20261103.php": "d7a0aaf98ecb3ec616cdc95cccbcd1d07b76449f3675dff032c4503921459187",
+ "storage/app/private/crm-record-race-verify-20261103.php": "55a2c59afff71e9348588a20f211989acd31913d8c76fa2b5560c2aee53b6c94"
+ },
+ "logs_sha256": {
+ "crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/crm-record-versions-feature-initial-20261103.log": "a16a57589a401d4a8d5dfeb9ab1b9af948eccce6e98a731f2305b2527e50e2f4",
+ "storage/app/private/crm-record-versions-types-initial-20261103.log": "54bca82bbc6183aabfb773aa2c4ef064c300af0f7695a77b1f332d885c10b2f6",
+ "storage/app/private/crm-record-race-migrate-20261103.log": "bc29cd0382c0a1ccadef7302675d91338d7712db05bc2f87a964c2277005b990"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/crm-record-versions-prior-receipt-20261103.json",
+ "sha256": "2903704a12e653e4a8db10630de46595da8725ff47ccac3a59ef900210ce414c"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "93ed191da4131b0f2931216ac66d0153b2f8888ba01586dece2ad69ff27b6f04",
+ "app/Http/Controllers/CrmController.php": "f389ae91baa0bcc452dd7683042fd52423845b83920180fbf7f1648a1371cb38",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "ee925ef7a210f65b6ec35db7baaf3a48fcec217153d27a1d9ebb5164196dd5db",
+ "resources/js/pages/crm/types.ts": "e9adcc202dc668f16a1e152c13444437868ace10f22eae9ea2b82a558a063fc8",
+ "tests/Feature/DeskClosedLifecycleTest.php": "402e7068c897e8411a5400a73abbc65d66e76303938f3be39818668c2ed5f026",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "73cfa960b62fff56ea92309d7b3a05974f8100d5f015784721cf7c82c5469a4a",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/CrmController.php": {
+ "previous": "f389ae91baa0bcc452dd7683042fd52423845b83920180fbf7f1648a1371cb38",
+ "current": "513ca5611700d54b891140d6f502825d20bedef84ca436cbbf7bd1ceab9d7db4"
+ },
+ "resources/js/pages/crm/lead.tsx": {
+ "previous": "ee925ef7a210f65b6ec35db7baaf3a48fcec217153d27a1d9ebb5164196dd5db",
+ "current": "a264d793cb8828e967928f4adc2b1d80b70d41e5b6b3f613615f7610a52bff0e"
+ },
+ "resources/js/pages/crm/types.ts": {
+ "previous": "e9adcc202dc668f16a1e152c13444437868ace10f22eae9ea2b82a558a063fc8",
+ "current": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6"
+ },
+ "tests/Feature/DeskClosedLifecycleTest.php": {
+ "previous": "402e7068c897e8411a5400a73abbc65d66e76303938f3be39818668c2ed5f026",
+ "current": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df"
+ },
+ "tests/frontend/desk-closed-lifecycle.test.mjs": {
+ "previous": "73cfa960b62fff56ea92309d7b3a05974f8100d5f015784721cf7c82c5469a4a",
+ "current": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Private edit PATCH requires version from coordinated frontend; old clients must refresh",
+ "Memory preservation during partial reload/errors, no browser-close draft recovery promised",
+ "CRM revision counter distinct from document/source editions; no new organisational permissions or MFA requirement",
+ "Concurrent service proof and HTTP tests distinct; visual/login real and active delivery pending",
+ "Existing owner-only closure/reopening and downstream states retained; CRM and portal remain partially covered"
+ ]
+ },
+ "dashboard_work_queue_increment_20261103": {
+ "recorded_at": "2026-11-03T06:47:46.516Z",
+ "requirements": [
+ "AUD-DASH-01",
+ "AUD-CRM-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 41,
+ "passed": 41,
+ "assertions": 694,
+ "duration_ms": 288232
+ },
+ "rounds_overlap": false,
+ "regression_scope": "Final forty-one cases include all eleven new queue scenarios, independent manager removal and synthetic transport fakes",
+ "new_feature_cases": 11,
+ "frontend_tests": 82,
+ "new_frontend_cases": 7,
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "dashboard_work_queue_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/DashboardWorkQueue.php": "c983022ac2a6ad5a2c63176549b50bff195696d57ec1a3e27e9cd19c69cde4b1",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "resources/js/pages/crm/lead.tsx": "5395e3c59454cf6682d04cf1034badc9d38b5c713ee82860bb72e9aa0a24b920",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-dashboard-work-queue-20261103.php": "a4173eb4d392453c48f12acc52498b1f4d61ea8c9be37957c5df64ffe58adf9a",
+ "storage/app/private/check-dashboard-work-queue-qa-20261103.php": "30364c9b5a9039d99f1411da3e076c95b45a0dfed9a54adb1eebfd4f69c3efb2"
+ },
+ "logs_sha256": {
+ "dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/dashboard-work-queue-feature-20261103.log": "f46e717b0892be1478c96fc62760a8b93cece1433324be54d67158fa2ed3bfa5",
+ "storage/app/private/dashboard-work-queue-feature-initial-20261103.log": "48c3db2b4ff94c0e65b139a96cf3f2b99a5569cdc88b6776cdf4d6c712e80ce8",
+ "storage/app/private/dashboard-work-queue-focus-20261103.log": "36422fec5e83947072c5c56f0316b4c5797781e67ccdd0c99529c53e5b563ce3",
+ "storage/app/private/dashboard-work-queue-phpstan-initial-20261103.log": "4939753e476550fd4a6753ac9b12c11e3adf8f0767afc05f14796cff7078e929"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/dashboard-work-queue-prior-receipt-20261103.json",
+ "sha256": "326fcb850d64c5fed1b2d25a6cc6a48ebf08592ff19db0ac82d2f3dad92b45b1"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "93ed191da4131b0f2931216ac66d0153b2f8888ba01586dece2ad69ff27b6f04",
+ "app/Http/Controllers/CrmController.php": "513ca5611700d54b891140d6f502825d20bedef84ca436cbbf7bd1ceab9d7db4",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "a264d793cb8828e967928f4adc2b1d80b70d41e5b6b3f613615f7610a52bff0e",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a"
+ },
+ "prior_code_deltas": {
+ "resources/js/pages/crm/lead.tsx": {
+ "previous": "a264d793cb8828e967928f4adc2b1d80b70d41e5b6b3f613615f7610a52bff0e",
+ "current": "5395e3c59454cf6682d04cf1034badc9d38b5c713ee82860bb72e9aa0a24b920"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Personal queue for three existing assignments, not all profile dashboards",
+ "Read dynamically; destination rechecks authority and state; no automatic decisions/notifications or new permissions",
+ "Counts remain separate; not unique investor/process counts",
+ "Browser visual/mobile/keyboard acceptance and active delivery pending",
+ "No new schema; owner-only closure/reopen and previous CRM concurrency retained"
+ ]
+ },
+ "crm_next_action_increment_20261103": {
+ "recorded_at": "2026-11-03T07:05:45.155Z",
+ "requirements": [
+ "AUD-CRM-01",
+ "AUD-DASH-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 75,
+ "passed": 75,
+ "assertions": 915,
+ "duration_ms": 339251
+ },
+ "final_focus": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 2,
+ "passed": 2,
+ "assertions": 42,
+ "duration_ms": 25126
+ },
+ "rounds_overlap": true,
+ "regression_scope": "Final two-case focus covers the typed quality subquery after the main regression; do not sum rounds",
+ "reproduction": {
+ "tests": 3,
+ "expected_before_fix": "302/302/200 instead of 422; accepted bug reproduction, not current failure"
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 87,
+ "new_frontend_cases": 5,
+ "race": {
+ "result": "passed",
+ "database": "crm_next_action_race_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "workers": [
+ {
+ "mode": "a",
+ "channel": "crm_controller",
+ "pid": 19280,
+ "database_pid": 27960,
+ "started": 1793689179.579149,
+ "finished": 1793689180.071067,
+ "outcome": "saved",
+ "lead_lock_wait_demonstrated": true
+ },
+ {
+ "mode": "b",
+ "channel": "investor_guidance",
+ "pid": 27500,
+ "database_pid": 25756,
+ "started": 1793689179.73836,
+ "finished": 1793689180.147708,
+ "outcome": "next_action_required",
+ "lead_lock_wait_demonstrated": false
+ }
+ ],
+ "saved": 1,
+ "next_action_required": 1,
+ "future_actions_remaining": 1,
+ "audit_events_added": 1,
+ "desk_events_added": 0,
+ "cases_preserved": true,
+ "lead_preserved": true,
+ "scope": "Two actual PostgreSQL processes through CRM controller and guidance service; HTTP middleware exercised separately."
+ },
+ "qa": {
+ "result": "passed",
+ "database": "crm_next_action_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed",
+ "types": "passed",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-crm-next-action-20261103.php": "809bce19480921bf78e007d95e98ff2b1c9ec29aa617c038e495b56cc6be5020",
+ "storage/app/private/check-crm-next-action-qa-20261103.php": "d3ca73cefe463af293ca71d6dd6252172c11acfc89afcac868016abb36404318",
+ "storage/app/private/crm-next-action-race-env-20261103.php": "6aa09df0285b3bbcd9b3254bfa4b106f87cde0633a316211f58ea4120ff008b9",
+ "storage/app/private/crm-next-action-race-init-20261103.php": "361acde854717f707aad3ef12fff5a9cad78926fc203bb3fa672aab30bd5d9fe",
+ "storage/app/private/crm-next-action-race-worker-20261103.php": "224885c37de5bd849348d152f005dc106d526677aed00c12bccc2f26ac5724f9",
+ "storage/app/private/crm-next-action-race-verify-20261103.php": "5139b185f50e0068527ffabd255328a61d5865f5f4b381c8059efa5c2447fd4d"
+ },
+ "logs_sha256": {
+ "crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/crm-next-action-phpstan-initial-20261103.log": "04cd5a71a08eebc9c25055c157a1ecef32685c1640ddc231fe2147e2734fe499"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/crm-next-action-prior-receipt-20261103.json",
+ "sha256": "60a236157990dec6ae6861ed7d812c9cbb1cc6a31ade6446ae7a91cdd617212c"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "93ed191da4131b0f2931216ac66d0153b2f8888ba01586dece2ad69ff27b6f04",
+ "app/Http/Controllers/CrmController.php": "513ca5611700d54b891140d6f502825d20bedef84ca436cbbf7bd1ceab9d7db4",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "5395e3c59454cf6682d04cf1034badc9d38b5c713ee82860bb72e9aa0a24b920",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "c983022ac2a6ad5a2c63176549b50bff195696d57ec1a3e27e9cd19c69cde4b1",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890"
+ },
+ "prior_code_deltas": {
+ "app/Services/Ai/InvestorGuidance.php": {
+ "previous": "93ed191da4131b0f2931216ac66d0153b2f8888ba01586dece2ad69ff27b6f04",
+ "current": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1"
+ },
+ "app/Http/Controllers/CrmController.php": {
+ "previous": "513ca5611700d54b891140d6f502825d20bedef84ca436cbbf7bd1ceab9d7db4",
+ "current": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd"
+ },
+ "resources/js/pages/crm/lead.tsx": {
+ "previous": "5395e3c59454cf6682d04cf1034badc9d38b5c713ee82860bb72e9aa0a24b920",
+ "current": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894"
+ },
+ "app/Services/DashboardWorkQueue.php": {
+ "previous": "c983022ac2a6ad5a2c63176549b50bff195696d57ec1a3e27e9cd19c69cde4b1",
+ "current": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Availability is derived from existing task/dossier states, not new permissions or universal workflow",
+ "Independent later owner closure or deadline expiry may leave no future task; no automatic replacement or close restriction introduced",
+ "Quality missing-action and future-action completion constraints retain distinct deadline meanings",
+ "Real two-process controller/service race and HTTP coverage do not establish browser acceptance",
+ "Other portal/CRM variants, visual verification and active delivery remain partial"
+ ]
+ },
+ "partnership_editing_increment_20261103": {
+ "recorded_at": "2026-11-03T08:07:00.367Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 19,
+ "passed": 19,
+ "assertions": 148,
+ "duration_ms": 39936
+ },
+ "new_feature_cases": 10,
+ "frontend_tests": 103,
+ "new_frontend_cases": 16,
+ "reproduction": {
+ "scenarios": 4,
+ "failed_assertions": 3,
+ "test_errors_from_missing_availability": 1,
+ "distinct_defects": 3,
+ "not_http_500": true
+ },
+ "race": {
+ "result": "passed",
+ "database": "partnership_editing_race_v2_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 8540,
+ "database_pid": 632,
+ "started": 1793692853.350352,
+ "finished": 1793692853.507727,
+ "id": 1,
+ "version": 2,
+ "status": "draft",
+ "availability": "SYNTHETIC November resources",
+ "lock_wait_demonstrated": true
+ },
+ {
+ "mode": "b",
+ "pid": 19148,
+ "database_pid": 28144,
+ "started": 1793692853.372405,
+ "finished": 1793692853.513017,
+ "id": 1,
+ "version": 2,
+ "status": "draft",
+ "availability": "SYNTHETIC November resources",
+ "lock_wait_demonstrated": false
+ }
+ ],
+ "records": 1,
+ "events": 1,
+ "audit_events": 1,
+ "notifications": 1,
+ "same_identity_and_version": true,
+ "availability_preserved": true,
+ "sector_inactive_after_first_commit": true,
+ "scope": "Two actual PostgreSQL service processes; HTTP authority/validation tested separately."
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_editing_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipExchange.php": "a161c079b12c29523b5479eaf0522db615002d7fa6c8ff29f7670c2a2c265efe",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "afcd70c2b234e8e12463ba6da821b41b254d8f64c66458b03d3d2b10ee6cd313",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-editing-20261103.php": "0d0f6577ad054567aa8b20d64c498c72d1731eb5fb05c5dc290e48bb1aadb60c",
+ "storage/app/private/check-partnership-editing-qa-20261103.php": "61419af2372943d658ba1e293989236522d8f054cd5c4741e1cd72542a7d63e4",
+ "storage/app/private/partnership-editing-race-v2-env-20261103.php": "198f3123391bca829221e79a5f1eef9ecb3625557f4e4a537049469a845e1aed",
+ "storage/app/private/partnership-editing-race-v2-init-20261103.php": "0ef092ca0253af738f9c7405693922720c0e565acfc3e5bfebb24176729459e9",
+ "storage/app/private/partnership-editing-race-v2-worker-20261103.php": "844723a0605dfcb9d04113215b895d075f4fcbcd064bdf95f40d533675c387bb",
+ "storage/app/private/partnership-editing-race-v2-verify-20261103.php": "3e155d432873b56fbd13608be439404a05dc2eae1ceef7ffd26f692b017bc463"
+ },
+ "logs_sha256": {
+ "partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-editing-types-initial-20261103.log": "0b5607cba8b8ad7c0b029e24987300bd97c7f137b2171686fb2dc8cc13906ab6",
+ "storage/app/private/partnership-editing-feature-final-20261103.log": "afceb0f7aae118197b1e8d5441418ea54cee3c99b63766a2b1fe288c487c6e96",
+ "storage/app/private/partnership-editing-feature-final2-20261103.log": "3fc0e4000ce06a7d5fae17c17140f51be7f27ae4f6d2c9162b20257433841788"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-editing-prior-receipt-20261103.json",
+ "sha256": "5dd5d3b239c54c45ce3bcbc29f249da11910baf020de713b3087c4e33fd81e89"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139"
+ },
+ "prior_code_deltas": {},
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Memory recovery and navigation warning do not promise recovery after browser close/reload/back or reauthentication",
+ "Events preserved are not full immutable text snapshots",
+ "Structural request validation still precedes creation replay; no universal future-schema compatibility claim",
+ "Existing authority and source gates unchanged; preserved reference is not new disclosure authority",
+ "Synthetic geographic fixture is not official imported geography or real publication",
+ "Component/HTTP/SQL proofs are not browser acceptance; other partnership variants and active delivery remain partial"
+ ]
+ },
+ "partnership_participants_increment_20261103": {
+ "recorded_at": "2026-11-03T08:17:40.835Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 25,
+ "passed": 25,
+ "assertions": 211,
+ "duration_ms": 78870
+ },
+ "new_feature_cases": 6,
+ "frontend_tests": 1413,
+ "new_frontend_cases": 6,
+ "frontend_scope": "All tests/frontend/*.test.mjs, real transpiled components; no browser acceptance",
+ "reproduction": {
+ "tests": 4,
+ "assertion_failures": 3,
+ "missing_property_test_errors": 1,
+ "http_responses_were_200": true
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_participants_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression_before_test_only_formatting",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipExchange.php": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44",
+ "app/Http/Controllers/PartnershipExchangeController.php": "224222a1240cb121eddded9fa279cbacc4d25cfb6b444356ba2c65b7d61c8430",
+ "resources/js/pages/partnerships/room.tsx": "de1a4f542bd88d03ac1a905f57e5a3722f559a761e947b65a4a6c8bb560a2577",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "7d29d4f91133dfc09be1cd658ac57cd8f669bbe71e70f3e29a69cc1295091c12"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-participants-20261103.php": "29cd00a4c27240f165218f5e2fe0b8b70f14ead1345fa708a322ec3968fc31ca",
+ "storage/app/private/check-partnership-participants-qa-20261103.php": "759c27e2bb2408000e0bfe04389e8f7d85dc99e17cf54531450041edf5878cab"
+ },
+ "logs_sha256": {
+ "partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-participants-reproduction-20261103.log": "42182a11056ecbf39a4c9b3e7d2826a2d898b93ea55dc7700653b3894b25490f"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-participants-prior-receipt-20261103.json",
+ "sha256": "90f1eb92267454d16c8ee12f94c09c3b47583db4945425aaef8d851dfb72dfcf"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "a161c079b12c29523b5479eaf0522db615002d7fa6c8ff29f7670c2a2c265efe",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "afcd70c2b234e8e12463ba6da821b41b254d8f64c66458b03d3d2b10ee6cd313",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "a161c079b12c29523b5479eaf0522db615002d7fa6c8ff29f7670c2a2c265efe",
+ "current": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Current account names are not immutable historical name snapshots",
+ "Selection never grants access and is rechecked by existing command authority",
+ "No new atomic guarantee for concurrent membership revocation beyond existing locks/checks",
+ "Room version remount and full recovery/comparison in agreement/interest/milestone forms remain separate work",
+ "Historical notification recipients are unchanged",
+ "Component/HTTP/SQL proofs are not browser acceptance; other variants and active delivery remain partial"
+ ]
+ },
+ "partnership_room_recovery_increment_20261103": {
+ "recorded_at": "2026-11-03T08:50:18.838Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 34,
+ "passed": 34,
+ "assertions": 310,
+ "duration_ms": 108454
+ },
+ "final_focus": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 2,
+ "passed": 2,
+ "assertions": 37,
+ "duration_ms": 29250
+ },
+ "rounds_overlap": true,
+ "regression_scope": "Final two-case focus verifies UUID case normalization after main regression; do not sum rounds",
+ "new_feature_cases": 9,
+ "frontend_tests": 1429,
+ "new_frontend_cases": 16,
+ "adapted_frontend_cases": 6,
+ "frontend_scope": "Broad full1429 followed by22 overlapping final room cases after contextual status-label correction; do not sum rounds; actual transpiled forms/hooks, not browser acceptance",
+ "race": {
+ "result": "passed",
+ "database": "partnership_room_recovery_race_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 6596,
+ "database_pid": 12240,
+ "started": 1793695102.512657,
+ "finished": 1793695103.40708,
+ "lock_wait_demonstrated": true,
+ "milestone": {
+ "saved": true,
+ "milestone_id": 13,
+ "version": 1,
+ "replayed": false
+ },
+ "upload": {
+ "uploaded": true,
+ "document_id": "097845ef-deac-4ee3-aa41-942a84c95109",
+ "replayed": false
+ },
+ "scan_dispatches": 1
+ },
+ {
+ "mode": "b",
+ "pid": 12744,
+ "database_pid": 27688,
+ "started": 1793695102.333281,
+ "finished": 1793695103.42712,
+ "lock_wait_demonstrated": false,
+ "milestone": {
+ "saved": true,
+ "milestone_id": 13,
+ "version": 1,
+ "replayed": true
+ },
+ "upload": {
+ "uploaded": true,
+ "document_id": "097845ef-deac-4ee3-aa41-942a84c95109",
+ "replayed": true
+ },
+ "scan_dispatches": 0
+ }
+ ],
+ "counts": {
+ "partnership_milestones": 1,
+ "partnership_documents": 1,
+ "documents": 1
+ },
+ "files": 1,
+ "events_added": 2,
+ "audit_events_added": 2,
+ "notifications_added": 2,
+ "bytes_preserved": true,
+ "scope": "Two actual PostgreSQL service processes; milestone lock contention demonstrated, followed by document replay; HTTP authority/validation/rollback covered separately."
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_room_recovery_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "app/Http/Controllers/PartnershipExchangeController.php": "0e6232cc722a0c6994fd25ddd166f9e75a0d6f2dddddc223ac4b46e6fb1848d9",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-room-recovery-20261103.php": "faab0073cd98d722972846a90c076243f5a7d87a7c6ca1b898dea973f18f9d95",
+ "storage/app/private/check-partnership-room-recovery-qa-20261103.php": "f5c03784f7806e4bcd43d9fdb14f787a1edf46dbac62eae69d76b929fb7692dc",
+ "storage/app/private/partnership-room-recovery-race-env-20261103.php": "ce6b8a3397e819f233a41e6ca89bb081e9fe2fb90d96a48c6de47866ce76b284",
+ "storage/app/private/partnership-room-recovery-race-init-20261103.php": "96dfdd48ce54d13aa94590464b1233c8166ed1d890ef6ca610e84e405f27b596",
+ "storage/app/private/partnership-room-recovery-race-worker-20261103.php": "45695bbf4a0daa0079a10a16064c81f67843c5b650e2328d1548a38f0e4cbdf2",
+ "storage/app/private/partnership-room-recovery-race-verify-20261103.php": "a3721c0fa5382fe69508e9b74ad95b1a1ac66a35f0f39b324f06cff64f0a9e1b"
+ },
+ "logs_sha256": {
+ "partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-room-recovery-types-initial-20261103.log": "bbca431216f4c9bc14f4c76df4c9195c5cd651b00020eff234a0948f966f60e7",
+ "storage/app/private/partnership-room-recovery-phpstan-initial-20261103.log": "e027d2b6ce3e1ca9b9772987d56105cb25816d0bf8ac62679e69b05de020b1fc",
+ "storage/app/private/partnership-room-recovery-frontend-focus-initial-20261103.log": "9d4bd2db1b9ee62d20892b3969ad7557443751c2908565343f30ecdaefe8ca1a",
+ "storage/app/private/partnership-room-recovery-format-final-20261103.log": "d6ff55ac612e663947803b54f0ad7b207990a596eeae188b429cc5ef30cfbf42",
+ "storage/app/private/partnership-room-recovery-pending-label-reproduction-full-20261103.log": "2ff27ee6350983b16d8679b0cd6487f8898cd08af26401030f497fce8422ca7e",
+ "storage/app/private/partnership-participants-before-room-recovery-20261103.mjs": "7d29d4f91133dfc09be1cd658ac57cd8f669bbe71e70f3e29a69cc1295091c12"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-room-recovery-prior-receipt-20261103.json",
+ "sha256": "57dbdfb87e9fd3e0e1b4cbe50d59d36758e9206578317d39c97f8f3a8f97b0f6"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "afcd70c2b234e8e12463ba6da821b41b254d8f64c66458b03d3d2b10ee6cd313",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "224222a1240cb121eddded9fa279cbacc4d25cfb6b444356ba2c65b7d61c8430",
+ "resources/js/pages/partnerships/room.tsx": "de1a4f542bd88d03ac1a905f57e5a3722f559a761e947b65a4a6c8bb560a2577",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "7d29d4f91133dfc09be1cd658ac57cd8f669bbe71e70f3e29a69cc1295091c12"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "224222a1240cb121eddded9fa279cbacc4d25cfb6b444356ba2c65b7d61c8430",
+ "current": "0e6232cc722a0c6994fd25ddd166f9e75a0d6f2dddddc223ac4b46e6fb1848d9"
+ },
+ "resources/js/pages/partnerships/room.tsx": {
+ "previous": "de1a4f542bd88d03ac1a905f57e5a3722f559a761e947b65a4a6c8bb560a2577",
+ "current": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41"
+ },
+ "tests/frontend/partnership-participants.test.mjs": {
+ "previous": "7d29d4f91133dfc09be1cd658ac57cd8f669bbe71e70f3e29a69cc1295091c12",
+ "current": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Memory preparation and leave warning do not promise recovery after browser close/reload/back or reauthentication",
+ "Legacy milestone/upload clients without a key remain compatible and are not promised idempotency",
+ "Historical notification recipients and full text snapshots are unchanged",
+ "No independent two-upload lock contention forced; real milestone contention followed by document replay",
+ "Fake scan dispatch is not execution of the antimalware worker; no new post-commit queue recovery mechanism",
+ "Component/HTTP/SQL proofs are not browser acceptance; candidatures, other variants and active delivery remain partial"
+ ],
+ "frontend_final_focus_tests": 22,
+ "frontend_rounds_overlap": true
+ },
+ "partnership_candidacies_increment_20261103": {
+ "recorded_at": "2026-11-03T09:34:54.325Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 47,
+ "passed": 47,
+ "assertions": 401,
+ "duration_ms": 135417
+ },
+ "new_feature_cases": 13,
+ "frontend_tests": 1451,
+ "new_frontend_cases": 22,
+ "reproduction": {
+ "tests": 4,
+ "assertion_failures": 4,
+ "details": "Omitted organization lost; wrong ID updated; per-candidacy can_edit absent; replay409 after an assessment"
+ },
+ "race": {
+ "result": "passed",
+ "database": "partnership_candidacies_race_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "workers": [
+ {
+ "mode": "a",
+ "pid": 14008,
+ "database_pid": 10348,
+ "started": 1793697864.047853,
+ "finished": 1793697864.264986,
+ "lock_wait_demonstrated": true,
+ "result": "submitted",
+ "version": 2,
+ "id": 39
+ },
+ {
+ "mode": "b",
+ "pid": 18460,
+ "database_pid": 23200,
+ "started": 1793697864.186159,
+ "finished": 1793697864.273204,
+ "lock_wait_demonstrated": false,
+ "result": "conflict",
+ "status": 409
+ }
+ ],
+ "interest_version": 2,
+ "revised_declarations_preserved": true,
+ "stale_evaluation_refused": true,
+ "previous_snapshot_preserved": true,
+ "events_added": 1,
+ "audit_events_added": 1,
+ "notifications_added": 2,
+ "replay_read_only": true,
+ "scope": "Two actual PostgreSQL processes; revised submission holds the parent lock and stale evaluation waits, then refuses without deadlock or overwriting the revised declaration."
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_candidacies_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "source_preservation": {
+ "result": "passed",
+ "database": "partnership_candidacies_20261103_test",
+ "port": 55441,
+ "tables": 45,
+ "unchanged_exchange_outside_interest_and_decide": true,
+ "line_endings_normalized_for_comparison": true
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "app/Services/PartnershipExchange.php": "c81c875e6ea3620e3024e794c69b2267030daaddb8b8c6ab93c5f6088ed4972e",
+ "app/Http/Controllers/PartnershipExchangeController.php": "15a88a99a6e54579f52fe1b342dd9f8416e40b162d8f6ecada6f4772eb157a15",
+ "resources/js/lib/partnership-candidacy-edit.ts": "bf363bef6f30b0e1e2bba9e685b79f7b5f6b7aff5e613e62eb030b0e6eea58df",
+ "resources/js/components/partnership-candidacies.tsx": "62f4ef96e9f597067541535a3aebd16a8d74cd806582a79c18976bcac4df0613",
+ "resources/js/pages/partnerships/detail.tsx": "3df1b06776409f8d6892a29ce2f3301377aed4de1334078c9eedad63f13dab03",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "256c5087f8d42867d3b1426ed1a535412ca802c05361041553f6bd05f70a7191",
+ "tests/frontend/partnership-candidacies.test.mjs": "f781dbea3e2e8461481eceaa9ff282d8b0df592017679201a61fe9681d2cd32c"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-candidacies-20261103.php": "e60c0c658f9a5ce241efdfcbb3779d65c4a4813bdd5cf9c6a4b267b99ce47fdc",
+ "storage/app/private/check-partnership-candidacies-qa-20261103.php": "e9f980afcdfbc096a2d906c0561c5f5a8d75be3a5b1884c28f3c9993b789340d",
+ "storage/app/private/prepare-partnership-candidacies-qa-20261103.cjs": "8b38ed40604e452c66c1a63cbf1a89351a8610a403a2a893d4d43dd289543224",
+ "storage/app/private/partnership-candidacies-race-env-20261103.php": "2a72cef13eea1aac68f2d74f9c604a61469ddb916380d658b8e1fdf01becf419",
+ "storage/app/private/partnership-candidacies-race-init-20261103.php": "9180d05d52a94b11d12dd908bed374e610f384b106d204b9d4aec64bc5e4b1c5",
+ "storage/app/private/partnership-candidacies-race-worker-20261103.php": "35abdc2113dfc4ebf6bea18884c523e256a7f11eb82988e2a56ec0ec568cd998",
+ "storage/app/private/partnership-candidacies-race-verify-20261103.php": "c7baefe23b232a2579ea13ee6a169c9a1929dcdcba7b96908670a298540ff445"
+ },
+ "logs_sha256": {
+ "partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-candidacies-feature-verified-20261103.log": "e6bc7493813d18f74ce9b1c5ad608eef07638b295b0a5bb1d0f4b8d4cb251ca5",
+ "storage/app/private/partnership-candidacies-frontend-focus-initial-20261103.log": "215ec4a1240e90cde49c9ee60c3676facbf3dba4c2ec531b22102886653bb65a",
+ "storage/app/private/partnership-candidacies-format-final-20261103.log": "0fd717296d9a776df60a1d9479078eea6e0bccfd9612c9efd2fd56c296f030e3",
+ "storage/app/private/partnership-exchange-before-candidacies-20261103.php": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44",
+ "storage/app/private/partnership-detail-before-candidacies-20261103.tsx": "b1b1b5afc81e80c643d7d62dee1019002d36348bb6531a65b04650db5304c908"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-candidacies-prior-receipt-20261103.json",
+ "sha256": "87783b29bd4e5ab5015e9bcadcdde568a4a2a7f1891c7659d3164e143c620238"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "afcd70c2b234e8e12463ba6da821b41b254d8f64c66458b03d3d2b10ee6cd313",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "0e6232cc722a0c6994fd25ddd166f9e75a0d6f2dddddc223ac4b46e6fb1848d9",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "eb6549f0e377bc0c72b6835982a1f25a8fb325b28ec9dfdc66996c10e5143f44",
+ "current": "c81c875e6ea3620e3024e794c69b2267030daaddb8b8c6ab93c5f6088ed4972e"
+ },
+ "resources/js/pages/partnerships/shared.tsx": {
+ "previous": "afcd70c2b234e8e12463ba6da821b41b254d8f64c66458b03d3d2b10ee6cd313",
+ "current": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5"
+ },
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "0e6232cc722a0c6994fd25ddd166f9e75a0d6f2dddddc223ac4b46e6fb1848d9",
+ "current": "15a88a99a6e54579f52fe1b342dd9f8416e40b162d8f6ecada6f4772eb157a15"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation is memory-only; no new promise after browser close/reload/navigation/reauthentication",
+ "Legacy requests without explicit identity/context/command keys retain their existing protocol and its limitations",
+ "Visibility of nonpublic proposal remains unchanged; native page may be unavailable after scope/publication change even when JSON replay recognizes an operation",
+ "New private audit snapshots do not reconstruct older missing versions or implement every history reader",
+ "Existing publication/moderation editor and historical notification recipients remain separate work",
+ "Synthetic controller/service/component proofs are not browser acceptance or active delivery"
+ ]
+ },
+ "partnership_history_increment_20261103": {
+ "recorded_at": "2026-11-03T09:59:32.926Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 57,
+ "passed": 57,
+ "assertions": 488,
+ "duration_ms": 244914
+ },
+ "new_feature_cases": 10,
+ "frontend_tests": 1460,
+ "new_frontend_cases": 9,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_history_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "app/Http/Controllers/PartnershipExchangeController.php": "19bf8191b6fe8bd81fca22f3cfd352a784c50038b0a162d44cb3008ce7472c2d",
+ "routes/partnerships.php": "79cefbc56e19ce026f2c131d2e4c8502a478e37cd6d0485502b43f7f6c5d6796",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "5c9d85cecbfb20862c350fa63a54b73547b99ad34bdd8addeec07422874221f6",
+ "resources/js/components/partnership-candidacies.tsx": "5c06b6b2f75e0187eb703c60337fd96e617e201e29cf3dda4a1207d93e044139",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-history-20261103.php": "e194bfbd49740ebcc1794e717d64dd2df3d66bdc5e92607dbb0d085b192030f2",
+ "storage/app/private/check-partnership-history-qa-20261103.php": "6ba290231991b66354677c033bb525dce91920f94c03182101c851cc503cdb5d"
+ },
+ "logs_sha256": {
+ "partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-history-prior-receipt-20261103.json",
+ "sha256": "107b0da9dffebe031348fd4dede8812c7fd4f242b9c9eceddf960c4073c2f98a"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "c81c875e6ea3620e3024e794c69b2267030daaddb8b8c6ab93c5f6088ed4972e",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "15a88a99a6e54579f52fe1b342dd9f8416e40b162d8f6ecada6f4772eb157a15",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "bf363bef6f30b0e1e2bba9e685b79f7b5f6b7aff5e613e62eb030b0e6eea58df",
+ "resources/js/components/partnership-candidacies.tsx": "62f4ef96e9f597067541535a3aebd16a8d74cd806582a79c18976bcac4df0613",
+ "resources/js/pages/partnerships/detail.tsx": "3df1b06776409f8d6892a29ce2f3301377aed4de1334078c9eedad63f13dab03",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "256c5087f8d42867d3b1426ed1a535412ca802c05361041553f6bd05f70a7191",
+ "tests/frontend/partnership-candidacies.test.mjs": "f781dbea3e2e8461481eceaa9ff282d8b0df592017679201a61fe9681d2cd32c"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "15a88a99a6e54579f52fe1b342dd9f8416e40b162d8f6ecada6f4772eb157a15",
+ "current": "19bf8191b6fe8bd81fca22f3cfd352a784c50038b0a162d44cb3008ce7472c2d"
+ },
+ "resources/js/components/partnership-candidacies.tsx": {
+ "previous": "62f4ef96e9f597067541535a3aebd16a8d74cd806582a79c18976bcac4df0613",
+ "current": "5c06b6b2f75e0187eb703c60337fd96e617e201e29cf3dda4a1207d93e044139"
+ },
+ "tests/frontend/partnership-candidacies.test.mjs": {
+ "previous": "f781dbea3e2e8461481eceaa9ff282d8b0df592017679201a61fe9681d2cd32c",
+ "current": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Older events remain partial; missing scope never becomes personal by inference",
+ "Actor/organization names and assessment criterion labels use current catalogue; frozen matching uses recorded labels",
+ "Historical ACL is reevaluated from current candidacy access and saved organization, without a new grant",
+ "No restore/reapply operation or browser acceptance; other publication/moderation, role and notification variants remain partial",
+ "Existing dashboard selects the current proposal title even after unpublication; historical notification recipient listing does not recheck representation. Reader-only nondisclosure proof does not close those consumers; concrete follow-up recorded."
+ ]
+ },
+ "partnership_dashboard_increment_20261103": {
+ "recorded_at": "2026-11-03T10:14:04.108Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 73,
+ "passed": 73,
+ "assertions": 576,
+ "duration_ms": 198874
+ },
+ "new_feature_cases": 16,
+ "frontend_tests": 1466,
+ "new_frontend_cases": 6,
+ "reproduction": {
+ "tests": 3,
+ "failed": 3,
+ "assertions": 6
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_dashboard_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "app/Services/PartnershipExchange.php": "1e238ea2150e4553241a9e3a79210be7c6fbccd36971d22c76799e3d04a12719",
+ "app/Http/Controllers/PartnershipExchangeController.php": "68c35d0c1f802c850928b327f07396ab6e84be9e137f3dd05bd0ea53b5e272e1",
+ "resources/js/pages/partnerships/dashboard.tsx": "845834257bd79fc71b1ddbc30afac3155504e31ff4b8600bac93721835b613e5",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-dashboard-20261103.php": "7d31338dcf21fe7ad778e170a751249c2c928756b977a4d0e3ac0b178ce43d1b",
+ "storage/app/private/check-partnership-dashboard-qa-20261103.php": "f5f2b5702c20dd3b393b52a3c2486846b29d26d78ffb732faba40df11a4d5973"
+ },
+ "logs_sha256": {
+ "partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-dashboard-focus-initial-20261103.log": "f83c05e9f9500cb238326d76e5b8f2b0346358a4e60db704f68ed85add808a2a",
+ "storage/app/private/partnership-dashboard-focus-expanded-20261103.log": "1893eeeea887b5b8ededfb7b2a5e382760bb6db71dd417ae83c67be28f68f662",
+ "storage/app/private/partnership-dashboard-frontend-focus-20261103.log": "268fe8cad1d3eb9e65851e23b4294f8c1c666aa07c5e6e3a3be473478f5af9b5",
+ "storage/app/private/partnership-dashboard-phpstan-initial-20261103.log": "6c7ced0bf5f0b17c78a57dc0c265adb782228f57ad36fbf26d7fde05b5f35919",
+ "storage/app/private/partnership-dashboard-phpstan-second-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-dashboard-prior-receipt-20261103.json",
+ "sha256": "6a58b1ff76206afa9e978b0fa0bea32f12008138f212c8dbf7f44912f2531813"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "c81c875e6ea3620e3024e794c69b2267030daaddb8b8c6ab93c5f6088ed4972e",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "19bf8191b6fe8bd81fca22f3cfd352a784c50038b0a162d44cb3008ce7472c2d",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "bf363bef6f30b0e1e2bba9e685b79f7b5f6b7aff5e613e62eb030b0e6eea58df",
+ "resources/js/components/partnership-candidacies.tsx": "5c06b6b2f75e0187eb703c60337fd96e617e201e29cf3dda4a1207d93e044139",
+ "resources/js/pages/partnerships/detail.tsx": "3df1b06776409f8d6892a29ce2f3301377aed4de1334078c9eedad63f13dab03",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "256c5087f8d42867d3b1426ed1a535412ca802c05361041553f6bd05f70a7191",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "79cefbc56e19ce026f2c131d2e4c8502a478e37cd6d0485502b43f7f6c5d6796",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "5c9d85cecbfb20862c350fa63a54b73547b99ad34bdd8addeec07422874221f6",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "c81c875e6ea3620e3024e794c69b2267030daaddb8b8c6ab93c5f6088ed4972e",
+ "current": "1e238ea2150e4553241a9e3a79210be7c6fbccd36971d22c76799e3d04a12719"
+ },
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "19bf8191b6fe8bd81fca22f3cfd352a784c50038b0a162d44cb3008ce7472c2d",
+ "current": "68c35d0c1f802c850928b327f07396ab6e84be9e137f3dd05bd0ea53b5e272e1"
+ },
+ "resources/js/pages/partnerships/dashboard.tsx": {
+ "previous": "5c9d85cecbfb20862c350fa63a54b73547b99ad34bdd8addeec07422874221f6",
+ "current": "845834257bd79fc71b1ddbc30afac3155504e31ff4b8600bac93721835b613e5"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Legacy notices without recorded historical scope remain retained but are not exposed or acknowledged by inference",
+ "New delivery follows existing operational representative roles, not a new subscription or automatic grant; read-only membership may read an already addressed notice",
+ "No retrospective redistribution or rewriting of prior event recipients",
+ "Controller/service/component tests are not browser acceptance, active installation or full module acceptance",
+ "Publication/moderation editor recovery, other role/consumer variants, deadlines and external channels remain separate work"
+ ]
+ },
+ "partnership_publication_increment_20261103": {
+ "recorded_at": "2026-11-03T10:30:40.725Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 85,
+ "passed": 85,
+ "assertions": 642,
+ "duration_ms": 214962
+ },
+ "new_feature_cases": 12,
+ "frontend_tests": 1482,
+ "new_frontend_cases": 16,
+ "reproduction": {
+ "tests": 3,
+ "failed": 3,
+ "assertions": 6
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_publication_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipPublication.php": "249e59c60f0bfaf724dc69443e1c7179a8fa2f02c8f8b734f5f4fbc16d042df8",
+ "app/Services/PartnershipExchange.php": "e8c637b35365a8b075203992da7d23541e9bdd60883d460e3f43727861d915ce",
+ "app/Http/Controllers/PartnershipExchangeController.php": "a8223f5f391f4727fd6a8b6a3f843d8258be94331232818bed09fcce9cbdfb6d",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "resources/js/pages/partnerships/detail.tsx": "36c21c898ebecd50502955c7e36a224c93525c918e1a12bcd736f5c9b4d2704b",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-publication-20261103.php": "29eca844de1915e0a6139b2ea654c0aaccc066d4b4652e73ec4105ca992224bd",
+ "storage/app/private/check-partnership-publication-qa-20261103.php": "e5330dd9a27c1d9d2d660bf899f7314f34b67b65043853287adfb396a6ade30d"
+ },
+ "logs_sha256": {
+ "partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-publication-focus-initial-20261103.log": "84daddb95b970afd2758f3a8045970975d32686e1524adb832906da0237bc185",
+ "storage/app/private/partnership-publication-focus-expanded-20261103.log": "a757f82a3fc52791b563415dc96845e13fd4208f0dbf325602b6d67dd5144554",
+ "storage/app/private/partnership-publication-frontend-focus-initial-20261103.log": "ccf789871da6ae3406c32a619d072e9e387db6828eeec528bb5606b88d7b922a",
+ "storage/app/private/partnership-publication-frontend-focus-final-20261103.log": "8679bc790e35107533460d26606447ade2979b0b19d0689693f5401fae7b2f77",
+ "storage/app/private/partnership-publication-frontend-expanded-20261103.log": "994517d9ebfe191352c62db8dcf3dadd16a41a22d7b3e017243274c63e8b1fa1",
+ "storage/app/private/partnership-publication-format-initial-20261103.log": "fa5a6f44db536cf3e86399d5c8b0370d7570ce82d76ff490688fe3132c8a7def"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-publication-prior-receipt-20261103.json",
+ "sha256": "c093dfe70fd32b8a334b2884d3e8d34ca3cbdf1ae51baaa3d7d3198c0be0e799"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1e238ea2150e4553241a9e3a79210be7c6fbccd36971d22c76799e3d04a12719",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "68c35d0c1f802c850928b327f07396ab6e84be9e137f3dd05bd0ea53b5e272e1",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "bf363bef6f30b0e1e2bba9e685b79f7b5f6b7aff5e613e62eb030b0e6eea58df",
+ "resources/js/components/partnership-candidacies.tsx": "5c06b6b2f75e0187eb703c60337fd96e617e201e29cf3dda4a1207d93e044139",
+ "resources/js/pages/partnerships/detail.tsx": "3df1b06776409f8d6892a29ce2f3301377aed4de1334078c9eedad63f13dab03",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "256c5087f8d42867d3b1426ed1a535412ca802c05361041553f6bd05f70a7191",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "79cefbc56e19ce026f2c131d2e4c8502a478e37cd6d0485502b43f7f6c5d6796",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "845834257bd79fc71b1ddbc30afac3155504e31ff4b8600bac93721835b613e5",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "1e238ea2150e4553241a9e3a79210be7c6fbccd36971d22c76799e3d04a12719",
+ "current": "e8c637b35365a8b075203992da7d23541e9bdd60883d460e3f43727861d915ce"
+ },
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "68c35d0c1f802c850928b327f07396ab6e84be9e137f3dd05bd0ea53b5e272e1",
+ "current": "a8223f5f391f4727fd6a8b6a3f843d8258be94331232818bed09fcce9cbdfb6d"
+ },
+ "resources/js/lib/partnership-candidacy-edit.ts": {
+ "previous": "bf363bef6f30b0e1e2bba9e685b79f7b5f6b7aff5e613e62eb030b0e6eea58df",
+ "current": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133"
+ },
+ "resources/js/components/partnership-candidacies.tsx": {
+ "previous": "5c06b6b2f75e0187eb703c60337fd96e617e201e29cf3dda4a1207d93e044139",
+ "current": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2"
+ },
+ "resources/js/pages/partnerships/detail.tsx": {
+ "previous": "3df1b06776409f8d6892a29ce2f3301377aed4de1334078c9eedad63f13dab03",
+ "current": "36c21c898ebecd50502955c7e36a224c93525c918e1a12bcd736f5c9b4d2704b"
+ },
+ "tests/frontend/helpers/partnership-candidacy.mjs": {
+ "previous": "256c5087f8d42867d3b1426ed1a535412ca802c05361041553f6bd05f70a7191",
+ "current": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Memory-only preparation; no browser-close/reload or reauthentication recovery guarantee",
+ "Legacy transitions without command keys retain their prior protocol and replay limits",
+ "Recorded publication snapshots do not reconstruct older versions or implement a full historical reader",
+ "Post-creation content-save recovery and other actor/consumer variants remain separate work",
+ "Synthetic service/component proofs are not browser acceptance, active delivery or full module acceptance"
+ ]
+ },
+ "partnership_versions_increment_20261103": {
+ "recorded_at": "2026-11-03T10:48:45.686Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 97,
+ "passed": 97,
+ "assertions": 739,
+ "duration_ms": 365374
+ },
+ "new_feature_cases": 12,
+ "frontend_tests": 1490,
+ "new_frontend_cases": 8,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_versions_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "app/Services/PartnershipExchange.php": "674a91fd2255ca0038bffb66a74e48253fa8d570eba962bbb300cacdf09e2b71",
+ "app/Http/Controllers/PartnershipExchangeController.php": "553dafed3da15915089cab08e6f8df7d99f99bba37fc8f63c66b6ddf6bcafcab",
+ "routes/partnerships.php": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-versions-20261103.php": "28700683a5cb7bbb94c42276691157df853ed14203d4ece250a2ead94eba81f7",
+ "storage/app/private/check-partnership-versions-qa-20261103.php": "8479b0d160e0a8da1a31bc79cc08e7212c61372c69f0cfcdfd5282d3a0cae2cc"
+ },
+ "logs_sha256": {
+ "partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-versions-feature-initial-20261103.log": "c1a72a41b32d4371a548a4c039518504ad35b67ac505b335e5007f7fa4fc43b0",
+ "storage/app/private/partnership-versions-frontend-focus-20261103.log": "59f6ac987bdf73b3a0014fa6522284848956d1d3ad36c2f44f9f9a637cf37585",
+ "storage/app/private/partnership-versions-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/partnership-versions-format-initial-20261103.log": "b2405128d9bf1b96c1a9f45ecf8b08e1b111ab27ad97a63b72074196be7f06b7"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-versions-prior-receipt-20261103.json",
+ "sha256": "1d8bce173dc954c7a599a5de686d04b4b6a3f2e679422b4f51ff038712d2af96"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "e8c637b35365a8b075203992da7d23541e9bdd60883d460e3f43727861d915ce",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "a8223f5f391f4727fd6a8b6a3f843d8258be94331232818bed09fcce9cbdfb6d",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "36c21c898ebecd50502955c7e36a224c93525c918e1a12bcd736f5c9b4d2704b",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "79cefbc56e19ce026f2c131d2e4c8502a478e37cd6d0485502b43f7f6c5d6796",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "845834257bd79fc71b1ddbc30afac3155504e31ff4b8600bac93721835b613e5",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "249e59c60f0bfaf724dc69443e1c7179a8fa2f02c8f8b734f5f4fbc16d042df8",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "e8c637b35365a8b075203992da7d23541e9bdd60883d460e3f43727861d915ce",
+ "current": "674a91fd2255ca0038bffb66a74e48253fa8d570eba962bbb300cacdf09e2b71"
+ },
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "a8223f5f391f4727fd6a8b6a3f843d8258be94331232818bed09fcce9cbdfb6d",
+ "current": "553dafed3da15915089cab08e6f8df7d99f99bba37fc8f63c66b6ddf6bcafcab"
+ },
+ "resources/js/pages/partnerships/detail.tsx": {
+ "previous": "36c21c898ebecd50502955c7e36a224c93525c918e1a12bcd736f5c9b4d2704b",
+ "current": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883"
+ },
+ "routes/partnerships.php": {
+ "previous": "79cefbc56e19ce026f2c131d2e4c8502a478e37cd6d0485502b43f7f6c5d6796",
+ "current": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1"
+ },
+ "resources/js/pages/partnerships/dashboard.tsx": {
+ "previous": "845834257bd79fc71b1ddbc30afac3155504e31ff4b8600bac93721835b613e5",
+ "current": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc"
+ },
+ "app/Services/PartnershipPublication.php": {
+ "previous": "249e59c60f0bfaf724dc69443e1c7179a8fa2f02c8f8b734f5f4fbc16d042df8",
+ "current": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Older events without full snapshots or historical scope remain partial; no reconstruction from current values",
+ "Moderator history reading reuses the existing global read gate and does not change decision independence",
+ "Historical origin/location identifiers do not grant current source access or official territorial validation",
+ "New creation/edit snapshots do not implement uncertain post-creation save replay",
+ "Other actor/consumer variants, metadata summary, browser acceptance and active delivery remain separate work"
+ ]
+ },
+ "partnership_draft_recovery_increment_20261103": {
+ "recorded_at": "2026-11-03T11:11:36.305Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 109,
+ "passed": 109,
+ "assertions": 802,
+ "duration_ms": 282546
+ },
+ "new_feature_cases": 12,
+ "frontend_tests": 1502,
+ "new_frontend_cases": 12,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_draft_recovery_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "app/Http/Controllers/PartnershipExchangeController.php": "5386c018e9f8ef940633b038ee81ff09d743d5ef55d8eaa80ad656f0671afb5f",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-draft-recovery-20261103.php": "2efa113db47626768d4fad53d1b9b335b49013a05baacd9ff6cd2a7749502df7",
+ "storage/app/private/check-partnership-draft-recovery-qa-20261103.php": "c024d48743f9a8a2cb898ba4b87fe1b2faccf330a3a6a7fbe703283eadbd83b2"
+ },
+ "logs_sha256": {
+ "partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-draft-recovery-frontend-reproduction-20261103.log": "b91fed381ecb6c9aaefd0332392e8a907d62229fe96518f1b15b9e863793c07b",
+ "storage/app/private/partnership-draft-recovery-feature-initial-20261103.log": "f8d0c37928c59aa6e3f368c2fbd646be49e2e0bff85e1c80b6a8c489bb260bc3",
+ "storage/app/private/partnership-draft-recovery-feature-expanded-20261103.log": "6cd95ce541cd4e0c7056d54a50dd1cb2d36b86956f0653dc4b53b6a0a5b61f35",
+ "storage/app/private/partnership-draft-recovery-frontend-initial-20261103.log": "fd016eac19671398bf11882b3743954ab3a33c8767cc3dcfaaef64723f9ef0bc",
+ "storage/app/private/partnership-draft-recovery-frontend-expanded-20261103.log": "6a6238a37a20a4cb8539485706d235577ed448a249b8a4b82dacb568f7d9b994",
+ "storage/app/private/partnership-draft-recovery-format-initial-20261103.log": "dc68a792a1844e54810c581e3309f41f5f873f7df0f48e89c37808d9b8e3b91e"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-draft-recovery-prior-receipt-20261103.json",
+ "sha256": "1ba1fed2af271c7347dd00ff84c19f119a0cb2c636dccd40fbc6e4e4dc548744"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "674a91fd2255ca0038bffb66a74e48253fa8d570eba962bbb300cacdf09e2b71",
+ "resources/js/lib/partnership-edit.ts": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "resources/js/components/partnership-edit-comparison.tsx": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "resources/js/pages/partnerships/editor.tsx": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "app/Http/Controllers/PartnershipExchangeController.php": "553dafed3da15915089cab08e6f8df7d99f99bba37fc8f63c66b6ddf6bcafcab",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d"
+ },
+ "prior_code_deltas": {
+ "app/Services/PartnershipExchange.php": {
+ "previous": "674a91fd2255ca0038bffb66a74e48253fa8d570eba962bbb300cacdf09e2b71",
+ "current": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89"
+ },
+ "resources/js/lib/partnership-edit.ts": {
+ "previous": "0b76fded4ee1ebfcf34d6fcb44028ec6514622f4c3cb5acbd99563964d78c5f1",
+ "current": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479"
+ },
+ "resources/js/components/partnership-edit-comparison.tsx": {
+ "previous": "12704eabea5393e305af0ba46202da5412c62e701a117d0eb4868b53bfc7ce4b",
+ "current": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1"
+ },
+ "resources/js/pages/partnerships/editor.tsx": {
+ "previous": "1cea1cb870506b56fe8e6ae913e5cb6f7dd904b3247057656389ceea2c765760",
+ "current": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62"
+ },
+ "tests/frontend/partnership-editing.test.mjs": {
+ "previous": "037d6157fe5a3c60d00bf1c798febd2becfd55bbdab4e8c60cade7feedbac541",
+ "current": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10"
+ },
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "553dafed3da15915089cab08e6f8df7d99f99bba37fc8f63c66b6ddf6bcafcab",
+ "current": "5386c018e9f8ef940633b038ee81ff09d743d5ef55d8eaa80ad656f0671afb5f"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation remains memory-only across browser closure, reload or reauthentication",
+ "Legacy updates without operation keys retain version conflict semantics, not identifiable replay",
+ "Current authority is always required; a revoked actor cannot recover by a previously known nonce",
+ "Snapshot and command metadata do not grant source access or alter decisions after the saved revision",
+ "Other role/consumer variants, metadata summary, browser acceptance and active delivery remain separate work"
+ ]
+ },
+ "partnership_agreements_increment_20261103": {
+ "recorded_at": "2026-11-03T11:52:38.755Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 121,
+ "passed": 121,
+ "assertions": 905,
+ "duration_ms": 222723
+ },
+ "document_scan": {
+ "tests": 1,
+ "assertions": 96,
+ "errors": 0,
+ "failures": 0,
+ "skipped": 0
+ },
+ "new_feature_cases": 12,
+ "frontend_tests": 1514,
+ "new_frontend_cases": 12,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_agreements_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "app/Http/Controllers/PartnershipExchangeController.php": "6e3f2b58fee93b223acfca209939a6c38a9844ad1ace58e27c2c810acdcf8e03",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "resources/js/pages/partnerships/room.tsx": "78fe41428010d28fb348ac7e68dd703e550738e8842b182b84e18687a1c47ef2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "tests/frontend/helpers/partnership-room.mjs": "b9d7bb17a030b9c4f3fc5df8bdf38006d475833c47de6d5653be7f34e6401ce6",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-agreements-20261103.php": "71ef8326f6e9a095672f24fce8f5263d3ff5b32d6b4ffd171d5a45cfaabb6396",
+ "storage/app/private/run-partnership-agreements-documents-20261103.php": "4a447de720464f872524038accee084ddc5f775dbf6ea0c45a409f23b2934d15",
+ "storage/app/private/check-partnership-agreements-qa-20261103.php": "fb1749791275573738607cfd2ed692203ea16cb3e83030b3009c88b40af57342"
+ },
+ "logs_sha256": {
+ "partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-agreements-feature-initial-20261103.log": "ea2f7b9c1a0e3d5141f429a54fca2c0dace49c731784925dfc7ff93729292f01",
+ "storage/app/private/partnership-agreements-feature-wired-20261103.log": "5e211773cb6d543d7f2bf07b0a63eb3ff7369bc07e98440481ff1c1c3d88417d",
+ "storage/app/private/partnership-agreements-feature-expanded-20261103.log": "babe54e1c3958c0aa513f8c99238fadc23304683e7fad3bdcb778111b53e700f",
+ "storage/app/private/partnership-agreements-frontend-initial-20261103.log": "800b547421dbd3f224ecdbe96c6b23eec2d18cb594b1a019948ad13531dcda33",
+ "storage/app/private/partnership-agreements-frontend-second-20261103.log": "71cdbfd6bd37f7a935424c02a48648a10a3bba85094732843a55ac0045c74974",
+ "storage/app/private/partnership-agreements-frontend-expanded-20261103.log": "84ba224a05d73afb3b4ebd831287c9fcb81084410431d75537a74d0da02bb230",
+ "storage/app/private/partnership-agreements-types-initial-20261103.log": "cdc2e5b4b99a941848759eb008bf00b791bd6086bd85a4254bd9ab74889dba57",
+ "storage/app/private/partnership-agreements-format-final-20261103.log": "51695425b2b8e366683e17f9a42a4c6e4ba70bc2ec957dbaa19fc91b60b89a69",
+ "storage/app/private/partnership-agreements-feature-final-20261103.log": "71f1b7bd541d387f47ef4de70b87cf8a57f478575e3c78c110c60b564834d602"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-agreements-prior-receipt-20261103.json",
+ "sha256": "8051777694cf5b8a8ca8017cdb5f56862543f0955334543848f8c1a0e60284c8"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "5386c018e9f8ef940633b038ee81ff09d743d5ef55d8eaa80ad656f0671afb5f",
+ "resources/js/pages/partnerships/room.tsx": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "tests/frontend/partnership-room-recovery.test.mjs": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "5386c018e9f8ef940633b038ee81ff09d743d5ef55d8eaa80ad656f0671afb5f",
+ "current": "6e3f2b58fee93b223acfca209939a6c38a9844ad1ace58e27c2c810acdcf8e03"
+ },
+ "resources/js/pages/partnerships/room.tsx": {
+ "previous": "032ae8377d91069649e6b1a4875c55d288eb460bedd5826063aba25c53277a41",
+ "current": "78fe41428010d28fb348ac7e68dd703e550738e8842b182b84e18687a1c47ef2"
+ },
+ "resources/js/lib/partnership-room-edit.ts": {
+ "previous": "ec585d533fffc5ec9e72bc42515156d995bacb16a2df967632eeb187b7a17bae",
+ "current": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca"
+ },
+ "resources/js/components/partnership-room-comparison.tsx": {
+ "previous": "81a35f68ab08d6629bb1c204de335e7268164881f31af784c88c83f88a53049d",
+ "current": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e"
+ },
+ "tests/frontend/helpers/partnership-room.mjs": {
+ "previous": "8363adb0a828948ee8356dafe9eaaa7ac70f916a8a1f7298ab844361c611df65",
+ "current": "b9d7bb17a030b9c4f3fc5df8bdf38006d475833c47de6d5653be7f34e6401ce6"
+ },
+ "tests/frontend/partnership-room-recovery.test.mjs": {
+ "previous": "8075c211e52f6ff6ea27445c8571248250fb7a779d3289d302b321b7604e86d6",
+ "current": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation remains memory-only across browser closure, reload or reauthentication",
+ "Legacy clients without parent version tokens retain only their room-version context guard",
+ "Current authority is required even for replay; existing proponent-first party precedence is preserved",
+ "Internal bilateral confirmation leaves legal_signature_status not_verified",
+ "Agreement snapshots do not replace a scoped history reader; role variants, detail summary, browser acceptance and active delivery remain pending"
+ ]
+ },
+ "partnership_agreement_history_increment_20261103": {
+ "recorded_at": "2026-11-03T12:19:48.516Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 132,
+ "passed": 132,
+ "assertions": 1009,
+ "duration_ms": 717591
+ },
+ "new_feature_cases": 11,
+ "frontend_tests": 1525,
+ "new_frontend_cases": 11,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_agreement_history_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipAgreementHistory.php": "c944e65977911a7a4fe4ffb548e519450c90b4214d73b2d1233fb0dc372e324c",
+ "app/Http/Controllers/PartnershipExchangeController.php": "d344f6e9d788e61c9bcbab66faca6cea8954102022286505584718010ec22e59",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-agreement-history-20261103.php": "81238ef26bb3b5459979b1155a9321d3ef0b54b2cb9b68a4de5ffc2c6a427c5d",
+ "storage/app/private/check-partnership-agreement-history-qa-20261103.php": "282181b3e7e0e7bbd731361db42db842d13a97db58b2e8bd2ed54f20d869e819"
+ },
+ "logs_sha256": {
+ "partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-agreement-history-feature-initial-20261103.log": "16ef61b586bf658e4620d49a859bbc2d73bc82b934204d0361cea7202fe3f9c2",
+ "storage/app/private/partnership-agreement-history-frontend-initial-20261103.log": "c92b4d2ae7ee755de05c89ca23b413b41f7ceb626af22148cf8629b57de261b5",
+ "storage/app/private/partnership-agreement-history-frontend-expanded-20261103.log": "e2279d9cba9bc93fe1c55354b794d171d88e861b60f1de57013408ad563cac61",
+ "storage/app/private/partnership-agreement-history-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/app/private/partnership-agreement-history-format-final-20261103.log": "198df4841e2d5fc91578fefc2c6f2315167c9c5511c475d4c5475e2e438ae48e"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-agreement-history-prior-receipt-20261103.json",
+ "sha256": "91c264d55bc8c05e59b42e1e2b6240adf0deea6abd84de92fc04684b54d27888"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "6e3f2b58fee93b223acfca209939a6c38a9844ad1ace58e27c2c810acdcf8e03",
+ "resources/js/pages/partnerships/room.tsx": "78fe41428010d28fb348ac7e68dd703e550738e8842b182b84e18687a1c47ef2",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "b9d7bb17a030b9c4f3fc5df8bdf38006d475833c47de6d5653be7f34e6401ce6",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "6e3f2b58fee93b223acfca209939a6c38a9844ad1ace58e27c2c810acdcf8e03",
+ "current": "d344f6e9d788e61c9bcbab66faca6cea8954102022286505584718010ec22e59"
+ },
+ "resources/js/pages/partnerships/room.tsx": {
+ "previous": "78fe41428010d28fb348ac7e68dd703e550738e8842b182b84e18687a1c47ef2",
+ "current": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3"
+ },
+ "tests/frontend/helpers/partnership-room.mjs": {
+ "previous": "b9d7bb17a030b9c4f3fc5df8bdf38006d475833c47de6d5653be7f34e6401ce6",
+ "current": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac"
+ },
+ "routes/partnerships.php": {
+ "previous": "8e783817af0e5fd2d49becd3c26adc6a134fd812e04fc3abdb13efb7bb22e9a1",
+ "current": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation remains memory-only across browser closure, reload or reauthentication",
+ "Legacy events without snapshots or historical scopes are not reconstructed from current state",
+ "Current room authority and historical representation are required; moderation adds no private-room authority",
+ "Internal confirmation and history do not certify legal signatures",
+ "Other role/consumer variants, detail summary, browser acceptance and active delivery remain pending"
+ ]
+ },
+ "partnership_agreement_projection_increment_20261103": {
+ "recorded_at": "2026-11-03T12:32:18.847Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 141,
+ "passed": 141,
+ "assertions": 1146,
+ "duration_ms": 256536
+ },
+ "new_feature_cases": 9,
+ "frontend_validation": {
+ "current_focused": 39,
+ "full_reused_from": "partnership_agreement_history_increment_20261103",
+ "full_reused_tests": 1525,
+ "new_cases": 0,
+ "client_source_changes": 0
+ },
+ "build_validation": {
+ "reused_from": "partnership_agreement_history_increment_20261103",
+ "artifact_sha256": {
+ "public/build/manifest.json": "e2ece183952cc69d82951cfb31eda80a37e787a8616e1d8fbf2cb4b092d44dab",
+ "public/build/assets/room-B9Gz5mlQ.js": "463d584961fcb0d3d9985e663e5253f9ef2e2daead2316b6e2a76059d0cdc656",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/partnership-agreement-instrument-CCnuZNBy.js": "428f576c3f28fc665002ef48e6e3633fc09a93249fa347dc526bb6c1d65a866b",
+ "public/build/assets/shared-AVMnLN2h.js": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "public/build/assets/shared-CjcfdjBU.js": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "public/build/assets/shared-DcTJM_Z4.js": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/agreement-history-m6ws3VcA.js": "f18ec78fced719ed02f853c8b2ca3ed603a94bf0bf69db748ba1c38f51c95acd"
+ }
+ },
+ "qa": {
+ "result": "passed",
+ "database": "partnership_agreement_projection_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "client": "focused_passed_full_and_types_lint_build_reused_unchanged_sources"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "app/Http/Controllers/PartnershipExchangeController.php": "cf8861013e0020326f5c2b06d5e8f21dd28ef4bd01b952c4b97709e4053acacd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-agreement-projection-20261103.php": "c06db61df66f69bd48219b279c4cf30ceaadef0c4b681aacaeae46ebfe78a59a",
+ "storage/app/private/check-partnership-agreement-projection-qa-20261103.php": "c93d2d5b462c5f6ba5c5aee94730c7ea4c4778b29d0c19c56c6268680d1289b2"
+ },
+ "logs_sha256": {
+ "partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-agreement-projection-feature-initial-20261103.log": "143b831c7db0bf0c317dd450f690aabb8418d0627ecc237f9e19c93f399bb39a",
+ "storage/app/private/partnership-agreement-projection-pint-expanded-20261103.log": "bfea4e6dbeeca83ea0b366c6d3bd8a9164cc17e1b34386ce91b4c6674d2523cf",
+ "storage/app/private/partnership-agreement-projection-pint-fixed-20261103.log": "8f99db3bf6350173558442145b82a154739c5ea1e2cd45c5b52f65083658fb51"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-agreement-projection-prior-receipt-20261103.json",
+ "sha256": "871ec820ef1e4550f81938544bf2af7c1940d77913e5dd44089455adb0c1a612"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "d344f6e9d788e61c9bcbab66faca6cea8954102022286505584718010ec22e59",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "c944e65977911a7a4fe4ffb548e519450c90b4214d73b2d1233fb0dc372e324c",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "d344f6e9d788e61c9bcbab66faca6cea8954102022286505584718010ec22e59",
+ "current": "cf8861013e0020326f5c2b06d5e8f21dd28ef4bd01b952c4b97709e4053acacd"
+ },
+ "app/Services/PartnershipAgreementHistory.php": {
+ "previous": "c944e65977911a7a4fe4ffb548e519450c90b4214d73b2d1233fb0dc372e324c",
+ "current": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "No new full frontend/type/lint/build round; previous evidence is reused with unchanged client sources and checked compiled artifacts",
+ "Current room access continues to govern the current instrument; historical snapshots retain separate historical scope checks",
+ "Other workflows/consumers, detail summary, browser acceptance and active delivery remain pending",
+ "Preparation remains memory-only; historical content not captured is not fabricated"
+ ]
+ },
+ "partnership_publication_summary_increment_20261103": {
+ "recorded_at": "2026-11-03T13:11:29.300Z",
+ "requirements": [
+ "AUD-PART-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 149,
+ "passed": 149,
+ "assertions": 1247,
+ "duration_ms": 325561
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "083901bad36ea0d8f0efb9e22a7245f15579f7c3e0932f953630befac4189441",
+ "public/build/assets/detail-BT0Y4QFd.js": "b69e69ef108ada121514a810f8b3ebfb39c473242a3a31a0e0584a9f6640df7f",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/investment-complements-Cvv4XxIw.js": "937d121143009cbe9f0ca3cef73bdf09c7f0002e3538c2d15d566827922077f4",
+ "public/build/assets/app-DBMcKKWv.js": "c035bd91badad4bb75bcae83bc7e5bd5e272b21d9fa37f193a59bbf5ff918ce0",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/structure-geography-BEXuLtac.js": "4a07dcfc6dddab94d0c889f18591ce657c52ae05691287f3132fc75aa3ff7af7",
+ "public/build/assets/interactive-investment-map-E1X5J_3p.js": "000009095068e2f80b4b60abfffeb831f4e28310f74543a95cc0ad3bffb3bf4c",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "public/build/assets/shared-AVMnLN2h.js": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "public/build/assets/shared-CjcfdjBU.js": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "public/build/assets/shared-DcTJM_Z4.js": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/partnership-history-CfclSLAo.js": "4668cf773996dc3ac4444a5dc066e6486ab9759120203bdce4466c1579dd9c56",
+ "public/build/assets/publication-history-BDrB2ehn.js": "b860e0bbbbf41078590ed455d25ffd6ee4b56d858f9c08c7a51b7d672faf4ceb"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "e2ece183952cc69d82951cfb31eda80a37e787a8616e1d8fbf2cb4b092d44dab",
+ "current": "083901bad36ea0d8f0efb9e22a7245f15579f7c3e0932f953630befac4189441",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/room-B9Gz5mlQ.js": {
+ "previous": "463d584961fcb0d3d9985e663e5253f9ef2e2daead2316b6e2a76059d0cdc656",
+ "current": "463d584961fcb0d3d9985e663e5253f9ef2e2daead2316b6e2a76059d0cdc656",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/partnership-agreement-instrument-CCnuZNBy.js": {
+ "previous": "428f576c3f28fc665002ef48e6e3633fc09a93249fa347dc526bb6c1d65a866b",
+ "current": "428f576c3f28fc665002ef48e6e3633fc09a93249fa347dc526bb6c1d65a866b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-AVMnLN2h.js": {
+ "previous": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "current": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-CjcfdjBU.js": {
+ "previous": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "current": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-DcTJM_Z4.js": {
+ "previous": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "current": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/agreement-history-m6ws3VcA.js": {
+ "previous": "f18ec78fced719ed02f853c8b2ca3ed603a94bf0bf69db748ba1c38f51c95acd",
+ "current": "f18ec78fced719ed02f853c8b2ca3ed603a94bf0bf69db748ba1c38f51c95acd",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_feature_cases": 8,
+ "frontend_tests": 1533,
+ "new_frontend_cases": 8,
+ "qa": {
+ "result": "passed",
+ "database": "partnership_publication_summary_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "lint": "passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-partnership-publication-summary-20261103.php": "9fba8be109ed6ee152b95236912e42fe32c3f909f14e2d400fc6837e28791e3d",
+ "storage/app/private/check-partnership-publication-summary-qa-20261103.php": "a333bd52cf84af40096b90a78f7d6353bde4b5d45085a2d1085f261b9b1666da"
+ },
+ "logs_sha256": {
+ "partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/partnership-publication-summary-feature-initial-20261103.log": "e48db343b766c42c0da714d93f0f501746708bd5fb806d36110c12bae6f614c1",
+ "storage/app/private/partnership-publication-summary-frontend-initial-20261103.log": "49e0592dc85c1e1ed2730503d844744c1055cb238e2ea1548edee968a4cbeca8",
+ "storage/app/private/partnership-publication-summary-phpstan-initial-20261103.log": "f5584a7f2d1fe2012282ec4d7e6df7c537f7135e41dc1715951e7aec9b04866e",
+ "storage/app/private/partnership-publication-summary-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/app/private/partnership-publication-summary-format-final-20261103.log": "a04a5a90b1794c5ddeb99bf148efc7be7e8d6eb862c535efb19a2b0482994fb9",
+ "storage/app/private/partnership-publication-summary-feature-final-20261103.log": "53e3fe5371adb826360b19af29f8b689b36d232e4cea5c23103ad55196f6946a",
+ "storage/app/private/partnership-publication-summary-pint-verified-20261103.log": "4a66876bbbe9629c27e068056e7c0e12c71aa3d14eb7c8a25dcbeb835726c824",
+ "storage/app/private/partnership-publication-summary-pint-latest-format-20261103.log": "45468233880de7aabbd7cbbec3f921c6c7d8f4983ea066a86318118ca5fa55d5",
+ "storage/app/private/partnership-publication-summary-frontend-final-20261103.log": "dcec18035ff8b2980f8d8b30cd292d5326138ce0d5a2c68d8a99a779d2905dff",
+ "storage/app/private/partnership-publication-summary-frontend-focused-20261103.log": "4fd82d73f4070ce0d7fe52ed53ab7951ec4449857a291014e79ed79a2189359a",
+ "storage/app/private/partnership-publication-summary-build-final-20261103.log": "a384a81c6bfd47c1e86373279d223c2578d4c98dc36139bdf190a26f9de353ab",
+ "storage/app/private/partnership-publication-summary-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/app/private/partnership-publication-summary-lint-final-20261103.log": "4ddf38cd31be2601d8c17e44253bd0e47cf7eed1f7dffd7197769912ccd64e4e"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/partnership-publication-summary-prior-receipt-20261103.json",
+ "sha256": "3e4de3455327ca1e53c9f417501b3ae9002cc7c8b8491fdadebfea718a38cb2f"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "cf8861013e0020326f5c2b06d5e8f21dd28ef4bd01b952c4b97709e4053acacd",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "resources/js/pages/partnerships/publication-history.tsx": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/PartnershipExchangeController.php": {
+ "previous": "cf8861013e0020326f5c2b06d5e8f21dd28ef4bd01b952c4b97709e4053acacd",
+ "current": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e"
+ },
+ "resources/js/lib/partnership-candidacy-edit.ts": {
+ "previous": "0f9353598c4a4e4929bb17944b6e5fd67e655f67677bf181c17cb2650b44d133",
+ "current": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226"
+ },
+ "resources/js/pages/partnerships/detail.tsx": {
+ "previous": "878c17342576c19b57be003c02c32e14f73f305eef7f635395c15c5ae6f90883",
+ "current": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c"
+ },
+ "tests/frontend/helpers/partnership-candidacy.mjs": {
+ "previous": "9851c311fac36369d3b0c18b8031a5c368a05943fc5fe2fdc7248f7a16cc0c19",
+ "current": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51"
+ },
+ "resources/js/lib/partnership-publication.ts": {
+ "previous": "e4e5f8db54800f389eab6889fd44f3cae65eda0d028e5d41af00338f97b1dea2",
+ "current": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23"
+ },
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": {
+ "previous": "1d68f7a8b06847721227a289d0f5f0fc35c77f432e3e3067f8350c1b5ed83980",
+ "current": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c"
+ },
+ "app/Services/PartnershipPublicationHistory.php": {
+ "previous": "ce983828ab46c974f4afef54c54fb550dbf7c30630b6225c4a07d251b6e61f16",
+ "current": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379"
+ },
+ "resources/js/pages/partnerships/publication-history.tsx": {
+ "previous": "ceb25a419e315c7f41175ef271c60abe31581751f795d21b4fb851640643a0f6",
+ "current": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763"
+ },
+ "tests/frontend/partnership-publication-history.test.mjs": {
+ "previous": "f407e1e9c4a41c78787c86707ca37989c59b7c1545ea7d8744aad2058a4a386d",
+ "current": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation remains memory-only across browser closure, reload or reauthentication",
+ "Summary and full reader share historical authority; missing content is not reconstructed",
+ "Browser acceptance, active delivery and other workflow/consumer variants remain pending",
+ "Previous compiled artifacts are historical fingerprints superseded by the current successful build, not current-bundle claims"
+ ]
+ },
+ "crm_task_creation_increment_20261103": {
+ "recorded_at": "2026-11-03T15:14:50.288Z",
+ "requirements": [
+ "AUD-CRM-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 77,
+ "passed": 77,
+ "assertions": 877,
+ "duration_ms": 330073
+ },
+ "targeted_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 10,
+ "passed": 10,
+ "assertions": 79,
+ "duration_ms": 80600
+ },
+ "new_feature_cases": 10,
+ "frontend_tests": 1545,
+ "focused_frontend_tests": 41,
+ "new_frontend_cases": 12,
+ "qa": {
+ "result": "passed",
+ "database": "crm_task_creation_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "format_and_lint_passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/CrmTaskCreation.php": "ae2238989e99cc83cc6ef0e951e5d2414dc474328fe33c060d1b4126a2ebe8bd",
+ "app/Http/Controllers/CrmController.php": "d4dfcefe1229dc347cef25cc4219f885d8d4c6a87454c55542a2104c3da49699",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "11d8600bdcb8f83259498ef192a28799aa60acf22cc3de379e3d7ce184f36fc2",
+ "resources/js/components/crm-task-creation.tsx": "34a935d2f645fec39e44d78d4435569d4bbdb7892d07aadb222ce1b2b77883ad",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "73d6330d86bcd70a48d4c6508b2ed61988fbc8b5d60995b95dce9680f1f99e95",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "tests/frontend/crm-next-action.test.mjs": "98ab86586ef4abe63dcea9cc6cd070781cb32770fc42d43ed379fe444fd7c127",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-crm-task-creation-20261103.php": "3bd6b76d6fab0831965eaf4d1c7afaff4c7231defe08da714e3e463cbdbb017a",
+ "storage/app/private/check-crm-task-creation-qa-20261103.php": "6502eb4108955c494c6e570d1d5de65f0f481eeb97cca2d4d1428c4675abe8e2",
+ "storage/app/private/record-crm-task-creation-20261103.cjs": "03d38ea8b34f5cb9501098cb5256b6ad09b09c78831aa339ab277f5c2d2b9e23"
+ },
+ "logs_sha256": {
+ "crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/crm-task-creation-audit-diagnostic-20261103.log": "2a36b4fd252dd8b0decb36023c0c307ab21fd1424334459270d6241e854e6746",
+ "storage/app/private/crm-task-creation-build-final-20261103.log": "0945e3f05a9198c998f3df18f421a18d21657d0739ab9f2a8969834dbf208713",
+ "storage/app/private/crm-task-creation-check-final-20261103.log": "001c6612f25acc7bb9f19c0a034b1b84df6fb988c25d66f0c94835a174cab252",
+ "storage/app/private/crm-task-creation-check-fix-20261103.log": "80a3fa77c9552213c30426412ae89cdc8a3838fe9ab9b22aac00ff8946bae816",
+ "storage/app/private/crm-task-creation-feature-initial-20261103.log": "cd29bc0b1986d2a8ac1a3635dbe2fd03544cf6fb6e70f5a6a391721d58b5bb60",
+ "storage/app/private/crm-task-creation-fixtures-format-20261103.log": "b984ea56366b8b0907e5d3f6b8ff401bd5c6b885e777d76392c4266ece9b0885",
+ "storage/app/private/crm-task-creation-format-equivalence-20261103.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "storage/app/private/crm-task-creation-format-equivalence-verified-20261103.log": "3053fbc419044b573fb0bf9f3ff2cfae2cb04bfd7312144c1bdfe2294102fa20",
+ "storage/app/private/crm-task-creation-format-final-20261103.log": "2c4a9bff4d5621f519607b7494ff80d7a27bdab0e710979910a8b81e9ea726c6",
+ "storage/app/private/crm-task-creation-format-verified-20261103.log": "3f275248900064687d87d36b786a422482a2a9900cc75bc72f017d1744346d82",
+ "storage/app/private/crm-task-creation-frontend-final-20261103.log": "6f2138a4a104d381d4482ad48d9e74936fc6c9ec8418c9c4aa7e791cf9794b0e",
+ "storage/app/private/crm-task-creation-frontend-focused-final-20261103.log": "d5c1d714320e073aab6c0b65b1c31dc0975d148026cbca2620c14a526a832b35",
+ "storage/app/private/crm-task-creation-frontend-focused-initial-20261103.log": "567483e8a8c94a1a55efc0f389413fe30b9786ec8a00d19a50271118550670af",
+ "storage/app/private/crm-task-creation-frontend-focused-verified-20261103.log": "8d450fda07dbdc3ce762cacd434fe8f48ffc02ffa0791524665705b107253c06",
+ "storage/app/private/crm-task-creation-frontend-initial-20261103.log": "902be5c1dc4cd010b02a15b3a891765048ae13c581f454af90048decf4a95162",
+ "storage/app/private/crm-task-creation-lint-final-20261103.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "storage/app/private/crm-task-creation-lint-verified-20261103.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "storage/app/private/crm-task-creation-phpstan-initial-20261103.log": "9c61f046ff655af80f703c517eb062a0233c6937e889d07979f2ad103b13817b",
+ "storage/app/private/crm-task-creation-pint-correction-20261103.log": "97986b563cc32a0aca45165a01a5cdb966f43537505015199abe571259423bf5",
+ "storage/app/private/crm-task-creation-pint-final-20261103.log": "cb7c569a19ea349ec46399ea1256051f13372a0e24e3673aeaa71df07002af95",
+ "storage/app/private/crm-task-creation-pint-format-20261103.log": "dc7a2cb6faca80017a3a7b123b6fb3329b09a2b4fb348231b7784e3a8e024202",
+ "storage/app/private/crm-task-creation-pint-initial-20261103.log": "84e21b42b983d1bd3a0283e0ac8a92fc7378fbec6c350a995c20bfc392b21768",
+ "storage/app/private/crm-task-creation-types-initial-20261103.log": "f5096d010b0a973570e16ee03c7c44f23233e02945deb94042a2ab91a0542fcd"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/crm-task-creation-prior-receipt-20261103.json",
+ "sha256": "98a0f5f39e73a1a0f8c86ef17a9a17632f4b5853f56bec02f6f84bffd1cdeec9"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/CrmController.php": {
+ "previous": "ab92f9dc61642d5092d0ad3d75a6fcf4a03e2089c1304f4e99cd0aa104161efd",
+ "current": "d4dfcefe1229dc347cef25cc4219f885d8d4c6a87454c55542a2104c3da49699"
+ },
+ "resources/js/pages/crm/lead.tsx": {
+ "previous": "2f9442860ac208ceda2932e55aa2be70dc20990426595c0f807cf408edfe6894",
+ "current": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc"
+ },
+ "tests/frontend/desk-closed-lifecycle.test.mjs": {
+ "previous": "d87e025141841d1d7690c8a3705f5acb8ac68fdeeb42fac76b2a86cd07978ec2",
+ "current": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080"
+ },
+ "resources/js/lib/crm-record-edit.ts": {
+ "previous": "8eb42eb460f2e7d9dd1a4c1b171cc094ecc95d0b6499aba2e5bac843d9f86049",
+ "current": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74"
+ },
+ "tests/frontend/crm-record-versions.test.mjs": {
+ "previous": "63d721aa450ac4ad7740ffc375c01711d4cbe96494cf39ccb7a6d54f15a4ce3a",
+ "current": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a"
+ },
+ "tests/frontend/dashboard-work-queue.test.mjs": {
+ "previous": "cfdf351f4433e9d9cbedbaaad8db5c2d62ff3a48a08527259e3a6ae530904890",
+ "current": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630"
+ },
+ "tests/frontend/crm-next-action.test.mjs": {
+ "previous": "0b6050fd87a9283e989d5aab29cfaf9449442354ed2acfac6a7b9cb48bbff139",
+ "current": "98ab86586ef4abe63dcea9cc6cd070781cb32770fc42d43ed379fe444fd7c127"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "a32107191fad0a01d52e23cab00755a258e3a28b70df5d3f771dc813d7501ab6",
+ "public/build/assets/lead-Bh55RTTN.js": "f3027b02aa1c81dbecae3b59d9fe1f9ff7fac8a9a48c02f0042d42570397cb4f",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/shared-DcTJM_Z4.js": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/crm-edit-comparison-Db53T7I7.js": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "public/build/assets/types-BoD_IJFv.js": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "083901bad36ea0d8f0efb9e22a7245f15579f7c3e0932f953630befac4189441",
+ "current": "a32107191fad0a01d52e23cab00755a258e3a28b70df5d3f771dc813d7501ab6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/detail-BT0Y4QFd.js": {
+ "previous": "b69e69ef108ada121514a810f8b3ebfb39c473242a3a31a0e0584a9f6640df7f",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-complements-Cvv4XxIw.js": {
+ "previous": "937d121143009cbe9f0ca3cef73bdf09c7f0002e3538c2d15d566827922077f4",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-DBMcKKWv.js": {
+ "previous": "c035bd91badad4bb75bcae83bc7e5bd5e272b21d9fa37f193a59bbf5ff918ce0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/structure-geography-BEXuLtac.js": {
+ "previous": "4a07dcfc6dddab94d0c889f18591ce657c52ae05691287f3132fc75aa3ff7af7",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-E1X5J_3p.js": {
+ "previous": "000009095068e2f80b4b60abfffeb831f4e28310f74543a95cc0ad3bffb3bf4c",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": {
+ "previous": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "current": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-AVMnLN2h.js": {
+ "previous": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "current": "91fe5fa2640eabc7fc680954a847238df1156983839f5b56ed6e93b55dd0af7c",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-CjcfdjBU.js": {
+ "previous": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "current": "d58395c06df1a0f4a4489925cedd47115c59cc3889961ba0ae19f7d64c84db34",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-DcTJM_Z4.js": {
+ "previous": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "current": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/partnership-history-CfclSLAo.js": {
+ "previous": "4668cf773996dc3ac4444a5dc066e6486ab9759120203bdce4466c1579dd9c56",
+ "current": "4668cf773996dc3ac4444a5dc066e6486ab9759120203bdce4466c1579dd9c56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/publication-history-BDrB2ehn.js": {
+ "previous": "b860e0bbbbf41078590ed455d25ffd6ee4b56d858f9c08c7a51b7d672faf4ceb",
+ "current": "b860e0bbbbf41078590ed455d25ffd6ee4b56d858f9c08c7a51b7d672faf4ceb",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation is memory-only across page closure, reload and reauthentication",
+ "Legacy callers without an operation key retain the previous creation contract",
+ "No new multiprocess creation race is claimed; earlier concurrency proofs are preserved",
+ "Other consumers/profiles, browser acceptance and active delivery remain pending"
+ ]
+ },
+ "crm_task_preparation_increment_20261103": {
+ "recorded_at": "2026-11-03T16:11:29.773Z",
+ "requirements": [
+ "AUD-CRM-01"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 48,
+ "passed": 48,
+ "assertions": 369,
+ "duration_ms": 140591
+ },
+ "targeted_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 14,
+ "passed": 14,
+ "assertions": 123,
+ "duration_ms": 29746
+ },
+ "new_feature_cases": 14,
+ "feature_overlap": 13,
+ "frontend_focused_tests": 57,
+ "new_frontend_cases": 16,
+ "frontend_baseline": {
+ "tests": 1545,
+ "source_receipt": "crm_task_creation_increment_20261103",
+ "current_full_suite_executed": false,
+ "overlapping_cases_rechecked": 41
+ },
+ "qa": {
+ "result": "passed",
+ "database": "crm_task_preparation_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "format_and_lint_passed_without_warnings",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "routes/web.php": "b69f40c491dd141adf23be935e70419fa87fee1676a2e3ed2061437d26126720",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-crm-task-preparation-20261103.php": "ac574a21153e606b7a7dca13aebdb2a2fbccac7e0c1f3946ce3dddfb4a2b0160",
+ "storage/app/private/check-crm-task-preparation-qa-20261103.php": "fbf32ddd01a926f0d2808427498ea5e004bc912147bcfb360f39f26aa213785b",
+ "storage/app/private/record-crm-task-preparation-20261103.cjs": "ee00119bde973af66c9013c7d0a26e49b00c61a89e515753bd24d0d705a49062"
+ },
+ "logs_sha256": {
+ "crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/crm-task-preparation-build-accepted-20261103.log": "dbab95435b04cf958ea36b88701a2f86395379bd825baa336911282a10e2e60c",
+ "storage/app/private/crm-task-preparation-build-final-20261103.log": "5a281c8a708e3c0a6f81d1818464fbcb36ca903788fdd4b67133165c99055b8f",
+ "storage/app/private/crm-task-preparation-build-verified-20261103.log": "fe65c77e7ae5dcd1996afd077eccd1e03d136c4d58bcec96d9f1bf0cc616b088",
+ "storage/app/private/crm-task-preparation-check-accepted-20261103.log": "204dd4b069bb761d26fedff2cc04e24ccae3c329fa8f367ecaba949a08eadfca",
+ "storage/app/private/crm-task-preparation-check-empty-format-20261103.log": "ad47d43473c1531e7f849aa5b3edf9a6cdfcfa1b17f9bad3857fdb4dfc4b603e",
+ "storage/app/private/crm-task-preparation-check-final-20261103.log": "4abc95623ac9a19241c98383f3d30b133bb0d1ce4336ac3be88e51737e9d46ac",
+ "storage/app/private/crm-task-preparation-check-fix-20261103.log": "81fc3ab4b4a2d81096b2ed185080a40a087f6e4636e7748d21efecfa874bdb63",
+ "storage/app/private/crm-task-preparation-check-fix-final-20261103.log": "ed3def734ac1270b11e4d2f68f68797ba6ae918cadcbd51ad98c61f1e0def4c6",
+ "storage/app/private/crm-task-preparation-check-last-format-20261103.log": "fe883dcc799a370fcf06a926a55e964e89b0d07d9cf6400bba639733fb17f2df",
+ "storage/app/private/crm-task-preparation-check-verified-20261103.log": "5236190615011497b885a4496fe06958f64cf1965fd1ffdbbfd1de477367afbc",
+ "storage/app/private/crm-task-preparation-empty-reproduction-20261103.log": "0ebd72be1ed3eb84700b59315a0cf01996397a0fff7608f901646e7bd3fc86aa",
+ "storage/app/private/crm-task-preparation-feature-initial-20261103.log": "15209de8bf750cec02296d241d5e4a2ce9e5e63a57367cf5ee3e9320fd65b96c",
+ "storage/app/private/crm-task-preparation-feature-initial-full-20261103.log": "66ad0c8db3067acb469e7fa25cdfabcf3f987a73a59f6e03a7e69b7958c07fcc",
+ "storage/app/private/crm-task-preparation-frontend-accepted-20261103.log": "b7534743c59cc3fef1956e5052aacd4de2bf0a224c394d0ff7b189189c806cf9",
+ "storage/app/private/crm-task-preparation-frontend-final-20261103.log": "ef736e0122425fadd124e8884e6566d4d7946788240ce7d66216ad5fdf845752",
+ "storage/app/private/crm-task-preparation-frontend-focused-initial-20261103.log": "1da7c5f630783b13075f337d04a85642e8b5a2f045627dce490a4f80a465a16a",
+ "storage/app/private/crm-task-preparation-frontend-initial-20261103.log": "1f76d3f19687c7ade15a671db6bc8714fda738b06dd931545d73f69bd9b61d5f",
+ "storage/app/private/crm-task-preparation-frontend-verified-20261103.log": "7640822d08925396709f2fac6511c9b46cbe0d3911ac6ceba2682ccbe0010f3c",
+ "storage/app/private/crm-task-preparation-legacy-frontend-initial-20261103.log": "bd7a8bee7a2730c2d3e4bed924a635050af5585ba8415574a1be558356e03226",
+ "storage/app/private/crm-task-preparation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/crm-task-preparation-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/crm-task-preparation-pint-canonical-format-20261103.log": "d13d6560c98580acc8c03d4a0439363e3f730f715efbcd26d19a5cb9d9cfd4d4",
+ "storage/app/private/crm-task-preparation-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/crm-task-preparation-pint-format-20261103.log": "030efb03020462b987572b62677b52d5957122d16de7738a9a6b6d2d1252066a",
+ "storage/app/private/crm-task-preparation-pint-format-final-20261103.log": "329e42f7e10098bcdeb313dc9b56b2d773f4eae77e127bb9b13e787f7dd642fa",
+ "storage/app/private/crm-task-preparation-pint-format-verified-20261103.log": "218158d747bb22f0960d0d3b27d30e3bcbca5578d7e12825673b088c5a592f1c",
+ "storage/app/private/crm-task-preparation-types-accepted-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/app/private/crm-task-preparation-types-final-20261103.log": "fc4834e0f220b2c8a36895baa7f237e3e0164cf54657c6d75752f2da169f6870",
+ "storage/app/private/crm-task-preparation-types-initial-20261103.log": "313689f9cfb8bf88cd7ff039413e22ea03da2a79950724ef58ef426c09652991",
+ "storage/app/private/crm-task-preparation-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/crm-task-preparation-prior-receipt-20261103.json",
+ "sha256": "ab89edde19a71f85e07f44f5b436fb21fc77ce5d974c02f332915cdb5c903a81"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "d4dfcefe1229dc347cef25cc4219f885d8d4c6a87454c55542a2104c3da49699",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "98ab86586ef4abe63dcea9cc6cd070781cb32770fc42d43ed379fe444fd7c127",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "ae2238989e99cc83cc6ef0e951e5d2414dc474328fe33c060d1b4126a2ebe8bd",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "11d8600bdcb8f83259498ef192a28799aa60acf22cc3de379e3d7ce184f36fc2",
+ "resources/js/components/crm-task-creation.tsx": "34a935d2f645fec39e44d78d4435569d4bbdb7892d07aadb222ce1b2b77883ad",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "73d6330d86bcd70a48d4c6508b2ed61988fbc8b5d60995b95dce9680f1f99e95",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975"
+ },
+ "prior_code_deltas": {
+ "app/Http/Controllers/CrmController.php": {
+ "previous": "d4dfcefe1229dc347cef25cc4219f885d8d4c6a87454c55542a2104c3da49699",
+ "current": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268"
+ },
+ "tests/frontend/crm-next-action.test.mjs": {
+ "previous": "98ab86586ef4abe63dcea9cc6cd070781cb32770fc42d43ed379fe444fd7c127",
+ "current": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d"
+ },
+ "app/Services/CrmTaskCreation.php": {
+ "previous": "ae2238989e99cc83cc6ef0e951e5d2414dc474328fe33c060d1b4126a2ebe8bd",
+ "current": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e"
+ },
+ "resources/js/lib/crm-task-creation.ts": {
+ "previous": "11d8600bdcb8f83259498ef192a28799aa60acf22cc3de379e3d7ce184f36fc2",
+ "current": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69"
+ },
+ "resources/js/components/crm-task-creation.tsx": {
+ "previous": "34a935d2f645fec39e44d78d4435569d4bbdb7892d07aadb222ce1b2b77883ad",
+ "current": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722"
+ },
+ "tests/frontend/helpers/crm-task-creation.mjs": {
+ "previous": "73d6330d86bcd70a48d4c6508b2ed61988fbc8b5d60995b95dce9680f1f99e95",
+ "current": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "67dad39cc70ccfeae9bdd7ec4a8b965c1b13cc6bbcc73e62d79575acbee70c07",
+ "public/build/assets/lead-C8dktLbK.js": "fc30692a89d9168137cd4a01b023437a28f4dfd17b16660a997bc53c1d848c68",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/shared-DcTJM_Z4.js": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/crm-edit-comparison-Db53T7I7.js": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "public/build/assets/types-BoD_IJFv.js": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "a32107191fad0a01d52e23cab00755a258e3a28b70df5d3f771dc813d7501ab6",
+ "current": "67dad39cc70ccfeae9bdd7ec4a8b965c1b13cc6bbcc73e62d79575acbee70c07",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/lead-Bh55RTTN.js": {
+ "previous": "f3027b02aa1c81dbecae3b59d9fe1f9ff7fac8a9a48c02f0042d42570397cb4f",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-DcTJM_Z4.js": {
+ "previous": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "current": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/crm-edit-comparison-Db53T7I7.js": {
+ "previous": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "current": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/types-BoD_IJFv.js": {
+ "previous": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "current": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Only confirmed server preparation is durable; other forms and unconfirmed edits retain their own limitations",
+ "Preparation is per current account/lead and never grants business authority",
+ "Other consumers/profiles, browser acceptance and active migration/delivery remain pending",
+ "The prior integral frontend suite is historical; current execution is the focused 57-case scope",
+ "No new multiprocess creation/preparation proof is claimed"
+ ]
+ },
+ "education_work_queue_increment_20261103": {
+ "recorded_at": "2026-11-03T16:58:25.959Z",
+ "requirements": [
+ "AUD-EDU-01",
+ "AUD-EDU-03"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 30,
+ "passed": 30,
+ "assertions": 629,
+ "duration_ms": 132345
+ },
+ "new_feature_cases": 16,
+ "frontend_focused_tests": 22,
+ "new_frontend_cases": 17,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_education_draft_cases": 5
+ },
+ "qa": {
+ "result": "passed",
+ "database": "education_work_queue_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_level_7_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "functional_sources_sha256": {
+ "docs/investmoz/education/decisions.md": "ae144e7594d0e730dc62e0a4754072c09095f4187df8de9e5d585872402f3b1c"
+ },
+ "owner_reply": {
+ "question": "Approved representation and consent register/document for external Education actors",
+ "answer": "nao existe",
+ "effect": "External mandate/consent definitions remain absent; existing internal authority only"
+ },
+ "code_sha256": {
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "routes/web.php": "b4bab2e4254588a9fd82288c1152e3b6eb1a2ffd8dc6c3e7620735a1321ef175",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-education-work-queue-20261103.php": "75ca78511a44ffe374e24f6845ac4d2d68030b8640e337aae7ec1553f0c97806",
+ "storage/app/private/check-education-work-queue-qa-20261103.php": "e0fcdd77a2ad8044211e2c3a290e9d927a141d6c73a3fcda9784a6b25d57082b",
+ "storage/app/private/record-education-work-queue-20261103.cjs": "8e540112ad56f4f1167b340b39706ac58f3b3fe0c0e09c8bc0d8fe106d9eac26"
+ },
+ "logs_sha256": {
+ "education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/education-work-queue-check-fix-20261103.log": "a588014066df837a318303f3a74d8241424d91cb6e29bfda2c5c68996f10a436",
+ "storage/app/private/education-work-queue-check-format-final-20261103.log": "4a6c96c5bfa3ad912bc08f25ab03e1f38b85ca0379ece7a491679ce05e6be853",
+ "storage/app/private/education-work-queue-check-format-history-20261103.log": "bb693783c12f256080266550e347c1f21afe1800ceefc5d6765efad141b08c57",
+ "storage/app/private/education-work-queue-feature-final-20261103.log": "8e81774fae8e6b48df02330aed023bfa08e467b9574fc9d724242a061304e005",
+ "storage/app/private/education-work-queue-feature-initial-20261103.log": "f1b70d683ecd0951bb66d804d9f5d8eeb3cb2bf163abef0f5f7704736cfbb544",
+ "storage/app/private/education-work-queue-feature-verified-20261103.log": "0879ef26864b9bb12a102dfe3e9e98d0092f3c93193523d96849791d1edef601",
+ "storage/app/private/education-work-queue-frontend-expanded-20261103.log": "9eee60d4c28621ce136141310b9653aaa260bd13e07c15b480f575ecc633c00e",
+ "storage/app/private/education-work-queue-frontend-focused-initial-20261103.log": "c6b06e6d41324130d10f05ced25b67f27436b12f66783cc88e4a0cf2b6553fd8",
+ "storage/app/private/education-work-queue-frontend-initial-20261103.log": "b39d1730d084e3d2d7dc44f788c6984d168fc22aba0eeebe80217ae44a51bb7b",
+ "storage/app/private/education-work-queue-frontend-initial-current-20261103.log": "8e6bf7e5530b9bf7dd1574f585d1f49ef702c4618ae160076d96684b519ea393",
+ "storage/app/private/education-work-queue-phpstan-final-20261103.log": "0d89e28f347793cd2583cb8060b0c2af4153e9d0708cb5417f2a537beb4cab8d",
+ "storage/app/private/education-work-queue-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/education-work-queue-phpstan-verified-20261103.log": "6b8895211e0bbb1c6ee1723661d29f7427f9f4784283bd2c4985f0f1944cbaf7",
+ "storage/app/private/education-work-queue-pint-fixture-20261103.log": "d4a9a008f494e02934ba3f00f831194b62c28a8cc9fd866a95cf43f59e15a759",
+ "storage/app/private/education-work-queue-pint-format-20261103.log": "6ea738347d5ccb75d1008abe06292e79f050b3739ae7bdadf32cac7646e9309b",
+ "storage/app/private/education-work-queue-pint-format-final-20261103.log": "c540abf629a257417fba7fee408c706a75003a3caa2a311ab9d05c7fb0cd7720",
+ "storage/app/private/education-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/education-work-queue-saldo-before-20261103.log": "1b0031077eb0c3c0701e03b5c094fbcb0509be7c1aa8da4e041f9ad33c7775a5",
+ "storage/app/private/education-work-queue-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/app/private/education-work-queue-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/education-work-queue-prior-receipt-20261103.json",
+ "sha256": "7ebf15d3bb8a9507f7039d2bf7510f005d523a4604254c54b65d2f85fdf0b216"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "b69f40c491dd141adf23be935e70419fa87fee1676a2e3ed2061437d26126720",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216"
+ },
+ "prior_code_deltas": {
+ "routes/web.php": {
+ "previous": "b69f40c491dd141adf23be935e70419fa87fee1676a2e3ed2061437d26126720",
+ "current": "b4bab2e4254588a9fd82288c1152e3b6eb1a2ffd8dc6c3e7620735a1321ef175"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "74b86b3cc4e4a8797bcd19ab200cb7fba5e4153c50e23167f415a94d28121b01",
+ "public/build/assets/education-D6pbhgld.js": "c91c550f1d795db0b05ad5b3bffe0842006758c95c0a3b98881edbf2509d7cf3",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/investment-territory-B8X4GTKn.js": "a6ccabcbd97ab9b185244df88b1963466a015cc36a74713725f3d55a8f9bb8ae",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-Bmc7siSP.js": "e565a7ebe5c54d7e2980ab15e8e4918b9c0a2120f3ca94a97d671226fa858894",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/app-Bl3X2HAS.js": "c6ca295140fd427a09cbf6c9ee7319bf1d0922e1ff36e5b2ac488995828e1af0",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/territory-geometry-preview-DSWflanq.js": "f393ec55b7d2647bf389e8588f8f2634d8c409571bf0e39fd5616f0367070001",
+ "public/build/assets/interactive-investment-map-B1VxjrWs.js": "72f38b9e03e69453563a964748dbd087d291c3cd86f7e411c3872d17c89ca1da",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-DcTJM_Z4.js": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/declaration-CUXRdLsa.js": "9d0ab01163a62d68776c937a92b8282b9efd7014ce358fb2230d09e5fd060313",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/analysis-BadjC-0H.js": "cc210f6ad9d53e053fc26b98b06591c439245ea78de0422650be9644fe87744d"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "67dad39cc70ccfeae9bdd7ec4a8b965c1b13cc6bbcc73e62d79575acbee70c07",
+ "current": "74b86b3cc4e4a8797bcd19ab200cb7fba5e4153c50e23167f415a94d28121b01",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/lead-C8dktLbK.js": {
+ "previous": "fc30692a89d9168137cd4a01b023437a28f4dfd17b16660a997bc53c1d848c68",
+ "current": "fc30692a89d9168137cd4a01b023437a28f4dfd17b16660a997bc53c1d848c68",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-DcTJM_Z4.js": {
+ "previous": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "current": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/crm-edit-comparison-Db53T7I7.js": {
+ "previous": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "current": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/types-BoD_IJFv.js": {
+ "previous": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "current": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Existing internal manager only; external student/provider/employer journeys and mandate/consent definitions pending",
+ "No durable recovery of unconfirmed review preparation after losing the page",
+ "No reconstruction of older reasons never preserved; current master labels are not historical snapshots",
+ "No browser acceptance, new multiprocess proof or active installation claimed",
+ "Full historical frontend suite not repeated; focused 22 cases executed"
+ ]
+ },
+ "opportunity_technical_incidents_increment_20261103": {
+ "recorded_at": "2026-11-03T17:22:45.303Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 15,
+ "passed": 15,
+ "assertions": 264,
+ "duration_ms": 256041
+ },
+ "new_feature_cases": 8,
+ "frontend_focused_tests": 12,
+ "new_frontend_cases": 6,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_profile_transport_cases": 6
+ },
+ "initial_mixed_diagnostic": {
+ "status": "running_observed",
+ "session": 53686,
+ "database": "opportunity_incidents_20261103_test",
+ "observed_at": "2026-11-03T17:22:35.902Z",
+ "log": "storage/app/private/opportunity-incidents-feature-initial-20261103.log"
+ },
+ "qa": {
+ "result": "passed",
+ "database": "technical_support_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_level_7_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "owner_reply": {
+ "answer": "Perfil próprio de Suporte técnico",
+ "effect": "Scoped technical_support role; no automatic business decision or document authority"
+ },
+ "code_sha256": {
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "app/Services/OpportunityTechnicalIncidents.php": "c76caee675dc4f98c96479d84b0fee610b6d9b639928686ec3459acdbe0d5bba",
+ "app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "app/Services/OpportunityTechnicalSupport.php": "7d75c098849e231c54db7185beeca693bde56bf23c4b3fcf36eca0d2b2b505ae",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "321a0516510f545f03150a20f5f6a809be8fe863ce1efffe1b07bfa7406c75a6",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "routes/web.php": "8cb9afca629d92281a17a99e7dbcee5c4c9868d7608d7cb920ef5e3f5ff21a45",
+ "resources/js/components/opportunity-technical-incidents.tsx": "96d73cb8ea2cc09cd2f5f1eeb8c3e66dce58e914f75013602de8673de54d9662",
+ "resources/js/components/profile-navigation.tsx": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "d94509ad57f74f887fec07469b12c4325938720e96aca322a63f28c023a8d6ae",
+ "resources/js/types/profile-access.ts": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "718cb7a8decbdc2845035276d62a4bbf0432bcf0fbef63ee8023d836950a2c91"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-technical-support-20261103.php": "4b5b7b5a09e1178cbec2a229205aee76013fb2f90d3912ccbcc6f60b1afd7e6e",
+ "storage/app/private/check-technical-support-qa-20261103.php": "3f94783cdeb9e7ff204d0d94e07eed794424c3a0a55a0745b1f63f878c203889",
+ "storage/app/private/check-opportunity-incidents-qa-20261103.php": "40518c98c935ea05ca9a2dece8465400684392be7615c1656ee099914b1ad17c",
+ "storage/app/private/record-opportunity-incidents-20261103.cjs": "b8304a552f1be86e59a331d015f6c2e5e0c1d80b08e3e81dcb7a2772c391e787"
+ },
+ "logs_sha256": {
+ "opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/opportunity-incidents-check-format-20261103.log": "ee35f3eaf99c02bedc8a3e49e9dfe9edf61e1c740bf7d6932c142b3862371583",
+ "storage/app/private/opportunity-incidents-check-format-final-20261103.log": "c8e767f64f3e5826497ab0fa1fe74de3f9dbe61daccfb5d1a359868d7342a2e2",
+ "storage/app/private/opportunity-incidents-check-format-role-20261103.log": "3acf7d0300b4be32eb590434178dce289e4f2942e93ae8d70e4370765f4a1873",
+ "storage/app/private/opportunity-incidents-feature-role-final-20261103.log": "0a4f90e92c5889e0ba6a379e19286a35a63093deb6a9a621b8082d7aedffcab3",
+ "storage/app/private/opportunity-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/opportunity-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/opportunity-incidents-pint-fixture-20261103.log": "4776aad69785d5f0ca3aa9031995d5fa14b7de3f6e105914107f79bca49f5990",
+ "storage/app/private/opportunity-incidents-pint-format-20261103.log": "41878b10a7048f63a815b7ee5fed42c958c3eea54a2ebfb4f50bdf43f5d1c61e",
+ "storage/app/private/opportunity-incidents-pint-format-final-20261103.log": "3cfc95c69304d4af9333dd7c59c668e34805b3c229de96732939e66fe8763113",
+ "storage/app/private/opportunity-incidents-pint-format-role-20261103.log": "1afc34c1b277e395cdf3c089303a806518bc5109e534e37650a1d20223c33685"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/opportunity-incidents-prior-receipt-20261103.json",
+ "sha256": "81ac05296a74b5ca738749c404bd22b2d154d7582ca0b13899e480082778d5cb"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "b4bab2e4254588a9fd82288c1152e3b6eb1a2ffd8dc6c3e7620735a1321ef175",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9"
+ },
+ "prior_code_deltas": {
+ "routes/web.php": {
+ "previous": "b4bab2e4254588a9fd82288c1152e3b6eb1a2ffd8dc6c3e7620735a1321ef175",
+ "current": "8cb9afca629d92281a17a99e7dbcee5c4c9868d7608d7cb920ef5e3f5ff21a45"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "73051a57c960c9c161866607f6a465eb894f799112861482eefa0e82cf4445f4",
+ "public/build/assets/opportunity-draft-BBUKmvzc.js": "beb079355495fd49760f15e085ec7e90d7d3766810ad63d74d20aa72d105cf49",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/investment-territory-BRZ6u1s4.js": "a47701ae2c60873393008ad911c1e56b50e2627c3b20818ae19d215bc325f6bc",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-CBruj8Nl.js": "a105ba83135594116db29dc85c814f2c75e7273d46e5518c059a26a9da0b376f",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/app-CX6VnS3b.js": "4995ffb53d77617ffc6065d3e6601fd87b36e451f773cc2f0a2b63da5bedb768",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/territory-geometry-preview-D5j4bydx.js": "82570824d75b43cbb6b5cff78a772fb62aa9fa65cbc2881475fd0307951e6846",
+ "public/build/assets/interactive-investment-map-DW6UVqEU.js": "becd7d9d0900da7e25462c04d3c3357dafa8ad71de3bf16123398a483f0a9fc8",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-3QGErCo-.js": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-classification-BoQfr2Xg.js": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "public/build/assets/opportunity-search-filters-C6NFQIvP.js": "46bbfadf5df0e2174d47435ae6654028f733f97bf4de3c75ed7a8a91de8ba765",
+ "public/build/assets/proactive-investment-XdN3JLTR.js": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "public/build/assets/administration-B8fo3qS_.js": "77ee0ef3e5722182ff7f7ed17f08e98651009f826cfd16718c951a9e815d2ab0",
+ "public/build/assets/technical-support-egXrkOyq.js": "04068f4b6744e0d8af69fc27f21ce8dfd6be2ed6fd771aac2d0dc6bda5689c03"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "74b86b3cc4e4a8797bcd19ab200cb7fba5e4153c50e23167f415a94d28121b01",
+ "current": "73051a57c960c9c161866607f6a465eb894f799112861482eefa0e82cf4445f4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/education-D6pbhgld.js": {
+ "previous": "c91c550f1d795db0b05ad5b3bffe0842006758c95c0a3b98881edbf2509d7cf3",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-B8X4GTKn.js": {
+ "previous": "a6ccabcbd97ab9b185244df88b1963466a015cc36a74713725f3d55a8f9bb8ae",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-Bmc7siSP.js": {
+ "previous": "e565a7ebe5c54d7e2980ab15e8e4918b9c0a2120f3ca94a97d671226fa858894",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-Bl3X2HAS.js": {
+ "previous": "c6ca295140fd427a09cbf6c9ee7319bf1d0922e1ff36e5b2ac488995828e1af0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-DSWflanq.js": {
+ "previous": "f393ec55b7d2647bf389e8588f8f2634d8c409571bf0e39fd5616f0367070001",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-B1VxjrWs.js": {
+ "previous": "72f38b9e03e69453563a964748dbd087d291c3cd86f7e411c3872d17c89ca1da",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-DcTJM_Z4.js": {
+ "previous": "e973f9e86f9d785596987f62c09be162e8a12afe3ef99a21eb2823fbecff56ad",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/declaration-CUXRdLsa.js": {
+ "previous": "9d0ab01163a62d68776c937a92b8282b9efd7014ce358fb2230d09e5fd060313",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/analysis-BadjC-0H.js": {
+ "previous": "cc210f6ad9d53e053fc26b98b06591c439245ea78de0422650be9644fe87744d",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Incident treatment lifecycle/notes/history, alerting and other technical failure boundaries pending",
+ "Support role and queue are current-scope technical metadata only; no business ACL granted",
+ "Authenticated installer update/delivery and browser acceptance remain pending",
+ "Unknown outcome requires explicit state consultation; no automatic command repetition",
+ "Initial mixed execution is diagnostic and not claimed globally green; current final scope is 15 Feature and 12 frontend"
+ ]
+ },
+ "technical_incident_handling_increment_20261103": {
+ "recorded_at": "2026-11-03T17:45:14.618Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 18,
+ "passed": 18,
+ "assertions": 339,
+ "duration_ms": 165516
+ },
+ "new_feature_cases": 10,
+ "frontend_focused_tests": 28,
+ "new_frontend_cases": 16,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_transport_cases": 12
+ },
+ "qa": {
+ "result": "passed",
+ "database": "incident_handling_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "database": "incident_handling_concurrency_20261103b_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "scenarios": 1,
+ "workers": 2,
+ "observed": [
+ {
+ "pid": 21604,
+ "wait_event": "advisory",
+ "blockers": "{24952}"
+ },
+ {
+ "pid": 29124,
+ "wait_event": "transactionid",
+ "blockers": "{21604}"
+ }
+ ],
+ "results": [
+ {
+ "status": 200,
+ "result_version": 1,
+ "replayed": false
+ },
+ {
+ "status": 409
+ }
+ ],
+ "final_version": 2,
+ "final_state": "resolved",
+ "readonly_replay": true,
+ "business_preserved": true,
+ "root_preserved": true,
+ "synthetic_counts": {
+ "users": 4,
+ "organizations": 1,
+ "opportunities": 1,
+ "portal_role_assignments": 2,
+ "audit_events": 3,
+ "tasks": 0
+ },
+ "row_visibility": [
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "active_writes": 0,
+ "active_migrations": 0
+ },
+ "concurrency_existing_guard": {
+ "result": "failed",
+ "error": "Existing QA records will not be reset."
+ },
+ "prior_mixed_terminal": {
+ "tool": "phpunit",
+ "result": "failed",
+ "tests": 45,
+ "passed": 41,
+ "assertions": 1004,
+ "duration_ms": 1371286,
+ "failed": 4,
+ "failures": [
+ {
+ "test": "Tests\\Feature\\OpportunityTechnicalIncidentsTest::test_failed_submission_rolls_back_and_records_only_minimal_private_metadata_then_allows_manual_recovery",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php",
+ "line": 73,
+ "message": "Expected response status code [503] but received 422.\nFailed asserting that 422 is identical to 503.\r\n\r\nThe following errors occurred during the last request:\n\n{\n \"message\": \"Preencha este campo antes de submeter. (and 18 more errors)\",\n \"errors\": {\n \"canonical.opportunity_category\": [\n \"Preencha este campo antes de submeter.\",\n \"Categoria fora desta entrega: concessão, financiamento, fornecimento e outros permanecem indisponíveis. Os registos anteriores são preservados.\"\n ],\n \"canonical.official_title\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_type\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.internal_contact_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.sector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.subsector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.economic_activity_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.location_mode\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.geographic_scope\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.locations\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.executive_summary\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.demand_statement\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.documents\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.evidences\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.publication_languages\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.visibility\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.truth_declaration\": [\n \"Preencha este campo antes de submeter.\"\n ]\n }\n}",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php:73"
+ ]
+ },
+ {
+ "test": "Tests\\Feature\\OpportunityTechnicalIncidentsTest::test_publication_failure_preserves_approved_content_public_projection_tasks_and_original_decisions",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php",
+ "line": 100,
+ "message": "Expected response status code [200] but received 422.\nFailed asserting that 422 is identical to 200.\r\n\r\nThe following errors occurred during the last request:\n\n{\n \"message\": \"Preencha este campo antes de submeter. (and 18 more errors)\",\n \"errors\": {\n \"canonical.opportunity_category\": [\n \"Preencha este campo antes de submeter.\",\n \"Categoria fora desta entrega: concessão, financiamento, fornecimento e outros permanecem indisponíveis. Os registos anteriores são preservados.\"\n ],\n \"canonical.official_title\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_type\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.internal_contact_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.sector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.subsector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.economic_activity_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.location_mode\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.geographic_scope\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.locations\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.executive_summary\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.demand_statement\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.documents\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.evidences\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.publication_languages\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.visibility\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.truth_declaration\": [\n \"Preencha este campo antes de submeter.\"\n ]\n }\n}",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php:100"
+ ]
+ },
+ {
+ "test": "Tests\\Feature\\OpportunityTechnicalIncidentsTest::test_a_second_storage_failure_returns_an_honest_reference_without_leaking_sql_or_claiming_a_saved_incident",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php",
+ "line": 132,
+ "message": "Expected response status code [503] but received 422.\nFailed asserting that 422 is identical to 503.\r\n\r\nThe following errors occurred during the last request:\n\n{\n \"message\": \"Preencha este campo antes de submeter. (and 18 more errors)\",\n \"errors\": {\n \"canonical.opportunity_category\": [\n \"Preencha este campo antes de submeter.\",\n \"Categoria fora desta entrega: concessão, financiamento, fornecimento e outros permanecem indisponíveis. Os registos anteriores são preservados.\"\n ],\n \"canonical.official_title\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_type\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.internal_contact_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.sector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.subsector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.economic_activity_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.location_mode\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.geographic_scope\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.locations\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.executive_summary\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.demand_statement\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.documents\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.evidences\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.publication_languages\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.visibility\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.truth_declaration\": [\n \"Preencha este campo antes de submeter.\"\n ]\n }\n}",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php:132"
+ ]
+ },
+ {
+ "test": "Tests\\Feature\\OpportunityTechnicalIncidentsTest::test_incident_consultation_rechecks_current_authority_and_never_grants_other_record_or_document_access",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php",
+ "line": 143,
+ "message": "Expected response status code [503] but received 422.\nFailed asserting that 422 is identical to 503.\r\n\r\nThe following errors occurred during the last request:\n\n{\n \"message\": \"Preencha este campo antes de submeter. (and 18 more errors)\",\n \"errors\": {\n \"canonical.opportunity_category\": [\n \"Preencha este campo antes de submeter.\",\n \"Categoria fora desta entrega: concessão, financiamento, fornecimento e outros permanecem indisponíveis. Os registos anteriores são preservados.\"\n ],\n \"canonical.official_title\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.promoter_type\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.internal_contact_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.sector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.subsector_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.economic_activity_id\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.location_mode\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.geographic_scope\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.locations\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.executive_summary\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.demand_statement\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.documents\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.evidences\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.publication_languages\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.visibility\": [\n \"Preencha este campo antes de submeter.\"\n ],\n \"canonical.truth_declaration\": [\n \"Preencha este campo antes de submeter.\"\n ]\n }\n}",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OpportunityTechnicalIncidentsTest.php:143"
+ ]
+ }
+ ],
+ "risky": 1
+ },
+ "prior_mixed_qa": {
+ "result": "passed",
+ "database": "opportunity_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_level_7_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "nine_sources_format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "app/Services/OpportunityTechnicalSupport.php": "dde836a4e0c1244b85344ee6fdb3e99af7e5849665701b74ba89592ff5ae185b",
+ "app/Services/OpportunityTechnicalIncidents.php": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "app/Http/Controllers/TechnicalSupportController.php": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe",
+ "routes/web.php": "24fdff12544570144f4a6955408ca22a9e249c9fadf68f8d733b81ede7b97909",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "resources/js/lib/technical-incident-labels.ts": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/components/opportunity-technical-incidents.tsx": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "resources/js/pages/profiles/technical-incident.tsx": "fc7cdaba8e5b892e61b03beedd1cf9377b723cf185cd2bcbaab1e343a38b1f58",
+ "resources/js/pages/profiles/technical-support.tsx": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0",
+ "tests/frontend/technical-incident-handling.test.mjs": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "174642a20b257b8045048ee986a69ae44ace04322073880f90396242c1de5193",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "8d1100fb70697ffde53396aa25e92d8d2e2d86fc5edd9289e77ae2eb103e0765"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-incident-handling-20261103.php": "c5749299882715fa8d4e7362ac1e349fdf47249303ff448f0d68c16b86ed06f1",
+ "storage/app/private/check-incident-handling-qa-20261103.php": "d53fb3d66f75a0b1ce9e5db2a3a9d68666466e8b2b7b08d0911a137c6df9b36d",
+ "storage/app/private/create-incident-handling-concurrency-qa-20261103.php": "c81f632b7b490c543273fa8675efb96ae6162175536149f54ca06908d6617b35",
+ "storage/app/private/verify-incident-handling-concurrency-20261103.php": "477a8c5bcca19368ed811b27bc904db9207d9b49337b9671ed14099b823c4c63",
+ "storage/app/private/record-incident-handling-20261103.cjs": "0e61bb6615f598c7e9b41846d03441c837262ade873cfeea8ad4f79ba5651e73"
+ },
+ "logs_sha256": {
+ "incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/incident-handling-check-final-20261103.log": "63bfb979c8f3956a70e03e61023ac3e758bb8b9ec9fbf14042df58c03ed024e3",
+ "storage/app/private/incident-handling-check-format-20261103.log": "bf36cc96fa632e4d12be2df656c47315332bdf5ccdfa6f44ce81d022bf7b7cba",
+ "storage/app/private/incident-handling-check-test-format-20261103.log": "468d6429fb773dd2f0e83f91a94e993ba68776db408ec0418e06630ecbbb2dff",
+ "storage/app/private/incident-handling-concurrency-20261103.log": "810e10d3478a4381472f0deee308a564ba008f9cd894c79bee589df7c89f2c13",
+ "storage/app/private/incident-handling-feature-initial-20261103.log": "ea30a1b715049bb44c92e04b8030ad348e73b8ae141960cafb7d004d4cd45991",
+ "storage/app/private/incident-handling-frontend-expanded-20261103.log": "36f16a7d6adb23d975752ea13c0e7fa45a1a610c3a7fc44d88c95cc1a8a40bbf",
+ "storage/app/private/incident-handling-frontend-final-20261103.log": "2a983956d27952f14693ad72702a8150c5d0222623476804be5bae62fd3466d8",
+ "storage/app/private/incident-handling-frontend-initial-20261103.log": "d0b896410d7038b305f05a935b070e79d365b2c61aa13a3a7d944e90bda16409",
+ "storage/app/private/incident-handling-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/incident-handling-pint-format-20261103.log": "a16141bb69c25cbd1310c757d8b9dd178c309cf3916c5e2f9f90ce3b6053a81b",
+ "storage/app/private/incident-handling-pint-format-final-20261103.log": "6ac9044aa54a9bd477156902583f33a2dfd7524d0969cac5d21b941e23c60071",
+ "storage/app/private/incident-handling-pint-tests-20261103.log": "d05142b987a6476f80c88e05172494522231ce0fa9a3db02032f05a5ba049fb8",
+ "storage/app/private/incident-handling-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/incident-handling-prior-receipt-20261103.json",
+ "sha256": "dcb9abae723d6b3e7a16f3c4609501f999531edddca10df2c2d0a5a57b70e511"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "8cb9afca629d92281a17a99e7dbcee5c4c9868d7608d7cb920ef5e3f5ff21a45",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "app/Services/OpportunityTechnicalIncidents.php": "c76caee675dc4f98c96479d84b0fee610b6d9b639928686ec3459acdbe0d5bba",
+ "app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "app/Services/OpportunityTechnicalSupport.php": "7d75c098849e231c54db7185beeca693bde56bf23c4b3fcf36eca0d2b2b505ae",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "321a0516510f545f03150a20f5f6a809be8fe863ce1efffe1b07bfa7406c75a6",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "96d73cb8ea2cc09cd2f5f1eeb8c3e66dce58e914f75013602de8673de54d9662",
+ "resources/js/components/profile-navigation.tsx": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "d94509ad57f74f887fec07469b12c4325938720e96aca322a63f28c023a8d6ae",
+ "resources/js/types/profile-access.ts": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "718cb7a8decbdc2845035276d62a4bbf0432bcf0fbef63ee8023d836950a2c91"
+ },
+ "prior_code_deltas": {
+ "routes/web.php": {
+ "previous": "8cb9afca629d92281a17a99e7dbcee5c4c9868d7608d7cb920ef5e3f5ff21a45",
+ "current": "24fdff12544570144f4a6955408ca22a9e249c9fadf68f8d733b81ede7b97909"
+ },
+ "app/Services/OpportunityTechnicalIncidents.php": {
+ "previous": "c76caee675dc4f98c96479d84b0fee610b6d9b639928686ec3459acdbe0d5bba",
+ "current": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074"
+ },
+ "app/Services/OpportunityTechnicalSupport.php": {
+ "previous": "7d75c098849e231c54db7185beeca693bde56bf23c4b3fcf36eca0d2b2b505ae",
+ "current": "dde836a4e0c1244b85344ee6fdb3e99af7e5849665701b74ba89592ff5ae185b"
+ },
+ "app/Http/Controllers/TechnicalSupportController.php": {
+ "previous": "321a0516510f545f03150a20f5f6a809be8fe863ce1efffe1b07bfa7406c75a6",
+ "current": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe"
+ },
+ "resources/js/components/opportunity-technical-incidents.tsx": {
+ "previous": "96d73cb8ea2cc09cd2f5f1eeb8c3e66dce58e914f75013602de8673de54d9662",
+ "current": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e"
+ },
+ "resources/js/pages/profiles/technical-support.tsx": {
+ "previous": "d94509ad57f74f887fec07469b12c4325938720e96aca322a63f28c023a8d6ae",
+ "current": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0"
+ },
+ "tests/frontend/opportunity-technical-incidents.test.mjs": {
+ "previous": "718cb7a8decbdc2845035276d62a4bbf0432bcf0fbef63ee8023d836950a2c91",
+ "current": "8d1100fb70697ffde53396aa25e92d8d2e2d86fc5edd9289e77ae2eb103e0765"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "413308aebb5417410d4a6f9a2197597e65a23a404d84e21655da168ea3f5be0f",
+ "public/build/assets/app-3dDpHpeP.js": "c25d89c9766aec79fcfaee617d59fd9209e13c659c761b58af25e484a373af54",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-draft-KXCC-PON.js": "efe416b80cb3193dfd394eca2ed0b7bf1c72517c6719c3a126a04f844a368c02",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/investment-territory-C1tzdaXj.js": "454b427892c1c2bbeeafe14aa4646e73862205bb9cfedd0bcf6020e8db831d0c",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-VLDr8qfP.js": "e0300425b9a11c550a69b81fd5e7f6b899e1c3439afb213fb08a7c43156208be",
+ "public/build/assets/territory-geometry-preview-bL9P_CZM.js": "292e39901c3931dca69b22f380ebe0a94d32134224183004ec196ab55e60dfdd",
+ "public/build/assets/interactive-investment-map-D8eE-r-w.js": "8d56511b2940f5a8410b38c977876398b1f14704ccd3575dd7514fa02a141e53",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-3QGErCo-.js": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-classification-BoQfr2Xg.js": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "public/build/assets/opportunity-search-filters-D2sQnQMb.js": "fcf7cda1f7a5fe15af8cacdafb4fef80049318560f34945108f7ac4cb6ac7f65",
+ "public/build/assets/proactive-investment-XdN3JLTR.js": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "public/build/assets/technical-support-Dg-ZQ0ws.js": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "public/build/assets/technical-incident-labels-BiFC6llC.js": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "public/build/assets/technical-incident-aGCrOhry.js": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "73051a57c960c9c161866607f6a465eb894f799112861482eefa0e82cf4445f4",
+ "current": "413308aebb5417410d4a6f9a2197597e65a23a404d84e21655da168ea3f5be0f",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-BBUKmvzc.js": {
+ "previous": "beb079355495fd49760f15e085ec7e90d7d3766810ad63d74d20aa72d105cf49",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-BRZ6u1s4.js": {
+ "previous": "a47701ae2c60873393008ad911c1e56b50e2627c3b20818ae19d215bc325f6bc",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-CBruj8Nl.js": {
+ "previous": "a105ba83135594116db29dc85c814f2c75e7273d46e5518c059a26a9da0b376f",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-CX6VnS3b.js": {
+ "previous": "4995ffb53d77617ffc6065d3e6601fd87b36e451f773cc2f0a2b63da5bedb768",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-D5j4bydx.js": {
+ "previous": "82570824d75b43cbb6b5cff78a772fb62aa9fa65cbc2881475fd0307951e6846",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-DW6UVqEU.js": {
+ "previous": "becd7d9d0900da7e25462c04d3c3357dafa8ad71de3bf16123398a483f0a9fc8",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-3QGErCo-.js": {
+ "previous": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "current": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-BoQfr2Xg.js": {
+ "previous": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "current": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-C6NFQIvP.js": {
+ "previous": "46bbfadf5df0e2174d47435ae6654028f733f97bf4de3c75ed7a8a91de8ba765",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-XdN3JLTR.js": {
+ "previous": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "current": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/administration-B8fo3qS_.js": {
+ "previous": "77ee0ef3e5722182ff7f7ed17f08e98651009f826cfd16718c951a9e815d2ab0",
+ "current": "77ee0ef3e5722182ff7f7ed17f08e98651009f826cfd16718c951a9e815d2ab0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-egXrkOyq.js": {
+ "previous": "04068f4b6744e0d8af69fc27f21ce8dfd6be2ed6fd771aac2d0dc6bda5689c03",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Unconfirmed note preparation is page memory only; not durable after page loss",
+ "Technical support never grants business or document authority",
+ "One actual concurrency scenario, not load or every interleaving; synthetic fixtures retained in a separate QA clone",
+ "Own alerting, other failure boundaries, authenticated installer update, delivery and browser acceptance remain pending",
+ "Initial mixed suite remains failed with explained fixture failures; current final scopes are 18 Feature and 28 frontend"
+ ]
+ },
+ "support_profile_installation_increment_20261103": {
+ "recorded_at": "2026-11-03T18:59:24.305Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 18,
+ "passed": 18,
+ "assertions": 230,
+ "duration_ms": 101840
+ },
+ "initial_server_regression": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 36,
+ "passed": 36,
+ "assertions": 569,
+ "duration_ms": 238086
+ },
+ "new_feature_cases": 10,
+ "frontend_focused_tests": 30,
+ "new_frontend_cases": 15,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_handling_cases": 15
+ },
+ "qa": {
+ "result": "passed",
+ "database": "support_profile_installation_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "operational": {
+ "result": "passed",
+ "target": {
+ "database": "support_profile_installation_operational_20261103c_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "restored": {
+ "database": "support_profile_installation_restore_20261103c_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "table_count": 190,
+ "sequence_count": 30,
+ "file_count": 1567,
+ "mfa_envelopes_readable": 3,
+ "table_snapshot_before": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "9594f769538aebed183d581491285c039227bbd55a3a0d97279a222bd9ef199f"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 104,
+ "sha256": "846bf2f9aab146256069b8e073862e0cb3f0be9f29dc833851bde11d36a8282f"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 1,
+ "sha256": "4eaade43d0062c019c8d00c34afdff4e41c7a2401967222efe6c28bbaca95301"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "468deb307cbc1ab6785bb7fec809c98128798378dfc33fbee789ace991e9a4bd"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 1,
+ "sha256": "7bd406edbde63602d41b4861b1b2d9d5e74e8c31186ba0c80a72b23bd6079410"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 1,
+ "sha256": "48c67bce2d217420f530f9f42840d58b8ba761e51c845fcd7ad74895ed0bb286"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "d7991d4bf39637023e7f38a41e1d49de4d519331ae72178db72b4201d895c294"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 3,
+ "sha256": "6ddffc7d51c8f4519ad28f25fc0513facfbd0c434406c5ed3bafb4d78a6179ec"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "table_snapshot_after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "9594f769538aebed183d581491285c039227bbd55a3a0d97279a222bd9ef199f"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 1,
+ "sha256": "ca5737597790331c304c84225e2d0b42127df7427e9e6d54b6b8a97ffa514ae6"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "48027acff5ac4bc70671d1db2d40404f61e010058f32b5d6a27e8c6921263a27"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 1,
+ "sha256": "4eaade43d0062c019c8d00c34afdff4e41c7a2401967222efe6c28bbaca95301"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "468deb307cbc1ab6785bb7fec809c98128798378dfc33fbee789ace991e9a4bd"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 1,
+ "sha256": "7bd406edbde63602d41b4861b1b2d9d5e74e8c31186ba0c80a72b23bd6079410"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 1,
+ "sha256": "48c67bce2d217420f530f9f42840d58b8ba761e51c845fcd7ad74895ed0bb286"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "d7991d4bf39637023e7f38a41e1d49de4d519331ae72178db72b4201d895c294"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 3,
+ "sha256": "6ddffc7d51c8f4519ad28f25fc0513facfbd0c434406c5ed3bafb4d78a6179ec"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "changed_tables": [
+ "audit_events",
+ "migrations"
+ ],
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "file_manifest": {
+ "private/synthetic-private-original.txt": "3b06a9c0852d829e6f7c853eb55212df7373b9fea0e1a2cbefda2557453775b5",
+ "candidate/app/Actions/Fortify/CreateNewUser.php": "caaaa98a8867c44ddaa45a1f58fd388f3b46f781d22cd9f8af67e292d3b82e60",
+ "candidate/app/Actions/Fortify/ResetUserPassword.php": "8ec7f8a74a7f30b729bf77578d1b6a9add3c48643c92d584f7bb69e5b81c0996",
+ "candidate/app/Concerns/PasswordValidationRules.php": "bc156c8d3556c45784ff6a319d02d7fb52ba2678ac4e4d6bf17d04861c4ebef7",
+ "candidate/app/Concerns/ProfileValidationRules.php": "274b9a825d140cc4a154f7ec816d368e1a9d7e8585158a70842b1d03415dae65",
+ "candidate/app/Console/Commands/AiBenchmark.php": "4e4c4b9b27abc0fa4bf3e747ff40dfffaa83c7c943c81c36fa529899ed4c75e6",
+ "candidate/app/Console/Commands/AuditTerritorialCsv.php": "853c5a180543d851de915bfdea81af159d153da7e35569b3802cb0771938fe7a",
+ "candidate/app/Console/Commands/BackfillMneCompatibility.php": "7ea719478dde2556b6653da2ea1a80d2db83a4cc63db953bf3a306d083bfbe8c",
+ "candidate/app/Console/Commands/CheckDevelopmentEnvironment.php": "fad049042c358686a71f327fc37eed20c2ea5dca179412855cca6dfaffb91062",
+ "candidate/app/Console/Commands/CheckDocumentLibrarySchema.php": "ba2345c60518c4a4c5f91fddfb8988ca529f75f0a8fe28a6a8606993be0e1911",
+ "candidate/app/Console/Commands/CheckMalwareScanner.php": "c2a3fe2b754b703a77cb506911ed028912bc0c7371fee26b78776a50687ab9e1",
+ "candidate/app/Console/Commands/DispatchInvestmentAlerts.php": "8c7c0a5dfa3b6c55ee4d9c0c748883b46c84cdc008b698ae702a753e11ae0322",
+ "candidate/app/Console/Commands/EscalateOverdueInvestmentTasks.php": "c09855a9919e6e5e686cbe751371e5a298a4d8e32b37724fd4b8146d8636bcb6",
+ "candidate/app/Console/Commands/ImportDocumentBatch.php": "e7bc2b3579d975d7e5c8fa750bbf19c569322567fddbab3838ff47e07095337e",
+ "candidate/app/Console/Commands/ImportIndustrialParkCandidates.php": "5dd60087f41b4c4cfa9083ad0cb8b91e11a3be3a9868928abbb1cadaa0db762e",
+ "candidate/app/Console/Commands/ImportInvestmentPortfolio.php": "a3b85f04b4cd4f8110391e480caf9538f03d79e5e77ebf820d9962086a31e0d0",
+ "candidate/app/Console/Commands/ImportInvestmentZones.php": "5442bf352b489b3fdb0991c0307f0e47134c1a0978d0bb6ffe5fd6e94e75afe3",
+ "candidate/app/Console/Commands/ImportLegalSourceArchive.php": "09cfec89c44805c96d1348223b124a7fb56137d17b8be7a729b17b424d97f9e3",
+ "candidate/app/Console/Commands/ImportTerritoryWorkbook.php": "b5d70a1287a4861fd9ec05056f896e01d712dd6f27982287c5c91148884ff500",
+ "candidate/app/Console/Commands/InstallFeaturesCommand.php": "d4322788cbaf54d35838519b16c874d05e8c24bd3cfb3e9f14af1767e19f9439",
+ "candidate/app/Console/Commands/PortalReadiness.php": "2371d25d75acd8bafdf8f4c9eb2e920bed44b14bbe01c13cf53ca8406f3f0ffe",
+ "candidate/app/Console/Commands/ReconcileInvestmentIdentity.php": "7974b6b9968d538d84efd4e8533ec8df439392c9d1c19451ad4e49852af0eb9a",
+ "candidate/app/Console/Commands/ReconcileMneCompatibility.php": "af621782870836180283e1ed5ab3985e62c8ddabc8328efff5c929416035d825",
+ "candidate/app/Console/Commands/RegisterFiscalQaDraft.php": "7f4eefd017509c353c11ce40c84ddbe15c9c1adeb43cb10bc79f8fda3d29ad73",
+ "candidate/app/Console/Commands/ScanPendingDocuments.php": "d28942e41f10b1a6649b284436acc364dac0205a646af4f6a07400d01b8f6a6b",
+ "candidate/app/Console/Commands/SuiteCrmProbe.php": "ac271bac3144c329bbccf2270bc4a01c9cf135c72bfbdbf98916c621edbc1a84",
+ "candidate/app/Domain/Interests/Enums/InterestStatus.php": "38347f9c0af8e5702f4c43119327f420d16e34e1056a42c6f4a2847eab737598",
+ "candidate/app/Domain/Opportunities/Enums/OpportunityStatus.php": "24a13cbbe6945ca39ba1a639dabe16f46f185bc2b29b7831b153c3ef9099893e",
+ "candidate/app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "candidate/app/Http/Controllers/AiController.php": "fd22c177665fae1785e75ce4bd526a9b16f37e5737ef31a616f2ab51b36169f5",
+ "candidate/app/Http/Controllers/Api/V1/HomeController.php": "5f961e97ab6b92de70c3dbe88b21dead5e75dd803cc314607ca331a0b6499bde",
+ "candidate/app/Http/Controllers/Api/V1/InterestRequestController.php": "e9da59499d3ac6ab39c3312d7505f9c80f95bd38579b5e4324d39c5936a5580c",
+ "candidate/app/Http/Controllers/Api/V1/LegislationSourceController.php": "07e48fda465501a0d1482149339c75cda1f98d38fb3b703f07d65a2f8ce416b3",
+ "candidate/app/Http/Controllers/Api/V1/OpportunityController.php": "15ebcfe75e0101e6434eac9272a92ced785a74185a0f4f10c2806fec2dff88c1",
+ "candidate/app/Http/Controllers/Api/V1/ReferenceCatalogController.php": "18134a6409914bf4b8c29a86ddfa10ecb0a20670a1f763598ef208438d0d3c8a",
+ "candidate/app/Http/Controllers/Api/V1/SectorController.php": "f35aa71dddabefb01376b6f45c4d1838bbd92ab86cada0eaf3aa2cf2e8c874d0",
+ "candidate/app/Http/Controllers/Api/V1/SimulationController.php": "90e8dda177075722a8f64d853feb3ecbbd5a0de555234ea3cb325406933edf25",
+ "candidate/app/Http/Controllers/Api/V1/SimulationFormDraftController.php": "b5c721e61956143d272c39a82f50b3defe79f3c7765a9abdf4637e88dd455d25",
+ "candidate/app/Http/Controllers/Api/V1/SimulationOfferDocumentController.php": "03e9e198050a7bd71861d109ca356709354c71cf6f9df10b90b0c8ce0821aff8",
+ "candidate/app/Http/Controllers/Api/V1/SimulationTaxParameterController.php": "9039958dba339b1e62926c445e3b27821416ff54b8a8ba736c3da30d13cc579c",
+ "candidate/app/Http/Controllers/ClusterCompetitivenessController.php": "12ab13860da1acda02dd77f38d0ddd0d1b8fca5856f7fa8823e9e6193143368e",
+ "candidate/app/Http/Controllers/ClusterValueChainController.php": "4048cbc7001f2794027f0800dc0c4c8615a1ed893ec30c8a781559b8b16f9bc6",
+ "candidate/app/Http/Controllers/CompanyComparisonController.php": "edfcb1fef24edace9de040fa413563f90572be3d33d13d4b54c114e2049f7802",
+ "candidate/app/Http/Controllers/CompanyPreparationController.php": "87d84329c83bc6dc778a4684c49ce413975e1d920bf622fdb124f430962c6c88",
+ "candidate/app/Http/Controllers/Controller.php": "25d1c1ef8e6cc8a376553faacfba2b07d9dfaee9bdbb84f14f77517580e9deb1",
+ "candidate/app/Http/Controllers/CorridorAgribusinessController.php": "3b2619b1a7f17e29c9b719ef4af700e43de36cacdb9751d009da52ff69ae9ac8",
+ "candidate/app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "candidate/app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "candidate/app/Http/Controllers/DeskRequestCheckpointController.php": "8b366844edcb686bd735aa7f91318460d32754286ef555d048267c0deb446a08",
+ "candidate/app/Http/Controllers/DeskServiceEditorController.php": "b56687e857d2f679ea1772ace493925ae811ce880bb1e81c56cbb714086b9aa0",
+ "candidate/app/Http/Controllers/DocumentMalwareController.php": "75425dd1fc27911d8587f121127ab08f0ae5e23edb4d2b6d55a97b8e9125efee",
+ "candidate/app/Http/Controllers/EconomicReferenceController.php": "bbd1a460d920f93e2c3b3f7eb11050f861106a2fa42535eba35d19d726bc65e2",
+ "candidate/app/Http/Controllers/EditorialArticleController.php": "db04f5f94e5ad23b2daabe2524e65001cd8bb4015c0de4e23ea86e255ba8cc3e",
+ "candidate/app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "candidate/app/Http/Controllers/EducationDeclarationDraftController.php": "0884d2b0eaeea60da4547c729c73373851256d6d0e1bf1ab5a3dc6582642c376",
+ "candidate/app/Http/Controllers/EducationInvestmentController.php": "30d16ae7db35dbeda19e1bb3ee90f374b0a045a431fcaffb616920c86f3f5d02",
+ "candidate/app/Http/Controllers/ExistingBusinessClassificationController.php": "42bae16c7e6445bf73328b0f8e2120c64be0f48fafa342108272dd862b9d1b93",
+ "candidate/app/Http/Controllers/ExistingBusinessController.php": "2638b2fc4fb3a3520a2c68f612c3efa4b0841f56cd4473be275b63ec5c132679",
+ "candidate/app/Http/Controllers/FundingProgrammeController.php": "bdbc975c23775094f0597e72d369f2ce4ab003a37950dfe2903433b3a1f0e781",
+ "candidate/app/Http/Controllers/InvestmentAlertPreferencesController.php": "619a5ba3578c94ec62fa60c56c587b0b31e5942ce70763035b115e19bbd0bf3a",
+ "candidate/app/Http/Controllers/InvestmentComplementController.php": "803e3e11dd8ecbb9a2db56623f6513091b6587818eab7db65fa8c70302a20770",
+ "candidate/app/Http/Controllers/InvestmentContextController.php": "1fb407368b4dbc6c65c0e8b7e6ab2609a2f61c5772d12a196c0eaaf7341a83a9",
+ "candidate/app/Http/Controllers/InvestmentCoordinatesController.php": "76e44c73f0ae73e8c5a0d4b625caaee8e0eb9654dfa7dd72e2b457cfb15f10ff",
+ "candidate/app/Http/Controllers/InvestmentDiscoveryController.php": "75192c4d10e4aeb9b6cd79394b8115fdf7f1e8577ce845f3a138a94d2a4eb944",
+ "candidate/app/Http/Controllers/InvestmentGuideController.php": "204e8950da9e90a9a87c4bef61a42cbf7f969a48a4084777cb35c1baff3157a0",
+ "candidate/app/Http/Controllers/InvestmentLegalSourceController.php": "0671ad4f0be05199fddb923e04529d0fe6c485895b0e6a8d6b01314cb57ed263",
+ "candidate/app/Http/Controllers/InvestmentPortfolioController.php": "ed07df8842d9ef559278f97faba4d5398747632ccad2312a736094f7d1762329",
+ "candidate/app/Http/Controllers/InvestmentRelationshipRepairController.php": "9b862cd953fb83d8aaba70cd01c40a9b8406552ccfa09dd5b599b5241f5402ac",
+ "candidate/app/Http/Controllers/InvestmentStructureController.php": "5ed3739d184cc023b6e6a54b3d5a99305ca88fc2e56dd49e4fca0e289e8245a2",
+ "candidate/app/Http/Controllers/InvestmentStructureRelationController.php": "a4f93c1a383a18b941e990e4b44289a73a4f2035b7704a3d145833dff1426099",
+ "candidate/app/Http/Controllers/InvestmentSubmissionController.php": "763f310dbdeb1c1a460b51f3b7ed1109aca81b9dd6e48dade1af2d90601ba575",
+ "candidate/app/Http/Controllers/InvestmentTerritoryController.php": "3b184c6ea1b97f0abe86d01567d3d73444c49192c638478a6d53619e63d5d18d",
+ "candidate/app/Http/Controllers/InvestmentWorkspaceController.php": "4714ddea4b6f0408599f8748f2f2668f604f18ee2a61852322932a0e2f306c30",
+ "candidate/app/Http/Controllers/InvestmentZoneAttachmentController.php": "98a2866083ba9696561962bb1a7b9a27701000d2f2bf2723ca7fd47b319c525b",
+ "candidate/app/Http/Controllers/InvestmentZoneController.php": "38f6ddd37aff8fda7eccee48433ecccd3498793d49221e61c016022d6e6a58ca",
+ "candidate/app/Http/Controllers/InvestmentZoneGeometryController.php": "cb38c92ae15c4f2410ef0472f3c82b492f724993c2c4945fdfe0b0ef90d8a7b5",
+ "candidate/app/Http/Controllers/InvestmentZoneLinkController.php": "1c1aa6c164489d0905b0ba9b5460573b436aeb3dd52da4b2aa5167f760da9861",
+ "candidate/app/Http/Controllers/InvestmentZoneRelationController.php": "0f2fb3e5917629dd453d30b525a041a034110eb2e72f0b3ee17d8495cec80694",
+ "candidate/app/Http/Controllers/InvestorContextController.php": "4e19aecb0871aa5c26102309d885b100a6734beb28e6e6b043074eb7f376c620",
+ "candidate/app/Http/Controllers/InvestorGuidanceController.php": "4aa1a8140fc80c9e34aaaccd7a41d3086b63e761c567c088928156d6a0d8b878",
+ "candidate/app/Http/Controllers/InvestorPathController.php": "7c7efecbbb0238f8143bf23d1d83e4ffdc43211d099188e0c6dae772cafdba85",
+ "candidate/app/Http/Controllers/InvestorWorkspaceController.php": "8279f05f55fb690df02470481187d81ac5fd213a8385c17e0dd4e97b7e2f4cb8",
+ "candidate/app/Http/Controllers/LandAssistanceController.php": "09832563c1b1f00c0dac84d49bc0a89118cbb8009be2a61ace6d290da410d065",
+ "candidate/app/Http/Controllers/LegacyContentController.php": "1af2a4e3b663b0bda3969c597ed1db4ce30b5c2e3a78d3d71a80f68cffc06bba",
+ "candidate/app/Http/Controllers/OpportunityClassificationController.php": "7befceff95da3e50fe635cc635f654897b94d26f3a0cddbd861251a5cdf18333",
+ "candidate/app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "candidate/app/Http/Controllers/OpportunityOriginReviewController.php": "4f00025abb2ea1d2032e13931b97c5cae2db8467c1d68c5489b47421e179da5e",
+ "candidate/app/Http/Controllers/OpportunityPromotionController.php": "32bdac22ad595a3be40ab99dd19d216683270bf4197373ead4b5c19884c8323e",
+ "candidate/app/Http/Controllers/OpportunityResourceController.php": "f83283162d7d643b3bda62f289962750dc05f2fe0ca474236db6ed95dd07f529",
+ "candidate/app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "candidate/app/Http/Controllers/PartnershipInstallationController.php": "350aebe2e4d6d57484716f5d3611f35dbead6da862a3693ba2307d854fe2347d",
+ "candidate/app/Http/Controllers/PortalContactController.php": "661fe0a2c80c88bde6b39318d53b64daf7809796502e34af8c7df31287740d35",
+ "candidate/app/Http/Controllers/PortalManagementController.php": "c6cd4569bde190edd730e8a8e528c3706a480d04dc2a92f299380a7d1f4084dd",
+ "candidate/app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "candidate/app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "candidate/app/Http/Controllers/PortalServicesController.php": "ed7c88674862385bf8497a02c2455aa0a71e4e1fab39468ad2580fe27cfeef21",
+ "candidate/app/Http/Controllers/ProactiveSupplyController.php": "298f060a82f042b789ddc03cb5abf70a99ebd14c2085571aaae541a677ad82b4",
+ "candidate/app/Http/Controllers/ProcurementController.php": "08c3604a4722096ee9d4baf6c4708b7517d04d3173cb750d2c3f9628f38fa626",
+ "candidate/app/Http/Controllers/ProductExperimentController.php": "ca422bbf440a684505205e6f9e8fe9e0d350d3df563fbe2c9998fc57118f4fb0",
+ "candidate/app/Http/Controllers/ProductUsageMetricsController.php": "bf591734493b64b6550a5f72b2230e054504f36accc607ddbb869aec7dcb5e4e",
+ "candidate/app/Http/Controllers/PublicBusinessOpportunityController.php": "b5d6cbdbb2031f50cb2ecd927247e4376661b72a71bd86b9bef382a41c868fd3",
+ "candidate/app/Http/Controllers/PublicGeographyController.php": "3dcce2bf9059c221b31ee0fe618dabe68c74043f24065841d2665e95e922611f",
+ "candidate/app/Http/Controllers/PublicPortalController.php": "43efa4a8f88545fa9833342f5ddfb08b74417e48a0866f779df42a26fba455f2",
+ "candidate/app/Http/Controllers/SectorReconciliationController.php": "d6455fef060a04cf7ccd997a1856ee2cced8f2a4d539ba83586ca9d56bb59683",
+ "candidate/app/Http/Controllers/Settings/ProfileController.php": "1155df036512d539d81dcf03a116bba07a411007d125fff060c60bde41101152",
+ "candidate/app/Http/Controllers/Settings/SecurityController.php": "de88a5e8594c9b03d55bf85a248231d1a148128ac4a1d8b7693847d6daa9ea85",
+ "candidate/app/Http/Controllers/SimulationFiscalSourceController.php": "1e20225fd73732f85f8d30c4e5e3680e5b409f6bd0022e700be8bb01448b34f5",
+ "candidate/app/Http/Controllers/SimulationTaxRuleGovernanceController.php": "cfaf90d67d09266d5cff439779f55c5b94dc96bf8c105a6f6327bcbef3f6a39c",
+ "candidate/app/Http/Controllers/TechnicalSupportController.php": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe",
+ "candidate/app/Http/Controllers/TerritorialRegistryController.php": "2e57b79332cec408c0c55afbdde5bc2167c6df345a16c05bcf71b0d7aee42ae5",
+ "candidate/app/Http/Controllers/TerritoryGeometryImportController.php": "44e7c64200103f58e87439a47042c02c619e0689c4a51202e5ef7e9b508db7c5",
+ "candidate/app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "candidate/app/Http/Controllers/VirtualDeskInstallationController.php": "9a7a7d04e78ebb44905511bf91c4b3409ab246491aa5e1bce8c86693efea7766",
+ "candidate/app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "candidate/app/Http/Middleware/AiEnabled.php": "f05236bc05eee01d9f1903f2274a1f9d6d915f4602076fcb54ee992719b3c527",
+ "candidate/app/Http/Middleware/AuditProfileDecision.php": "5e883af5fc3f16a51fbf16b61260a5ad70c182aa10c6f002fb5739f755e787e7",
+ "candidate/app/Http/Middleware/CollectPublicSearchMetrics.php": "673872c1290bd6dabf10c4ee601ea704396703780880223a0142d9c91eae3dfb",
+ "candidate/app/Http/Middleware/CorrelationId.php": "eec2fd36fd224e68226fdfd18c871c862b7cfab178934ecb1ae929a22280e890",
+ "candidate/app/Http/Middleware/EducationEnabled.php": "00343c9529e9e63e0f2ecd99ccdc6da7357c8c56008eae88c87f30da936b2824",
+ "candidate/app/Http/Middleware/EnsureDocumentManagement.php": "edc776dba4f246ce659f931928a819ab7d772745e965d6250335e68fafc4de44",
+ "candidate/app/Http/Middleware/EnsureHomologationAccess.php": "d61ef20b0a232eec9775e36a0b1d0d6851c8c54021c8046ababb5e7b73a0d235",
+ "candidate/app/Http/Middleware/EnsurePortalProfileAdministration.php": "eb87c0bc2edef22e66a39103c01b0e56e92a0e1800f92ef00167009daa8564f7",
+ "candidate/app/Http/Middleware/EnsurePortalProfiles.php": "b620dbc7ab03eeedd3c62fdf07324b47b5606b28cd585472a81d91224a4e1160",
+ "candidate/app/Http/Middleware/EnsureScopedEditorial.php": "7f962e1c86931f36b8af9b44be66a24ac8e619555d51aba926e50639e7c33ff9",
+ "candidate/app/Http/Middleware/EnsureScopedPortalAdministration.php": "cf8100f3d388e4f180e88ee2d5e6f7c113c0c02a596de2dd0e14037fa8233dd4",
+ "candidate/app/Http/Middleware/EnsureSimulationRecoveryCookie.php": "1dc683758aa4d7f675d5170fd715aca1794c9a9b838dedb30c644c2177707022",
+ "candidate/app/Http/Middleware/ExistingBusinessEnabled.php": "9e002d09f8c488ff4e09c2b2aa6c36d4705f71788d8bc3bc94aaf5e6e022b225",
+ "candidate/app/Http/Middleware/HandleAppearance.php": "0615a413bb12e39cb1c4a6baa93dfc2877c0988bfe31732d9e9cb8ef2b0523df",
+ "candidate/app/Http/Middleware/HandleInertiaRequests.php": "9190f8f68f377b9273c438fa26d3be281283665679752a8b97e2b2e8c82ec68e",
+ "candidate/app/Http/Middleware/PartnershipInstalled.php": "c3111eee7853dc492c55b12ef74df6780b352ab9941d664f5834f90baa1b0403",
+ "candidate/app/Http/Middleware/PortalProfileSession.php": "8359e4f205feabfbe549d0ad5cc60f551f2a4d42f6ea59b8094a65253ed94bd8",
+ "candidate/app/Http/Middleware/PreserveFormFeedback.php": "d056e6da373ebdcc7742970827a9c72c454cd635f60e5bd3ef45876a5f855dee",
+ "candidate/app/Http/Middleware/PrivateInvestmentResponse.php": "ef897d4dca11c968281bf5a4755a591a5b22766feb426ebdffc50c10fc5c8fdb",
+ "candidate/app/Http/Middleware/ProtectPrivilegedIdentity.php": "946bad7f4f57e46bbbedb9aded8e42c23b0496cdf88b6e68aeefcfc77f932580",
+ "candidate/app/Http/Middleware/ProtectProfileOpportunity.php": "bdadb19dda8003e573c3b98686b032da09f804e3465b247a9943afea47408af3",
+ "candidate/app/Http/Middleware/RequireZoneMfa.php": "5eec5a272f7b77386ccb9e991a27bea0345f9e23931970e29bb3c99d15e5d57c",
+ "candidate/app/Http/Middleware/TerritorialRequest.php": "c49c16e7ffd33025d3d94d6d87627474dda51f83181ea3b853716afefba92b60",
+ "candidate/app/Http/Middleware/VerifiedOrSimpleParticipation.php": "7f8a3cf33fe9af078e8e7ee51c119986e6a433e2165c5bf406499f404edb4be1",
+ "candidate/app/Http/Middleware/VirtualDeskInstalled.php": "a0a5d9b6123892b3b38313457415e73e6c9e4997cea8312adb215d60c45d188d",
+ "candidate/app/Http/Requests/AttachSimulationToDraftRequest.php": "51d9bb8027e7b3e2d3690aca4fb945da91da3b6dec4a65b23e5803cd2cd4090c",
+ "candidate/app/Http/Requests/ClaimSimulationFormDraftRequest.php": "a1bba65a18d049d3b9a0bf046864783e6b4d6b29ce1ef31826070729f5fb6461",
+ "candidate/app/Http/Requests/LinkSimulationDraftBusinessRequest.php": "7516a52c0daf533a267868bb5b066e7dca23f6562033f397d5c7f85746eb2b9e",
+ "candidate/app/Http/Requests/ResolveSimulationTaxParametersRequest.php": "633589ffa9e5eada4895901c99b71281440003cac598093b6e681f29ef575434",
+ "candidate/app/Http/Requests/Settings/PasswordUpdateRequest.php": "a32e9198f1e25363834ff12a1a7d1cc5ec0bcfda3f32cf1c1d03530315cf2bf5",
+ "candidate/app/Http/Requests/Settings/ProfileDeleteRequest.php": "f4d89321b0b482797c3fd5325f907ab4809b06ca3b60ffa8ea6d13540643b00e",
+ "candidate/app/Http/Requests/Settings/ProfileUpdateRequest.php": "846e47b3ad44f7d7cea00c6c6b5744552cb894e82e8f5ed5a9a7244a5c8b2c6c",
+ "candidate/app/Http/Requests/Settings/TwoFactorAuthenticationRequest.php": "ca9fb1252964deda922ad8dc4123650b86c07136f973f42bae4d103019b79b89",
+ "candidate/app/Http/Requests/StoreInterestRequestRequest.php": "a064fc0c71139b6ced9d209a490c1f339733ae9ad513c0128520b2942384eeac",
+ "candidate/app/Http/Requests/StoreLandAssistanceCaseRequest.php": "1b07eb06f9268f0a3f90c5055d3cf160ed76b09cec58b6542f1f1fe5db2c9eeb",
+ "candidate/app/Http/Requests/StoreSimulationFormDraftRequest.php": "61c79fd1735f54d8d1d964d521ec28613184e363dd07a95d619932ba30e9de68",
+ "candidate/app/Http/Requests/StoreSimulationRequest.php": "2b03bb7f16cadf990b3e6ff60cbb166fae408e340c9f94277f50c40d8da399af",
+ "candidate/app/Http/Requests/UpdateSimulationScenarioRequest.php": "c54d78771ad60c44320da0a50068ec62aab1c59833b20d83be2e376fa9b1ec83",
+ "candidate/app/Http/Resources/PublicBusinessOpportunityResource.php": "45f47177c6926d30fbb4885eafe5b66a3723ddc054818d5dcaa5e85ab6f5a9bc",
+ "candidate/app/Integrations/SuiteCrm/SuiteCrmClient.php": "fa2dd9e8bc4afcc07b49e8b27d1aa5594832b6e171b3d9f9583affc0b026115e",
+ "candidate/app/Integrations/SuiteCrm/SuiteCrmException.php": "a2a6c19e96b60a116fb882b7c35f2db5593234b77f5f5175427b2f2961b34dde",
+ "candidate/app/Jobs/CompareMneBusiness.php": "45789dfa3a98a640c74740b8c79cb2e7e3db99f8aa6a7168081ec26049131a0e",
+ "candidate/app/Jobs/NotifyInterestReceived.php": "2907eef3b044b19b15b9e4b3f05b4ebe1c7292e01a4452e2890f10a67463dd5e",
+ "candidate/app/Jobs/RunSimulation.php": "8aaf79277237e452bb19235c489fea7fdd3adafea7d11899f8db77ffed53a930",
+ "candidate/app/Jobs/ScanDocumentForMalware.php": "af4d1163ce3e3e0045a1f4a9b3e756208d59555249fb8412c37b825a19b5ad7b",
+ "candidate/app/Mail/ContactMessageReceivedMail.php": "619e10518436617ed1b641c495ef60bd59f9b985388ebe0aa474b3dec2e7e870",
+ "candidate/app/Models/AiRun.php": "4c466497c2a149cbf3614775b65e884ba9790e5a6ab350cd1c41f17f216f3a16",
+ "candidate/app/Models/ClusterProject.php": "f7a2b5addaea3cfdbc30828526a620e1de1762b3e4bfd8123a4038a2fbe0f309",
+ "candidate/app/Models/Contact.php": "83b482f1a35e0b2fe566e78bc33f0c8da228ccd560d0e61c343037c60a3e7fb0",
+ "candidate/app/Models/Course.php": "76d58938d2dc508259a19c92d9fa0315af8ec0f8aa66b7f92e4ba4e54790300f",
+ "candidate/app/Models/CrmRecord.php": "7a0ca250364f7c5ec676807df438b77f662cd85aa30ece274faaec279a517008",
+ "candidate/app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "candidate/app/Models/DevelopmentCorridor.php": "2143709560b929f38ebc479b85fb7308130566e795d7dc449fe551ce5664c985",
+ "candidate/app/Models/DomainRecord.php": "0bcbac4c31f8375bc8ad79e40aa3b53b862721ac2a22f15a26b4929eb8e490c2",
+ "candidate/app/Models/EconomicCluster.php": "e8460fc9acc4b3249693c7ed46fba46d365d869fe537aa12c74464087687fb71",
+ "candidate/app/Models/EducationInvestmentProposal.php": "50136e6ed9f8a644f70e492d625df5a9609ffe5b30d78578bc29e212dfff9214",
+ "candidate/app/Models/ExistingBusiness.php": "52f2f8c9a5a1b120b3573f0cbcecca9a33462b532b8b5e0e404f86874c18ec07",
+ "candidate/app/Models/ExistingBusinessMandate.php": "cc13c3a96db1acc980a0ef90fccac61d85c884bbc39f3ff0953b1595bacc58e1",
+ "candidate/app/Models/ExistingBusinessObject.php": "ae7d73fb1090723dc472cd0ad9ecb97bed6f10a07840ff89c2a0e55778808984",
+ "candidate/app/Models/GeoLocation.php": "de01aa587f6063b7de0b442beed98469eefa97ee4509e47ae83e94cf15b11414",
+ "candidate/app/Models/InterestRequest.php": "50c095520d26e779c670c5406b7ebc10f1659a35372af41f18b8731999ced027",
+ "candidate/app/Models/InvestmentDossier.php": "53737c61a7ed830b68f7ab1a2f30ac014896826494b7a1ef7d1821ca4c77d4ba",
+ "candidate/app/Models/InvestmentGap.php": "383da3cb1306b3b8121ea2a8d502f9c2ea368fe37eab5286be74559036240dcb",
+ "candidate/app/Models/InvestmentItem.php": "179743470b44baacc7609fea817ee11ea3bf6cb0bb779a5b9ddcbb3cf2dd5a9c",
+ "candidate/app/Models/InvestmentLegalSource.php": "f6c981ac9692eb2b7117985d9708756586b14ded428bf257f518ed59ffcdfa25",
+ "candidate/app/Models/InvestmentSpecificNeed.php": "e1a288ec8b869e255a9b5929fa853add36028beef334e7507dc08c973120a9fd",
+ "candidate/app/Models/InvestmentSubmission.php": "e220f9c88acef6302ecbbd7e4fe4f19e8f30356f0296c9d45a53dff8fa2936aa",
+ "candidate/app/Models/InvestmentZone.php": "a5e0f962af7dd4637000d0245e77ccf21130ad380bba5e653d96c2f9802183ab",
+ "candidate/app/Models/Investor.php": "4ee58768ddb5c7691b364bad04b497a428a10ff63fad4475b51ee081b148cb8d",
+ "candidate/app/Models/InvestorJourney.php": "5de09adeb944d94c360dbe2249980d35157127cc3550f054f01e85d52d5e65e2",
+ "candidate/app/Models/LabourDemand.php": "01d27f7c6527d7c0a5ee327920a702af55f790aa3a7a8c820e5a384c65a476f0",
+ "candidate/app/Models/LandAssistanceCase.php": "705ab9476f0e6859c0ec8df8e6e8ee1522b23d49f4084fb8d058b0b9524f69e9",
+ "candidate/app/Models/Lead.php": "732b38bcb0f28dd68cd86f47659c1dbf01d805f3fff2f97c32a233421bf6343b",
+ "candidate/app/Models/Occupation.php": "41143d001e01c4844755292480b9946c3d481ad545a2467c5c2c3716aeb990df",
+ "candidate/app/Models/Opportunity.php": "e0edfd3c37306f6d95926b3423394122d503b3434f16decddc7138ea6e4a8b64",
+ "candidate/app/Models/Project.php": "ba2c5caa85665eaa4118822cfe439b737cf5ec1230e33310146d463354a01564",
+ "candidate/app/Models/QuestionnaireVersion.php": "83ff9cdacbeda3ffda4d241f837c0048c2bcb977dd8d5a033c40bb0da9891f20",
+ "candidate/app/Models/Sector.php": "e6ead442de335d991ded80184796b1def53b9bfd5c9be525628602cbe778b3d4",
+ "candidate/app/Models/Simulation.php": "9a3b23497e97b6b28a4dfbf85a19f87d367d2fe67d6115986904d3b89edb6cdc",
+ "candidate/app/Models/SimulationFormDraft.php": "bef40f3f7bc1d6a6ccea1f6c3ef038e4e60a4681375db1dbcb12fa407e17bfbb",
+ "candidate/app/Models/SimulationJob.php": "7029fe77dbe5290b8fb586f6f8340b6c8365d6176adedb88bce6e94460029c32",
+ "candidate/app/Models/SimulationObligation.php": "1524b2eb97974b2c5d070c51f59c65ec91dd06d937d5497954f96d3d4b7e0b52",
+ "candidate/app/Models/SimulationReport.php": "bfc911113a22c908b23e3a32219e88ab99d1528004fda99f0d45229498ee1b7b",
+ "candidate/app/Models/SimulationResult.php": "2f5f4d9c60aa8e2291c214433bb36b0741ca7738cfd47d6f6aa749d54e5cfdff",
+ "candidate/app/Models/SimulationResultSource.php": "e6a95cdf0805e04f260aaf5b0639136336ae9b52028106113b2dd604d1ec3082",
+ "candidate/app/Models/SimulationScenario.php": "7c79aa8acac92a5f3f3d9e44ec644131fd8ca0bfe84140ed8b53e61619259a1b",
+ "candidate/app/Models/SimulationTaxRuleVersion.php": "e13f1716d7ab41815062f715942075ac2df879380d9c67319354d96bd2ccd46e",
+ "candidate/app/Models/Skill.php": "180c87130ba86153cc7099922b03000f69e2ab761659d83a5a159c17d4813b40",
+ "candidate/app/Models/TrainingCapacity.php": "70dea08b17c70c36db37f11726026cd56cc8f6bb04eaa3808a7a0c8d72a748d0",
+ "candidate/app/Models/TrainingProvider.php": "6d556bfbdd242501d3e664726b52431a59aae9dbf5a21b5c666c0f9703a7a3b3",
+ "candidate/app/Models/User.php": "63f950a46c8dae576f1f8ddb236d3b7176f4f7c9b18b7736de9b26d4ba0aeb76",
+ "candidate/app/Models/ValueChain.php": "3890d84bd4f7eb83738c58087dc1a8a3ef98c2359a37a16a348b75c2f8c34b40",
+ "candidate/app/Models/ValueChainLink.php": "64429a190ecabdd5688fc1e4db033adea5e9ee76caeddfe62d547e8107c3bda7",
+ "candidate/app/Policies/ExistingBusinessPolicy.php": "cf015b50fa5e1b6fc5103ce68469aa52a6fad07d054b76da412e64c62af36d4e",
+ "candidate/app/Policies/SimulationPolicy.php": "681b76ca9fc717140a5c5a243a7bc16fbb66ded53ec973859ff03b89f60cafb6",
+ "candidate/app/Providers/AppServiceProvider.php": "9b2b34ccb70f6947ed86e72cbb452f88abb838787bae79228c88c41bf2a09d18",
+ "candidate/app/Providers/FortifyServiceProvider.php": "0e49420e8450835e31b6c765343f40deea8f5d697471c330655c581c112e378c",
+ "candidate/app/Services/Ai/AiGateway.php": "ddec947af17d966169a2337f5f2d68f2bbb2bed32978c9391a1c01fd3758632d",
+ "candidate/app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "candidate/app/Services/Ai/EvidenceRepository.php": "19561a952f5af8420089271b102514e40ca7f99d6ea18c523d7cccb2b304c7b3",
+ "candidate/app/Services/Ai/HybridFusion.php": "4dd8c1575a88163636abd517ff92c2f50ac06ba67e3f3d216c52b08a976160f3",
+ "candidate/app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "candidate/app/Services/Ai/InvestorGuidanceEvidence.php": "795e3aa445b0acb02ac992adc63fd5626ea5b4cc464d68fb69294b7db8433c14",
+ "candidate/app/Services/Ai/InvestorGuidanceRules.php": "91f89953ff484420c2f78798a6048f231f4ad1adf8ef3907924621b787a6c78c",
+ "candidate/app/Services/Ai/SourceIngestion.php": "39518ea510a4b95b587558505967d07a22593f27e1b88b3817627a3f7f431da9",
+ "candidate/app/Services/ApprovedAdministrativeBoundaries.php": "401fd62795ca8f33106be6e07130d9207d6661695440bfc40f62f6f6b42bec64",
+ "candidate/app/Services/ApprovedAnchorTerritories.php": "d99be7045dd672d84b006e6b3c1e6fcc220456b9df8dff1560ed0054aef6a8e8",
+ "candidate/app/Services/BusinessFormSchema.php": "97ce5b2d62aa101a77dfb3b688046d0ba22e6377f4864aa99a0ac6326523bed4",
+ "candidate/app/Services/BusinessPointPublication.php": "16c23999131f397ae07d1e7ff287d61d836a0ad9b417266f7f065605e3c872a6",
+ "candidate/app/Services/BusinessProximitySearch.php": "a64e8ea02b3ae541390002c77bb68e506d72f6b508846c386433ca7fa21c89d1",
+ "candidate/app/Services/CartographyWorkbookAudit.php": "18186dc62542e653487f729775334ddfac0afdf9e96bb2c58cdffd691b41e95b",
+ "candidate/app/Services/ClusterCompetitiveness.php": "ee406045ae09204793eb0fc775f547f38f3d89ea6eb1f318caff0074112bc958",
+ "candidate/app/Services/CompanyComparison.php": "a165bc22c92cd825a02f83d07a862239a594442ee65e907ba67745f907df8906",
+ "candidate/app/Services/CompanyPreparation.php": "e473813b4abffeb02c5a2f0f86f77afb9c225cf3d5d444ae992938e6129682b9",
+ "candidate/app/Services/ContentManagement.php": "739c9f67404540611ce0490f2445e2a52fba6463aa7dd28bf2571df7c8be1064",
+ "candidate/app/Services/ConvertInterestToLead.php": "b1c75250cbacc4f3f92a3815f8a78a5b9e8cc8f5635c617674dd169d2cf4639a",
+ "candidate/app/Services/CorridorAgribusiness.php": "ed57f9788198a2c6615000e6a0a72d1116806375e5f6a8199e8e57c507bc1046",
+ "candidate/app/Services/CorridorAgribusinessOpportunities.php": "2b4544ad45b3f9431fbab985b150ee8060ba246a291075a5942f8f9038b6066b",
+ "candidate/app/Services/CountryCatalogue.php": "0d2a69a3fe30225d5eb0d881e5ddd81d5afc42a28413dc3e855a79e86f92f87d",
+ "candidate/app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "candidate/app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "candidate/app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "candidate/app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "candidate/app/Services/DeclaredOriginStatistics.php": "ac88d0e61eaed8f66c6c46749bfdc5c5e3445ef6fb864db20999be236fa7e13a",
+ "candidate/app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "candidate/app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "candidate/app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "candidate/app/Services/DeskServiceAvailability.php": "7ec1e41f2f4ecb9c00501a5aeb47248012e44663d7f5772df17128b990d9b12f",
+ "candidate/app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "candidate/app/Services/DocumentManagementAccess.php": "ea5bf6297100892ce7450bcf54a742cbba82e8d583820793fb03f67da68aaf1b",
+ "candidate/app/Services/EconomicReferenceCatalog.php": "2b30c4b666e2ba470d3b7a184f2c16a21b4ba083d9cd989205ccc3899251a0a0",
+ "candidate/app/Services/EconomicReferenceInstallation.php": "e707f5d092f9ed26ab2015f826e7d121a35efa321b4f3f149ad999fa89e86ad7",
+ "candidate/app/Services/EditorialInstallation.php": "e360f61ac7106c65d2b40a36918bdce659f915e74f95570010386e4c16f60a0b",
+ "candidate/app/Services/EditorialReading.php": "76c9dd157fd7d35ad2419c6ed8671fef8f81dc8677a196b8fca56b2e71715b5f",
+ "candidate/app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "candidate/app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "candidate/app/Services/EducationDeclarationRules.php": "3342de5086b5e49a75682ec1eea5827afcde9f94ad30b8cb25d04ded94488210",
+ "candidate/app/Services/EducationGapCalculator.php": "7cbca9c8cb6b03d97866a368cfa627ec1f0351e4761a1aa2d00f29d2b383292b",
+ "candidate/app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "candidate/app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "candidate/app/Services/ExistingBusinessClassification.php": "0bed4f5898507afa3bbfaa09a44c5b3a284297f3bd4a0e53a309b82cb91b9e48",
+ "candidate/app/Services/ExistingBusinessDrafts.php": "ab22dfb444b4ed363622a998af960d09c6f2e993fc8f484e23e80a653d2e71f7",
+ "candidate/app/Services/ExistingBusinessIntake.php": "a46d9ed56bb240f59ae40afa2236784d945bf635c5a142d92152ac0195b3aec8",
+ "candidate/app/Services/ExistingBusinessObjects.php": "0ccb9a9fd8b0c2b4c5e940a0dfe37a0f1cbda70c3f2c10164ad8a7a63f6e7f16",
+ "candidate/app/Services/ExistingBusinessProfileCategory.php": "efcad82ec2ca6ff2a3234bac85af6f5a05fda73b2c42084c0287d266c4e59c09",
+ "candidate/app/Services/ExistingBusinessVerification.php": "ac444e2bb74703aaa3bca1b2141f4079aa44e0282c22196dc587c8411729fa53",
+ "candidate/app/Services/FintechInvestment.php": "28f90e822ae943c92460cd6a609462914588aa0869641ac44d5f87d5ed9d1252",
+ "candidate/app/Services/FundingProgrammeReferences.php": "a479ce5b645f6b48f2df412c9bf2bda77db1c89d28528e887812f264750eab25",
+ "candidate/app/Services/FundingProgrammes.php": "6f2f0db08ebf4443243ea282e7e556a92f86cc64dba10012dfcdb76cea87c510",
+ "candidate/app/Services/IdempotencyConflict.php": "0cf235eaf05f75eb8fea94c5dd024fdcb9053f52c93e6e8cb0d9d98e0bfc490d",
+ "candidate/app/Services/InstitutionalLinkMonitor.php": "d72d6d0d0017bd0d085e59cd324e0986c3696d73a854489a4b6fa12cc81bf544",
+ "candidate/app/Services/InterestSubmission.php": "47b561d0d52d4990928d2eda84faecb3beb8b207a2ec7c07b01068177961730f",
+ "candidate/app/Services/InterestWorkflow.php": "8f1c6d7df1463167a47b0d4f6e2a8fd7d889997d6e0aefd6fac9344fc7dc222a",
+ "candidate/app/Services/InvestmentCatalogue.php": "ef4b28fa8dd060f8b420437aa748a5bba7a184864e2e86dc128881e85caca6d5",
+ "candidate/app/Services/InvestmentComplements.php": "90bcdaf08b644a79ef692ac66ad0d5b7ca32c415e3496ad7f8a746fad2c7cab4",
+ "candidate/app/Services/InvestmentConsumerScope.php": "b63dee74f0720c197e4a2cc8d1ab64b4ef99d6cea7b1af9b5a6b94aa3fc88719",
+ "candidate/app/Services/InvestmentContextRequirements.php": "29c9ae28b81983da48261993421c6bbbd93654f077ffca4aa8de979646b3f35c",
+ "candidate/app/Services/InvestmentCorridorContext.php": "7d3c66c1511c07a851a798667b5251e963960b072033131f89140c8908a52cc4",
+ "candidate/app/Services/InvestmentGeography.php": "a5b6f43422c68c1d5eaa955f2550a4e99eec5f805bf0898744701d7c0f3e4ec2",
+ "candidate/app/Services/InvestmentGuides.php": "7dace026a5793118c8b222612c6a79d76241f8fb5d7a6e1af1c332902236413e",
+ "candidate/app/Services/InvestmentIdentity.php": "368ee3f2788b1011473c652dabd9c66618afadeb5463c606a2d8ef781fb3527f",
+ "candidate/app/Services/InvestmentOpportunityAlerts.php": "9669b494961c11189688e42d4a3baa4ccf225489c93073234a08047d628e669c",
+ "candidate/app/Services/InvestmentOpportunityChoices.php": "5c590379543ac53f23210287dee62be3ad1656c6a240e602385bd5453c6105c0",
+ "candidate/app/Services/InvestmentRelations.php": "436e2e0e886741ee7e6440a447566f5c1ab0e9cad7e8fc88d298a5682bc2b92f",
+ "candidate/app/Services/InvestmentRelationshipRepair.php": "82c6496f504437ea32981ea04755238d8a9f55e0316e94117de2c9cf87b46c14",
+ "candidate/app/Services/InvestmentTerritorialTraceability.php": "4bc01f49f97a1089f88f46ef143ddcab931931a8d4510f03bcf8e3d487f63fc2",
+ "candidate/app/Services/InvestmentTerritorialValidation.php": "72de2f379db8fab7e40204d7e05ab971363a6f3e80f0301d73cb61e2588657f1",
+ "candidate/app/Services/InvestmentWorkspace.php": "14437df3de66344d4d6276132e3b8ddd43c82b4f0582e8fbeec3a65aeefe2a21",
+ "candidate/app/Services/InvestmentZoneAccess.php": "18707c3b5d69cb44a000632b982b3aae3e185f69a077d9a268086b3a8337f8f1",
+ "candidate/app/Services/InvestmentZoneIntegralDetails.php": "7aaa7d7cfa3283e5feed3ec509e7a98b4d218718a04ebd8260eba9e840011cfb",
+ "candidate/app/Services/InvestmentZoneOperationalDetails.php": "063be8e28e2f1972349a3ca21229ec81249467d119ae51bbc8b4c744ac84fbc5",
+ "candidate/app/Services/InvestmentZoneOperationalDetailsInstallation.php": "7f6fedb83cae71844359ce7f5cddb1e625c885cfe92c6936dfc2a8a3cda91f84",
+ "candidate/app/Services/InvestmentZoneOperationalProfile.php": "e85be43252cf8a162944d82602e05509b8477c6f37719d3de7d6f4bd5c6b7623",
+ "candidate/app/Services/InvestmentZonePathContext.php": "b5350271ad639923c50e1db125f29c5464e495cc060a379b4a663755260712a9",
+ "candidate/app/Services/InvestmentZoneProfileInstallation.php": "8290adc7023aab82b8e90203ab24520b59d938a98e7e0706c497ba9b18b63ae2",
+ "candidate/app/Services/InvestmentZones.php": "5a7f98a798c85abeba872d278818cecafeac860d366d65199e6bdb137fe03b4a",
+ "candidate/app/Services/InvestorContext.php": "c27cd1dcce765cadd09de5b11f0952cd87a76e3e51dcb3f12a0969814bfdbaf3",
+ "candidate/app/Services/InvestorContextConsumers.php": "73f3bcbb7623a54c12a538c57d4af76cb119c01b10720fb8fbb5c8f7ccf0e05a",
+ "candidate/app/Services/InvestorContextInstallation.php": "d6aa42e8b9f55f5989a84abfc5484ee3b01f3165b093cc61531a88f7242ace31",
+ "candidate/app/Services/InvestorPath.php": "e5c4648e380d5e30035ddaecaadb70f0c6a84558b1a959530029bba8b97c6b4a",
+ "candidate/app/Services/InvestorPathDefinition.php": "288b43cfc27a665a9b9dc9d4630e24bca84ea72c02dcfc0ee9093be7382a1ec1",
+ "candidate/app/Services/LegacyContent.php": "1538b0190dc638faf5aaa212d7d782f68911cdd84ba80073b2376e7237645296",
+ "candidate/app/Services/Malware/ArchiveLimitInspector.php": "9b7efc0aedfd07806a926efe71fa7aa462d62f5922c871fa5799dcf8ae953693",
+ "candidate/app/Services/Malware/ClamDScanner.php": "4bdefa6dc8727653e8e7a17bf135855319f5aa3d5c33e49845129be606a43a2e",
+ "candidate/app/Services/Malware/MalwareScanner.php": "162edca81f840dda27c515816e959b867a47f4e7f566f41d63c4540f56db3fc9",
+ "candidate/app/Services/Mne/BusinessRepository.php": "b5ff5a6a55bde93258b443f3e4fe3ab940c89fee88c876de2fe30b499f5779a4",
+ "candidate/app/Services/Mne/CompatibilityBackfill.php": "25b6924f62fcc88fca04e3ae3d8c77e3413c3360dd9ae5d3caf11b39195adba9",
+ "candidate/app/Services/Mne/CompatibilityShadow.php": "654fb448354a17a740f1ec841ab65d31608c52b6a890eadc8ff043c6acc690e3",
+ "candidate/app/Services/Mne/CompatibleBusinessRepository.php": "9ea93e7ae7e7c1c5f020530cee535638a1da5ab57c3ab612561c0bb4ff617937",
+ "candidate/app/Services/Mne/IdentityResolver.php": "2736710cd35bcb795ababb22a7d35ab2b34cc68cad0c2c04c01dab506a1ecc42",
+ "candidate/app/Services/Mne/LegacyBusinessRepository.php": "37cfc6a7704e8221c3526dc380ff6fc0aec474067ce70d8c2c970d305f7fe85b",
+ "candidate/app/Services/Mne/MneBusinessRepository.php": "f763c296cc4106c4d791d35e6b862b847b9d8e44d26367d4fa95d4c06a7dbdcb",
+ "candidate/app/Services/Mne/SectorResolver.php": "2394b1ed6176552cec05fda7e239f17217e46c57948cbeda037189184d0b964d",
+ "candidate/app/Services/OpportunityCanonicalContract.php": "d6b2b683dc75f9c396943e48cfbfc7e3c935913e8b29a13bb1a627df201c7ad6",
+ "candidate/app/Services/OpportunityCanonicalMetadata.php": "b620420f8d53bef285e271a615f8697efcdb01776346962a89b814714ca70142",
+ "candidate/app/Services/OpportunityCanonicalResponse.php": "060c43b0bce268cd8a6440e4f9bf30f41aa5aec0c971a95748bee5d6cb26ee4a",
+ "candidate/app/Services/OpportunityCanonicalValue.php": "1487d91443baf3d892d755e86d5def44185a42069132e6fe48cb86b15cc08353",
+ "candidate/app/Services/OpportunityCategoryFields.php": "d7d294c72b7c416bd91726e7d7e2a045968e85d62ddaf57137da921e0340f25c",
+ "candidate/app/Services/OpportunityClassification.php": "799a94b8bfc246a159ca17cdc77f3e21acdc7ad5ed68f10997d3cb062e2c2072",
+ "candidate/app/Services/OpportunityCompleteness.php": "1497712c221332e5f879205d94470c5cbe657d543565a99f08eee4543da0ddfb",
+ "candidate/app/Services/OpportunityContacts.php": "fde857229144c20b6f50964a72ec999db95ab4792a0450ce047cf0b6704fe50c",
+ "candidate/app/Services/OpportunityCorridorExplorer.php": "20cb16420c83191ef7b1b58b71f84b1a77dd3b204591dbc55628456f909d50df",
+ "candidate/app/Services/OpportunityImageProcessor.php": "f85be0b520ca9b743853a3e5d3708e9bd06f19c53329462b4c0eedc4c0384576",
+ "candidate/app/Services/OpportunityInitiativeApplicability.php": "d8b768134936b264209183d84843e7559a56cde46f5b0573dfb0ac3face86b70",
+ "candidate/app/Services/OpportunityLibrarySupport.php": "3889e21998128d89eb198dab389ab2d6ca58435d9afbeceee7c1595879630255",
+ "candidate/app/Services/OpportunityManagement.php": "bf737e8a379794b2ab0c8869228ee51df0f92609ca6f5e27857bcf6f57354c1a",
+ "candidate/app/Services/OpportunityManagementInstallation.php": "6e21c7b0dcacc775d2c8dc9ea9daee9281d83059ffd3fa0a4a4c427aee6f3c20",
+ "candidate/app/Services/OpportunityMaturity.php": "62bfdfbcc470c66142ceb30356f33daf6a8f9777783e6c17e9fbfa0b070ee481",
+ "candidate/app/Services/OpportunityModularProfiles.php": "cb986c24a03bbc4722340f2a3a1392c1c334445c06ad6f725751afb588d79eaa",
+ "candidate/app/Services/OpportunityOriginReview.php": "e3c7061ff0d00ef064bc26a94e2adaea0cdfb146de670b8c70847561593cc35b",
+ "candidate/app/Services/OpportunityProfileWorkflow.php": "77cac85d66bbb9669eb9da65d34c0ec57e77ceba4b6b85c9d7d7e85329d562bb",
+ "candidate/app/Services/OpportunityPromotion.php": "f49cf47686b21653ad9740cb79b53101f46475b963b6625e36475dcda1cf45f4",
+ "candidate/app/Services/OpportunityPublicText.php": "70b9206d110ccc831b69dec81dcc0d486e8a8a18aae9b04b726fe901731e74dc",
+ "candidate/app/Services/OpportunityRealEstateDraft.php": "b03dd6401c23c09353ce64c4f198c9e6503bad55d5267776f508aa263975fc11",
+ "candidate/app/Services/OpportunityResourceInstallation.php": "791b17af7e003ff25160e6487341d7c6195a07fe47438435f4c5b0f052ffd7d5",
+ "candidate/app/Services/OpportunityResources.php": "cf3baa0e5592f0b039189877faca514c62db65ae2e2bd634b5380c74f56ab412",
+ "candidate/app/Services/OpportunityReviewConditions.php": "0f4362a347eb1b8a4a95b05c037f0180ca40e76793bdcbb9eae51226861fba41",
+ "candidate/app/Services/OpportunityReviewMateriality.php": "88c8d046e4bd443115f497aecc507d8b2a3774a551ccbfcc3ed2364d428aba79",
+ "candidate/app/Services/OpportunityTechnicalIncidents.php": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "candidate/app/Services/OpportunityTechnicalSupport.php": "0c4f0cb1e087de63bb69c8e2c2941c9ee4d1c8a1e17eb38a27ab14541eee1490",
+ "candidate/app/Services/OpportunityTerritorialPresentation.php": "44d70cb65f0e668ce7fba49160e177bd3932902f64da52ff7a64ae220ccbea26",
+ "candidate/app/Services/OpportunityTextSearch.php": "5db4e6abe69be0b345c4bc81c5243b6278993f883dc38a5ae1a279fa13e44ab6",
+ "candidate/app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "candidate/app/Services/OpportunityWorkflowTasks.php": "2f9fb22446e535adeaadce24ba25fff7e5d9b1c240c9639d0e75b5bfbeef58d2",
+ "candidate/app/Services/OrganizationCountry.php": "cdced1699c1fb33db8d3001b801134c3e9ad954b71b045b04426370f90e14ad3",
+ "candidate/app/Services/OrganizationCountryInstallation.php": "fe7ab6843cb16c89e794ee23439bd322b55dede71c8ba15adc0e56f51ca8afe5",
+ "candidate/app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "candidate/app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "candidate/app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "candidate/app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "candidate/app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "candidate/app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "candidate/app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "candidate/app/Services/PartnershipInstallation.php": "54fffd68e38a5e3b15c5ce37d1f8079e70e52f3a773b11698a34dc994e1c847d",
+ "candidate/app/Services/PartnershipMatching.php": "47e3a82b816a5006862e3d787b4d7b0445745f2d48dbe75391757abe068c3c1c",
+ "candidate/app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "candidate/app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "candidate/app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "candidate/app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "candidate/app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "candidate/app/Services/PartnershipSources.php": "6f2b77169ea6f957223fef0dc5cd3dc95124032ac9a7c03483ec4fe2f2639a89",
+ "candidate/app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "candidate/app/Services/PortalInternalDesignation.php": "49efec80e265ceb9dfc2a45b0372101cbc086b41c4a1349c5cf8311adb78fd5a",
+ "candidate/app/Services/PortalProfileAccess.php": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "candidate/app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "candidate/app/Services/PortalProfileInstallation.php": "607281f4294c776253607a1c8d60a3f51f632b399922bf08f4610380e0847096",
+ "candidate/app/Services/PortalSuperusers.php": "48e62eb89155256b8709e3935f9f31893bdf04ae3a28397703dc292925c42c61",
+ "candidate/app/Services/PrivateInvestmentPreparation.php": "74502527dc6a1d04baf95ba2f04707891c6440cf212fdd050f037b388d2390e6",
+ "candidate/app/Services/ProactiveInvestment.php": "3d0182e75c77984aa5e78df10ea898f514ec56aed23896da4c0afb8923567212",
+ "candidate/app/Services/ProactiveSupply.php": "a65d7d5022d050e62e5cf018929891ad32aaccd6ae46aab85f7989f59d97b25c",
+ "candidate/app/Services/Procurement.php": "68f11711167ea92c43479db92981cb78130f043a45db985a2de886528a257c76",
+ "candidate/app/Services/ProductExperiments.php": "530adc81a008442dbbd473b5b1d750daddd2bbb6979354b3e85de2f1c4a21e55",
+ "candidate/app/Services/ProductUsageMetrics.php": "f78b6210e63bbaa64003e5cad29906847be81c194c2aa84748cfa081c6606235",
+ "candidate/app/Services/PublicBusinessLocations.php": "bdc91b9f5c813245f064fcc3635ce3b467d46f404443666959bdc650784f8ed6",
+ "candidate/app/Services/PublicDocumentPresentation.php": "e300ea55c42e65c24f68f511a27d0065f1aa1e0f14e221cac0fcae81ae44c53b",
+ "candidate/app/Services/PublicSearchMetrics.php": "09730864ec8999abd994603987e8315e88db148dc871e9ec092384d5115162d9",
+ "candidate/app/Services/RetainedGeoJsonCollection.php": "f22f3779b43594b581b95ad94b6899871eb47de0cf90991f9cc67ec8a0a770f5",
+ "candidate/app/Services/ScopedPortalAdministration.php": "b138edf2df64122749128fdd0f84aa2f4f996fac674881e50277f6520cf1ff84",
+ "candidate/app/Services/SectorInvestment.php": "d1dfeb099879a41f2c62d3eb580660be1dabfc2d99ac2a041b83173bcbd9eed4",
+ "candidate/app/Services/SectorOrganization.php": "59c77373572d742b1c844afdea83a4dcffab280071e931b52b69467137aa5bed",
+ "candidate/app/Services/SectorReconciliationExecution.php": "d4a413fe866d241fd6e6c8b9d0854509a3c835a7257c6cccf45daf020b6f96ad",
+ "candidate/app/Services/SimulationExecution.php": "ca2fa6a4e997920b5d5cf0f41649e096e99a7ff30554068e6e45546c8b4c6bb3",
+ "candidate/app/Services/SimulationFiscalQaPreview.php": "5f4e778bc171a6c4528812c03f32c240164ff9943bec02b2c31c1c9ceb156a74",
+ "candidate/app/Services/SimulationFiscalSnapshot.php": "7dcc7d4f30c95fc30aa4fb73d771ed74e9ca8be30ae5fa82d8e310e565e0b24f",
+ "candidate/app/Services/SimulationFiscalSourceAcceptance.php": "7bf1c5deadafa59d37209236cf446a6686e5724a21aa0c154b9eab30f783c620",
+ "candidate/app/Services/SimulationFormDraftPrivacyPolicy.php": "997e4402b7cb322b0bf322f9074c5a3f391f97e1d9550cb65069705f1f78ec74",
+ "candidate/app/Services/SimulationFormDrafts.php": "0d4615af3440bd8695151e1b7b8f5063d3828e166ac563312d55d82ba99a559c",
+ "candidate/app/Services/SimulationIvaDiagnostics.php": "077bd185fb15568e509331fc4a1cb9a19029a0707b338f872793adbdb7ad1b41",
+ "candidate/app/Services/SimulationPublishedFiscal.php": "232795efec955c019e9917e62eab4160adb98180334f9b2dbf941d64cf519362",
+ "candidate/app/Services/SimulationTaxGovernanceAccess.php": "b62a78b2aa42fee82a791547149514c68fd480b369eec8c89dfcc7e0319fed76",
+ "candidate/app/Services/SimulationTaxParameterResolver.php": "a4621e672ea4f38e81ff9828f4017889cc09d229c5940f6e38607acc9b27e1a8",
+ "candidate/app/Services/SimulationTaxRuleExpression.php": "a976c0eb43ebb706275ca17efc9354a8d84f2dbe698375211704b158df02f7e1",
+ "candidate/app/Services/SimulationTaxRuleGovernance.php": "e503854420386cd959e7ca58ad584e730cdc986994c60badea8ce55fcfe126e8",
+ "candidate/app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "candidate/app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "candidate/app/Services/TerritorialCsvAudit.php": "1dd3ff9b6ac545f3bc199a9f2e02c0a073fddbc130147f79ef52a8284c8d6eb5",
+ "candidate/app/Services/TerritorialRegistry.php": "bb3ea61a71d544a99c44ff880c85b2b815b1aae35c377476b95d80587486559d",
+ "candidate/app/Services/TerritoryGeometry.php": "00ce3e6dde92868b0d34b963b8e59a26e6663149cdc0398c645ef636ca382966",
+ "candidate/app/Services/TerritoryGeometryImport.php": "bbe0540d470bd8fc3aa6f2ad4e44b1b64ee81451b42e45f1b812adf5a7035526",
+ "candidate/app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "candidate/app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "candidate/app/Services/VirtualDeskInstallation.php": "bf05cb8c9e20282ca8eb7b5230a64d31594242e3e1ebf016a051fa8860fcad55",
+ "candidate/app/Support/CheckedFile.php": "46878b2e1bcf3efd8ed02f3c82699e3a5491785500f4befc013fd9b702d86923",
+ "candidate/app/Support/CheckedPattern.php": "e7a72c020cba8e474ff2a586993854f5af3dd0a12cdad9ed00f0363d4786a811",
+ "candidate/app/Support/IsolatedQaDatabase.php": "719f3e3a090ff02b122c5c2f33ff9821b9a0ea4593de4463f5b30d34c5584923",
+ "candidate/app/Support/SkillsEducationMigration.php": "c0d96a418138049613662e4e8f583fc4170a35ddf443b1ccf1b3b06b5dd91342",
+ "candidate/app/Support/StructuredData.php": "653344d0e8f5832fdd1c8a16aaf71e37a010e450cc0b4591103dface4c24b031",
+ "candidate/resources/js/actions/App/Http/Controllers/AiController.ts": "310f362f99884a80cd755ce853f53bc2c641d32a3e69a15fb87f2884197c1ff2",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/index.ts": "65a5cf087ef5953a3b647e0b2b5e3f250bf1546b6309fcc22e64a7c968e5af82",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/HomeController.ts": "5c35ad5441564c2c9b23de6ae489446f3451a98b53ff8b690062e468309da67f",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/index.ts": "c28d13ad11dd0b068ae15e7288fab77e41f20bc79b7b4f8c958f3b4d34171f46",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/InterestRequestController.ts": "9a12d6538e0242a63ee4c7ff0a194c25af73ea523382408d08b0e3d72df3c1f3",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/LegislationSourceController.ts": "b8c041e9d91235bb7e0566b9d1b71446eb50fcf6432e85feb080a672e02a41a0",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/OpportunityController.ts": "0a0b36ee688ed0161a55e3798f1298f87f62913989353801bd85e3018a5f5c1e",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/ReferenceCatalogController.ts": "3ce0270dc7a4f4c317f10ba7ca64df29cb64056c32538e3a65102af04083be37",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/SectorController.ts": "33bd94762fc9a0c7882f1ff068529e29732412e04a19c832bc612e85aacc7260",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/SimulationController.ts": "c3ebd3522169ea79f6a8e368705fd1e0a0bcd72d3dff647ba99344272a1b4051",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/SimulationFormDraftController.ts": "18c4779d34ce2e1abeeedcfdc809574422e72133b60bb6f56e3f037ae54083dc",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/SimulationOfferDocumentController.ts": "6626e5d6433ffb1645981402c66804da46980ed52b8e871a4e2e0a4474569fb5",
+ "candidate/resources/js/actions/App/Http/Controllers/Api/V1/SimulationTaxParameterController.ts": "2c6f015a93d6da766a1960c29b2315db17f391ed7c41cbe37499843c32a31759",
+ "candidate/resources/js/actions/App/Http/Controllers/ClusterCompetitivenessController.ts": "969c42d554470087caa596ca36b960357b5e44b17196bdef2b57dffd60d40e59",
+ "candidate/resources/js/actions/App/Http/Controllers/ClusterValueChainController.ts": "0e4818d93040b786731a4f4f0a5d906fdfdbc507fe935a93a80deb2dc76ebe43",
+ "candidate/resources/js/actions/App/Http/Controllers/CompanyComparisonController.ts": "b3b4c60e37a2cbed66838b1621d88354a310366011e37db8d85d16c01549fefc",
+ "candidate/resources/js/actions/App/Http/Controllers/CompanyPreparationController.ts": "ba82caf81dcc659598d72c217f15383d926eb479f2f15513ae6eac0016f46f3c",
+ "candidate/resources/js/actions/App/Http/Controllers/CorridorAgribusinessController.ts": "73851b416af30205e3cbc8613b5dbe88560e8f70d56655c8e2d9a227cce2295f",
+ "candidate/resources/js/actions/App/Http/Controllers/CrmController.ts": "05b674d1ac0068b4a9de553cd163ef588f9941b83d7fdc8631aa1c83f49a460c",
+ "candidate/resources/js/actions/App/Http/Controllers/DashboardController.ts": "ee720140ef3b9c9b557c97a3e462aa00a5ed22a86aff131c9ed3c1d4f63219bb",
+ "candidate/resources/js/actions/App/Http/Controllers/DeskRequestCheckpointController.ts": "1a16a26df1996bc9387fd946538f7f28f33e696b8ad5c918354f0968b705a302",
+ "candidate/resources/js/actions/App/Http/Controllers/DeskServiceEditorController.ts": "8371a1ecfc877707a09a0c58739ec55c1a2e25a5ae0e5aaed57bed6f64877626",
+ "candidate/resources/js/actions/App/Http/Controllers/DocumentMalwareController.ts": "496ab1d4316705aa9c5e7d8d13d9a1c1e22ff8e76227b093995d0d2a01d78baa",
+ "candidate/resources/js/actions/App/Http/Controllers/EconomicReferenceController.ts": "f68c8aa7663167a39d4136d971096f252bd9384a2196969679028c88701eb70a",
+ "candidate/resources/js/actions/App/Http/Controllers/EditorialArticleController.ts": "dd8fadfba8257609ce32bbd43c2a5e653d2a7c8af44a22f1a8d99aef7a7f360d",
+ "candidate/resources/js/actions/App/Http/Controllers/EducationController.ts": "7b1ef9c56ce66a3f50469640c93b33dcaf94da0b21a4616fcf6375ccbd381d15",
+ "candidate/resources/js/actions/App/Http/Controllers/EducationDeclarationDraftController.ts": "0957820ff49499500ccca4255390d4f5a491045d6f23f0810085363378181923",
+ "candidate/resources/js/actions/App/Http/Controllers/EducationInvestmentController.ts": "78892e990c1df9f3f147951d65b34235865dd1f4ccb82d1e81a72f23a9f770a9",
+ "candidate/resources/js/actions/App/Http/Controllers/ExistingBusinessClassificationController.ts": "7931e4ed11fcd4d974403435d025f190c07d5e7372c2d9aa6c4b32ce8ea9ab39",
+ "candidate/resources/js/actions/App/Http/Controllers/ExistingBusinessController.ts": "c56fe498ef94a224518bbf12e1520008083644501c170669c6de26cfa2e72ae6",
+ "candidate/resources/js/actions/App/Http/Controllers/FundingProgrammeController.ts": "c372dda878f20136d7aa8c6d00c1f18963166da63645f66c8ca2f7200591d889",
+ "candidate/resources/js/actions/App/Http/Controllers/index.ts": "56a7afec77d73b339c42a3ca7e88024904ff174ab0832257a44822958b210eaa",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentAlertPreferencesController.ts": "961d86fc58bb8bad67a043b81e5eb3bef7f5b749c10fe9901ea66449e25a60a1",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentComplementController.ts": "f004daa0c24aa3a2257faea8e5d6a182ecd4214a07dcf29f21dd575f43c64ef5",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentContextController.ts": "2e7b1831c903ce8ae13ecc6d563f44f9be1b856ffe15d046e77b75e427550a14",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentCoordinatesController.ts": "49bc6558eab060408f27e89a7115b00fc767f2db4aa6e7c090ee242320455382",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentDiscoveryController.ts": "90577ff65c4029a2c3f2e1c28ad6cb5b637ce8ccba984b4c6ecad51f68927ccf",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentGuideController.ts": "f142fe553028185ebfa7ae57e00416732ce17aa5ff5dd73c13bbeb7de717f4cf",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentLegalSourceController.ts": "aa40baec6c2c71cf10166b12722d0d09bdd2b55e70f66a71d5a28b2c489d726f",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentPortfolioController.ts": "e9e43751d0c83cf4cac4ccfc323df0eab3b66edc87e80821ce4a6054080aa4ba",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentRelationshipRepairController.ts": "e51e1656bd6adf3dad125f9605158cd6f796bacedd0af4da8389f4ac741c3d29",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentStructureController.ts": "fad8bffd60a38cc40b4d3f2500a0f3f8c3f4b0ec6d9f7299a3e664154e36401d",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentStructureRelationController.ts": "0b98080380ef7672413b4d7e20747f0ab401b17c727e1acb0633cfe3be77592a",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentSubmissionController.ts": "c8c71d25cf343763da07597149c8671e2987c397d8afe801bee1bd2f06eb2cbc",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentTerritoryController.ts": "b9d60db219e28445822a3faa7fedf87e25606c10a819225851bf1d65b15ed0a6",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentWorkspaceController.ts": "2b9cf68463e7f3182e37a772ded4439c95b72849860a50319322b44a05d78be8",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentZoneAttachmentController.ts": "f0b9843e24bc2a5e20ea600ae1b3f3602dd6abf997ca00ac35d77a387121b747",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentZoneController.ts": "dcd3358985547895a404c2c57c11c84beecfe7ab38b78de07dbd5804b4126518",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentZoneGeometryController.ts": "10550cd13c344415017f3ae355915c96d73a6f7d3671e90611b03bde3771edcf",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentZoneLinkController.ts": "1968603f89620c7e4759b1d526578aeb1c14e6490843bf314cc50cf80505c117",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestmentZoneRelationController.ts": "1db58fcfeea381c351e5d4de7fedb8f66fd9bfa03df65b44429632dcbca9096b",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestorContextController.ts": "771f87650f4b005842b6f99707d2da46715cb66f1bf1236fe52d22cecc73e91a",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestorGuidanceController.ts": "49c4902932b9a51bf1d92cbe55ce125883d153d4c6f514f74012ec63f5d2ef9b",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestorPathController.ts": "656a07d24b61fdb966887831ed44ab80aaee19bd1a798a6ea8082418f10792f7",
+ "candidate/resources/js/actions/App/Http/Controllers/InvestorWorkspaceController.ts": "365106c90da959a18df4e7e96def82d21bfcb611c4f1497f5bc54f16dbff095d",
+ "candidate/resources/js/actions/App/Http/Controllers/LandAssistanceController.ts": "67d992d24b193c691202666eb208ba685684ad2c6ae775a63d98aa1019a1f473",
+ "candidate/resources/js/actions/App/Http/Controllers/LegacyContentController.ts": "17cc73abb1a38954bc6e150e9cee4bfabbe9d8008f4f5e483654f20b0297d19f",
+ "candidate/resources/js/actions/App/Http/Controllers/OpportunityClassificationController.ts": "d09e8be3f6d8d5edc9ab624b7e274f440714b9ecf05068d48cd27ba6dc7565fd",
+ "candidate/resources/js/actions/App/Http/Controllers/OpportunityManagementController.ts": "c7ded2f4535654faf76d777ff2c06c519abda83eed7b7f3b625f30e331f7e8d7",
+ "candidate/resources/js/actions/App/Http/Controllers/OpportunityOriginReviewController.ts": "aef57f071793ff0b02b8806888bc0522245a1da58f4a3b715df175acda6a1f8d",
+ "candidate/resources/js/actions/App/Http/Controllers/OpportunityPromotionController.ts": "ec1764befa67cca5855b625e99446038eca338dce79b243c295c0136515fe2a6",
+ "candidate/resources/js/actions/App/Http/Controllers/OpportunityResourceController.ts": "240b1c9321237523cca7a2d491ffe2ec036252d4569a672763753bac590a7045",
+ "candidate/resources/js/actions/App/Http/Controllers/PartnershipExchangeController.ts": "2e30dc9cdcf43a3e43971cd1d1c91319660d0126102eba62c61eac9a3157da94",
+ "candidate/resources/js/actions/App/Http/Controllers/PartnershipInstallationController.ts": "1d76a415e78ff2cf4462a3d93393edfbe075a6c986cc3607c8b8a09cb5449dc8",
+ "candidate/resources/js/actions/App/Http/Controllers/PortalContactController.ts": "20dbea8839adce3cbcff116e4b93574f69295f3ef658c48a783fbcd30b1fc966",
+ "candidate/resources/js/actions/App/Http/Controllers/PortalManagementController.ts": "27af54fe428410f6f91ed0e3c06de2e80a53e3b56561e1b5f6271e8108dc2cc8",
+ "candidate/resources/js/actions/App/Http/Controllers/PortalProfileController.ts": "fcb0da65cd10dd576285ea135bfa3dc0d38da745e2def0455ce2eaaa8fa65e83",
+ "candidate/resources/js/actions/App/Http/Controllers/PortalProfileInstallationController.ts": "57418c0fcd62eec5bd7e0c7b691410a1087ba2cf3d63defa32bf00a75a28d579",
+ "candidate/resources/js/actions/App/Http/Controllers/PortalServicesController.ts": "00191616c2d2dd2572e461a5c3809315d0f35d90eca80c424d6d65a3fd671f67",
+ "candidate/resources/js/actions/App/Http/Controllers/ProactiveSupplyController.ts": "c8a18bceef65b7626cf98e54ed03f9286a338128751889a0702a85b9b3f86dbb",
+ "candidate/resources/js/actions/App/Http/Controllers/ProcurementController.ts": "85419eb77d04425724ffb9ad2c438a783261e82d5ee5aa6cb376a952d8690c3b",
+ "candidate/resources/js/actions/App/Http/Controllers/ProductExperimentController.ts": "95cd1e1cc6912dd67f1b8f5ba679960abca9c71c2e0a5d351d3b3f3ece38fa9f",
+ "candidate/resources/js/actions/App/Http/Controllers/ProductUsageMetricsController.ts": "975d38d6fcf8fee26832a4901a6d14fce843e0dd67cf09ee528e2ec13c33b764",
+ "candidate/resources/js/actions/App/Http/Controllers/PublicBusinessOpportunityController.ts": "c1e79b6888e120ff3e33c6c2b2bf3638599206a293f05af40ff28e8cdc15de87",
+ "candidate/resources/js/actions/App/Http/Controllers/PublicGeographyController.ts": "506b77e3cfccfd30d7b11884cad9755907fde20a35225f711f19217732c55d0d",
+ "candidate/resources/js/actions/App/Http/Controllers/PublicPortalController.ts": "e96ea883fadadf45482f7cac8b816d2d3a36137e2af148feef40b286bf69c734",
+ "candidate/resources/js/actions/App/Http/Controllers/SectorReconciliationController.ts": "d45f967eea54562b80a6b493d24c468e863b98be9e2e79fc936e66de86428218",
+ "candidate/resources/js/actions/App/Http/Controllers/Settings/index.ts": "e0adf324ae0e36956f61b63d6aacd254a17e5fa4fc6a3d29402a3ce1620dd0a0",
+ "candidate/resources/js/actions/App/Http/Controllers/Settings/ProfileController.ts": "7313726f725e743555112f40e0fc8710829bba067eea0d87dcffd8ed478dc03c",
+ "candidate/resources/js/actions/App/Http/Controllers/Settings/SecurityController.ts": "f245533c2e84c6271f047680dc817bf12be63c3e02f3f97b0d6c55e0e95b929f",
+ "candidate/resources/js/actions/App/Http/Controllers/SimulationFiscalSourceController.ts": "727ddd49d2e49daab34e1816415e1619b52c682888c103cc40d03afe2c6aab77",
+ "candidate/resources/js/actions/App/Http/Controllers/SimulationTaxRuleGovernanceController.ts": "2cfc5b2863ef89d1c175d01087dc76a00e9e3a83b86ff603d4d6f3ea572f4415",
+ "candidate/resources/js/actions/App/Http/Controllers/TechnicalSupportController.ts": "7ce8e2dd06701010abe927f33b2ee7347332a6a8db7815079149f36f81656fb2",
+ "candidate/resources/js/actions/App/Http/Controllers/TerritorialRegistryController.ts": "ee6c23d144320733e768c35182a65a9bc6b4974b637210ecce0c6e852bdfec67",
+ "candidate/resources/js/actions/App/Http/Controllers/TerritoryGeometryImportController.ts": "bc540e47263ffa86fbc33f84ba284506d7733d11ffb6af1214c7fc60ba4d3224",
+ "candidate/resources/js/actions/App/Http/Controllers/VirtualDeskController.ts": "f171062ee5a93dd085ebb20818fed083b99f9c0e0552fad7250dfaee0d64fd42",
+ "candidate/resources/js/actions/App/Http/Controllers/VirtualDeskInstallationController.ts": "1367c020807d1309b80c164ec34e35d2d06eaa05fb9f9ecda6146d20d204e164",
+ "candidate/resources/js/actions/App/Http/Controllers/VirtualDeskOperationsController.ts": "6a90cc2b9d257655c6e47326fc9d01f2335a1ac09cba1faa3aae1ca0ae09a78c",
+ "candidate/resources/js/actions/App/Http/index.ts": "0b55b9d20a4a7464c270c1eb7c9c7340520835951956fd2bf5c2f5970696a372",
+ "candidate/resources/js/actions/App/index.ts": "c6d561133623313382aad0840150305e7b69b6de1cf7fc13cf8d37f314055fac",
+ "candidate/resources/js/actions/Illuminate/index.ts": "5e9fe597eed0c242b053b49076b248dedb585cec6ccb2a20101cea14da6e4c28",
+ "candidate/resources/js/actions/Illuminate/Routing/index.ts": "88142a675525a48c2f2c9e28ea1ab2f5e8f37c98bf9e0a0f6295f2222589b522",
+ "candidate/resources/js/actions/Illuminate/Routing/RedirectController.ts": "6809fc3dfa922082b248cd6f73375cec892b463034c377a7df169ee785067423",
+ "candidate/resources/js/actions/Inertia/Controller.ts": "7e5abdedf989eafc2802335479b854d9445a0df9ab275f9481cc5bbba53a7d32",
+ "candidate/resources/js/actions/Inertia/index.ts": "f170c7ba412a0bfa44d8b3ed9e3523cf244d00801a0ef4c73bccd9bccfeb1107",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/AuthenticatedSessionController.ts": "dbdd01bf09c6f897cd850c8bfb472c8d5764d58342349d5318472d130f78604b",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/ConfirmablePasswordController.ts": "82eac89af65e47f7bf710ba2fa6cca12e3b2c31ba6784bb7d982a2c4d204a3f8",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/ConfirmedPasswordStatusController.ts": "7aff9a32c0efb0c3387d4f19ae7917e6d10376a4bd1161905ebcacb90bacd0b5",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/ConfirmedTwoFactorAuthenticationController.ts": "2db3d31e78aba722d8d11c513358d00950ec5be6b8335ae012a0b8850acf4861",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/EmailVerificationNotificationController.ts": "7fed293849ae11ee49a85a3a37f67c1d13a8cd8e846a3441b1472fcf0542d533",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/EmailVerificationPromptController.ts": "72dc682bdc990c9a8c7ea2f0e82bc87c4829bb47341bfbd751d4a15b515a3a1e",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/index.ts": "0f2e8c4c68c26bb344272dde56982d11a2ea9754fa5fdb8f514eccd9c3672d74",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/NewPasswordController.ts": "a2b541a9d270b408d0014a09c754fbbc75fddec68e2f74e01aa9588240543a7f",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/PasswordResetLinkController.ts": "ac44d0e2ecb39219a96fd0144e7244f3f9d7cc24a135cd0ca19cfd54fc819b4b",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/RecoveryCodeController.ts": "b361a2d0c63dc900233534078eabe19eafd999d0aeebb0abe818b0313556a65d",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/RegisteredUserController.ts": "ed0d5ca8c34c495f9f54864083864fe5d0dd3022b98cb10ef2aedab057f83370",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/TwoFactorAuthenticatedSessionController.ts": "34f261e3440dc62cf95e5c0a63b8f43379eb5992d029c7954db6399a078cf41c",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/TwoFactorAuthenticationController.ts": "c21021df63fdd9bdfbe0495e3730d33dcd1f552db50afe3bc8050442b02c1799",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/TwoFactorQrCodeController.ts": "4f23349ddda8472be6418b2b1c313b501bea2f0eb8151b0a63559616fe6724ee",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/TwoFactorSecretKeyController.ts": "9b0d3a0261c6b295514a03b99cf2d081a5d770a6d71a5fa32092a2276086a8e7",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/Controllers/VerifyEmailController.ts": "6af16da8aa248054cf3ef43c30407c1d224c40edfc0ead332a4df8861615d2d3",
+ "candidate/resources/js/actions/Laravel/Fortify/Http/index.ts": "0b55b9d20a4a7464c270c1eb7c9c7340520835951956fd2bf5c2f5970696a372",
+ "candidate/resources/js/actions/Laravel/Fortify/index.ts": "4b2326063175a4cbb8d5faf1c299151d9617b47036fbc82c3d5e564dc6534270",
+ "candidate/resources/js/actions/Laravel/index.ts": "1077bc3732b450e978452c90a9162a11df3c5627ebb66dcc8d4841ab32f5ee05",
+ "candidate/resources/js/actions/Laravel/Passkeys/Http/Controllers/index.ts": "747ff1c0b944e6dfdc485958bb3a2c16772b0cfcd172f72b2803ff48fdd99466",
+ "candidate/resources/js/actions/Laravel/Passkeys/Http/Controllers/PasskeyConfirmationController.ts": "1c1194ff565b0fa5629eaac1fc80b9447caa58abf74e3113e2fdaa9a66462aff",
+ "candidate/resources/js/actions/Laravel/Passkeys/Http/Controllers/PasskeyLoginController.ts": "73d9a4d8ed4e8cc2b43f9ffc1797a1dc6ac121eb891233f8d282971c69715530",
+ "candidate/resources/js/actions/Laravel/Passkeys/Http/Controllers/PasskeyRegistrationController.ts": "90573e3b46a5890d21c1ab1c544307221834b84add453db06805082f2528ba6d",
+ "candidate/resources/js/actions/Laravel/Passkeys/Http/index.ts": "0b55b9d20a4a7464c270c1eb7c9c7340520835951956fd2bf5c2f5970696a372",
+ "candidate/resources/js/actions/Laravel/Passkeys/index.ts": "a74fdfb05e73ef7209382b3531e356bb1a34d1776ab5d56c8c0786dd34df0e10",
+ "candidate/resources/js/app.tsx": "2ce2c8bf5b588dbfecb38113ad8517b95baf4aabebeaef0d864eb7b77127ae18",
+ "candidate/resources/js/components/acquisition-allocation.tsx": "51a1193074581aa20f39a389fbd19f7da8605b9ac7ee214ee748da34f19930fd",
+ "candidate/resources/js/components/acquisition-beverage-restitution.tsx": "ee26db3568275815bf9f2b7fd1533a32d669add5f019387f146c03b4d67ffe96",
+ "candidate/resources/js/components/acquisition-closure.tsx": "cd464ac68cf83e799273ed618fd43d7464266cd5f44388e78211a38c476a809c",
+ "candidate/resources/js/components/acquisition-imports-exclusions.tsx": "600de6667f4656961e82e4ab1820bab1635318f0cc77f1e0a40516cfb239b339",
+ "candidate/resources/js/components/acquisition-operation-link.tsx": "23ac452c4e120dd2e5a3eabe95e5b372def4faf814842001412294f323d284b8",
+ "candidate/resources/js/components/acquisition-refund.tsx": "ca5c86bebacd3b88512a89be964bbc915283b954547293bf764f51a0104b2d9e",
+ "candidate/resources/js/components/acquisition-regularizations.tsx": "64487c6d42547a8da63ec2a99955a099edd654c121da4842ae257ed7731a9946",
+ "candidate/resources/js/components/acquisition-substitution.tsx": "edf3721fbd6f451bf23b808b6f040980e0d7da9c22492f05e53b992bafe13ef2",
+ "candidate/resources/js/components/alert-error.tsx": "bb2845205fd65353a13cc2d4bd91eb6615521ca81f7bfe811536a2563953b34f",
+ "candidate/resources/js/components/app-content.tsx": "3e1108b00c0343c5b467483b33e9278ffb2778d4c8e7877f0c63a1b879e272bb",
+ "candidate/resources/js/components/app-header.tsx": "268aeb25a0bcbcb7460c0ab9a8c026bf2b3ad21e57b4d0512a2af8a7629416e7",
+ "candidate/resources/js/components/app-logo-icon.tsx": "b9fc868aef3f74410cc0bb821c165292c6ff1c36a0d687a65919309b66a7475c",
+ "candidate/resources/js/components/app-logo.tsx": "a481d04e0537d6e83a80aa8c8b3a83dd995606efc34836b8d48dd69fc234e838",
+ "candidate/resources/js/components/app-shell.tsx": "e290b18e92dec75b60b0ef4ff69aa78e398fe6e2f98a9ae13e1df18616253348",
+ "candidate/resources/js/components/app-sidebar-header.tsx": "9d4bd87e66b385789a99efde4d7d79ff9b479452cc40d45105e9f32b9f2d24e0",
+ "candidate/resources/js/components/app-sidebar.tsx": "96be928da05d4d37584d22813087ff855e796bb787d18f4687b06e76c825ff05",
+ "candidate/resources/js/components/appearance-tabs.tsx": "d53f48b0883713bf786fdf4b7877e03638bcf2e707b64ea6b8559501bfc8c4c7",
+ "candidate/resources/js/components/breadcrumbs.tsx": "b6968897d551e98eaf73a87ae7cede9d53b4f88d6757cad0008404a6990555e3",
+ "candidate/resources/js/components/business-point-summary.tsx": "57cfa820345391a16acd030a8faafdbb9cf7e4adacbba70944a2ddbd7d4a94bc",
+ "candidate/resources/js/components/catalogue-filter-context.tsx": "b155d5e812b52fc52677cb9a8d44068f64821732c90a82dabb521eed44af047e",
+ "candidate/resources/js/components/catalogue-guide-links.tsx": "638b6f9db281caadd29b882f70123898ba410a089a00ae99ef5d1a01ddf308df",
+ "candidate/resources/js/components/catalogue-investment-map.tsx": "d8188c74d53db1f114729d7b87c86cfa65047ee79d55a8ceb64add113693a378",
+ "candidate/resources/js/components/catalogue-navigation.tsx": "3b46e0c8def6b0935af39d1f897d75c462c818e9d9939cd960fb47df898f83bb",
+ "candidate/resources/js/components/cluster-competitiveness-public.tsx": "85ab2f59de4c63faf6ea699855bbcf0c9efaea0ff9c39421d5640286e9df5910",
+ "candidate/resources/js/components/content-management-entry.tsx": "d5aa701381e7ab7e2ae44fbe85ade567eb0a64cc332ef6ddc53acf0dd26b62d9",
+ "candidate/resources/js/components/context-documents.tsx": "98355412635047ed6f19c9220b3e3411afb94102298f0ec52dc160299a44d01b",
+ "candidate/resources/js/components/country-select.tsx": "8e9054aad07d98909c3afb37e7b3c6e7afb722e44ed0519b416b0b740da2df85",
+ "candidate/resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "candidate/resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "candidate/resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "candidate/resources/js/components/delete-user.tsx": "2f94b4dc6edf20bf9e00940d4d7e7b5da31bdf560f26b84efd65672bcee585b8",
+ "candidate/resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "candidate/resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "candidate/resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "candidate/resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "candidate/resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "candidate/resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "candidate/resources/js/components/desk-service-history.tsx": "6d5cec32b9ba08fd0ca77fe182aa3e052b76ec2476f9933d0b98d1ba29f91d18",
+ "candidate/resources/js/components/desk-typed-choice.tsx": "50deef44aa80b26a5322a7a8b9b51ecbab5306e8ff530882a2f114c2a586aa6e",
+ "candidate/resources/js/components/dossier-navigation-context.tsx": "48b05c3fd983adaaaeae05d3c07b9b1a4d0b2467fcb1f52b5eac1fabaf611f2b",
+ "candidate/resources/js/components/dossier-prefill.tsx": "3ea0b617d047bf7dc5acf12b4288938fe617b712f7dd29d0b5037913d070a536",
+ "candidate/resources/js/components/editorial-reading.tsx": "4e822f23f7025784cb390eeeb7bdf0d06a311594476e3dde12c49904e56ffc3a",
+ "candidate/resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "candidate/resources/js/components/education-submitted-snapshot.tsx": "8f64fbf6c39a0166405340f68ff8acc0dd38d5eea4f994ae825faa15b8939a4a",
+ "candidate/resources/js/components/educational-article-card.tsx": "a8ef531f130f3f2a1ca8dcdd7207cde31134e9414dd79498d7e667cc6abcdd86",
+ "candidate/resources/js/components/educational-guides.tsx": "2a2a52e50694e336f05544d51fc776a3bbc2b06d2ab61a1b3cdf1d261afca474",
+ "candidate/resources/js/components/fintech-investment.tsx": "b0ba0af0da1da4a7ce7f1281370c766afea8ef5b26a14b4ed27186c526aad640",
+ "candidate/resources/js/components/fiscal-calculation-gaps.tsx": "63d5810ddfc37ff9babb3a0eb6cab392709ed5b3351b13b71496bf8860d6ff4b",
+ "candidate/resources/js/components/fiscal-claim-events.tsx": "36f0ca5985302b1d24a4d700d1cd908ac650eeef6f1f1b5f7b44931b883920a1",
+ "candidate/resources/js/components/fiscal-l3-preparation.tsx": "9614d130edd7977d421ff9b033c9514a0b96f2b58f088343f9c3605b8ec45004",
+ "candidate/resources/js/components/fiscal-proof-parcel.tsx": "59b9bce202cccf3c72183034d84b34c605aae9dc9e4a2f9befd1557a0c4b714a",
+ "candidate/resources/js/components/fiscal-qa-preview.tsx": "08d992563de1c664b941e8151bdf76646f5feb678e3ba547ac90429652895a02",
+ "candidate/resources/js/components/funding-criteria-assessment.tsx": "34a1cabfb18eeadfab02e57dcfbd7976cf1fea0220af92d56ad209032cfe43b7",
+ "candidate/resources/js/components/heading.tsx": "22b088092301a7afd15bebfd515a9128b5a507d0e502f65fc2069d1b81b7d178",
+ "candidate/resources/js/components/input-error.tsx": "6a7e5e44d6a77d8ee0c7b0896b53b94784341a5c7cfd7825d4499e8593a313b4",
+ "candidate/resources/js/components/institutional-source/AboutStory.tsx": "0f1b748f4146ff720136ccc034613476c9e572db73f44f01afa3e307c52f4f85",
+ "candidate/resources/js/components/institutional-source/BackButton.tsx": "ddb4c1be242533d05fd63c7323553640732490c118b21a91dca07434b90ae75e",
+ "candidate/resources/js/components/institutional-source/CompanyValues.tsx": "b05f0e3b3ca708e382124973e30fe89f376fc07ad23da22f357322db5663324f",
+ "candidate/resources/js/components/institutional-source/institutional-map.tsx": "8841209cdd3a75d5f9cca85a24cb0fe775d3be06319a5968cf69ae0b062bc872",
+ "candidate/resources/js/components/institutional-source/MissionVision.tsx": "59a6c0aa3a0aa074de4b1fb418e8da1081c6040a53dac95efb68b18a96484dba",
+ "candidate/resources/js/components/institutional-source/source-advertisement-slot.tsx": "5eecd5a7a0f5cad6eef9e251cbbebd5f48d208c21a447b85f0e7eb3d46d3e24a",
+ "candidate/resources/js/components/institutional-source/source-text.tsx": "8135b6370fae74de916a22b79934cc02a2f9a3f1b89eb2be1bba7e18917688a8",
+ "candidate/resources/js/components/interactive-investment-map.tsx": "557d31504076afcd93a3d865133986745fffe29f4386d5f41680b2bd5fe1a0e4",
+ "candidate/resources/js/components/investment-complements.tsx": "d79ed07dd2b420b8728f3b627bf16fcad64d6c856eff9b5c0a96898609a3813b",
+ "candidate/resources/js/components/investment-consumer-identity.tsx": "ec45bfc6c67d0e221545125a70b57966696fa63f1214a4484d7ed9fc85e2d818",
+ "candidate/resources/js/components/investment-context-assessment.tsx": "a63c60e200b58e752067bf75b1e855edfc76eac1cb4ff3beb99fd705e75cc8b1",
+ "candidate/resources/js/components/investment-context-cards.tsx": "a199da3692d01070649101d5ca5ef628d8bffb88c240646462f9712286a84b44",
+ "candidate/resources/js/components/investment-coordinates.tsx": "361fc644c64a9a827d75051b437dc5d0491cb05dcdb16236d7affea5905efb7f",
+ "candidate/resources/js/components/investment-map-coverage.tsx": "2c4c51b5cde168bf3d67db989dd09dcd8c9b17a405ad00819e255beb1d71fc85",
+ "candidate/resources/js/components/investment-map-panel.tsx": "6a5a27a572576a74d56742c3355b110d80c719a84a34afff2e422b224f140a63",
+ "candidate/resources/js/components/investment-opportunity-choices.tsx": "eb117463f7a3b7ad4a940a86e9cd1f78a5b520e3b3ffdfdb6d844572bacd11bc",
+ "candidate/resources/js/components/investment-requirements.tsx": "adfef5e5910176ce8bb9f1bf6b4a301569d4ab97941d5641d1bde0ea7e4f501d",
+ "candidate/resources/js/components/investment-roadmap.tsx": "1d3f2835b03eb072c745e174b70983cca84c7a16f575b7c5a52072cfcc51f087",
+ "candidate/resources/js/components/investment-steps.tsx": "b1ff9729f637b6f67bb01df637cd78dd9c5010d37dcc662368fad6416cd8780f",
+ "candidate/resources/js/components/investment-territory.tsx": "a238b6bff6f8fcd08b077af9eb125627864f3882e1c164313922672fccdc8c9a",
+ "candidate/resources/js/components/investment-zone-installation.tsx": "87d988d93462f608ad661cfc46f3329b09e21c5fc86c709ddeb03398567d2ff5",
+ "candidate/resources/js/components/investment-zone-integral-details.tsx": "0031be9238d00be8e4cd5c45ee5d3a0ed8751d686a53721618b6cfbdb8528d5c",
+ "candidate/resources/js/components/investment-zone-operational-details.tsx": "b096918b919737efd34e58b642c9e477955dab686317d22c25413b2872516c6e",
+ "candidate/resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "candidate/resources/js/components/journey-companion.tsx": "73a6c20b5c0998e9ae2e0d7fd7e152f1493b4502dd7df1c6a11e6226a5c81a34",
+ "candidate/resources/js/components/journey-document-resources.tsx": "b74636455ecbcabf5160315ea8637c2e404954ae0fc7c2477a02d2ba2686c8ed",
+ "candidate/resources/js/components/manage-passkeys.tsx": "8f3e8970d3b82deba721ac27e57718e2e7dcecc67b1e78cb6404c475c9f9c62e",
+ "candidate/resources/js/components/manage-two-factor.tsx": "35fea615cf3a0454448057b0ef3137e24c21df4de30a58fce04cb847eb89eba1",
+ "candidate/resources/js/components/nav-footer.tsx": "357eeed7fde8937dcb629272896526ab223343f540bd30c2a087504d8433550a",
+ "candidate/resources/js/components/nav-main.tsx": "e168bd24c34c260d6d2b91ec5514176694066d200b10ebec0d9b0d92db787327",
+ "candidate/resources/js/components/nav-user.tsx": "7a003397c732b1d25df125c43ee58b1a906ba3353f5d721aeacf99fbed165cc6",
+ "candidate/resources/js/components/navigation-context.tsx": "41fade3fcce18eaa17325332e598ba646aff45a064683d86910f5ff079a3547a",
+ "candidate/resources/js/components/opportunity-alert-preferences.tsx": "c76a36fa7e2c51081558273a828c70c93d5cd491dc8017f564b7af6a6671d550",
+ "candidate/resources/js/components/opportunity-canonical-fields.tsx": "70bba90799e6057024f09fc32b85282c46002b6c8274b970fc80a48a79a20bf5",
+ "candidate/resources/js/components/opportunity-classification.tsx": "fb4d843c8c056f10c34baa5ab9f2ba324e9796456a20455303b7a3b0747ee6cd",
+ "candidate/resources/js/components/opportunity-contact-form.tsx": "9a7d38082b39aea5785a884b0d5d413754f8d2d3c53fb4c57bd6c75b1a9344be",
+ "candidate/resources/js/components/opportunity-corridor-groups.tsx": "3db613b823a44a8777bdf9c5bf37f2899b173c7b3f8ec0520286ba752f6d9801",
+ "candidate/resources/js/components/opportunity-fill-flow.tsx": "ad9c3d1f426bf3006ffc4b76424a49a2f01550ddf06ce5c7767aafa25fdb6ec0",
+ "candidate/resources/js/components/opportunity-library-reuse.tsx": "80e618ee46e43aa164ddc1f68bd7f5a71d90b5af633d681a3e2550488249fddb",
+ "candidate/resources/js/components/opportunity-parcel-geometry.tsx": "2c12ced86f598a96cf37a0ac849d376fce5ffe7ca1c6ffca0e082ec8c30c5c51",
+ "candidate/resources/js/components/opportunity-profile-actions.tsx": "70a07af684dd635a2bea9365c5fc429a534b5e2a823008e31aae6d98f2fcc136",
+ "candidate/resources/js/components/opportunity-related-results.tsx": "7d161f39b5e1b20c7ecca32b3ef8589d572981d4d3585f91b957a76e04dd3ae1",
+ "candidate/resources/js/components/opportunity-search-filters.tsx": "7dc3b81e9d699d43a6610575de7891ca184f00df60e363e91c75c7a1a02b5897",
+ "candidate/resources/js/components/opportunity-technical-incidents.tsx": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "candidate/resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "candidate/resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "candidate/resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "candidate/resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "candidate/resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "candidate/resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "candidate/resources/js/components/partnership-search-results.tsx": "7170c79aacf3bebaf48bfd3109b9d7d815ef57f13fdef57b45b6fbe92691dfe2",
+ "candidate/resources/js/components/partnership-source-links.tsx": "167af5b0e0fdf997121e327c68ace7acd3df0aef9ebf9ab08f2c095bae4278d5",
+ "candidate/resources/js/components/passkey-item.tsx": "a307c5ef209e24f3f913f77e355a4d04a1433f59f520ad45ad40112111ab4677",
+ "candidate/resources/js/components/passkey-register.tsx": "e7cb9d853eb943fd0899bc8530378eddbf941f9334a77bcbb7693d2e29d99470",
+ "candidate/resources/js/components/passkey-verify.tsx": "6db387920437ab39cd734a2af9bec7e64ae6469c0f1b368d536b275e57cbea37",
+ "candidate/resources/js/components/password-input.tsx": "63ff5269832c13a4cc8e3f556ace5684c161b5227c9ab62d6df1f0619aa781fc",
+ "candidate/resources/js/components/portal-grouped-menu.tsx": "42f72ff7fa94d4c42580e490d697f53f4f3ae8aaf9fef0a5d525f3960f2c94f0",
+ "candidate/resources/js/components/portal-hero.tsx": "214fa7ee656148ed05dae49ff7ce27c09623c7f43f29f51f957bcb0da4891489",
+ "candidate/resources/js/components/portal-product-identity.tsx": "02faff000f910fe93aced426b61dabb2bc91ed7fcc4fb17d8326e0b9e0aa1cbb",
+ "candidate/resources/js/components/portal-sidebar-navigation.tsx": "46d4ce030502d52d89f4766d5cebaead12a79e7a9921be87217ab037ab285fda",
+ "candidate/resources/js/components/private-investment-preparation.tsx": "ec387317c8a4b0c82bf6339d3e3d898e9fdae3682419fbbc4b6a09c1b248a9f9",
+ "candidate/resources/js/components/proactive-investment.tsx": "005842f331bfafb8af417fecf28bec78dee31c75491fd38f2789f4697bf0ecf1",
+ "candidate/resources/js/components/proactive-supply.tsx": "63b6982e43b9dc72fa55134827af76de06c9d26470f0633d81c83fc72e207e1f",
+ "candidate/resources/js/components/profile-navigation.tsx": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "candidate/resources/js/components/profile-proof-picker.tsx": "35ef30f8451f09ece8f0338d955dfb094063a677b4cbd7e194582d3233340df1",
+ "candidate/resources/js/components/project-dossier-export.tsx": "c0bbea29c8e307785cbe54014a85d6271c723a541bea9f2ad5196118b9570764",
+ "candidate/resources/js/components/project-planning.tsx": "c06629c89124f2a44402c8c30cfd7c51f19dd884f70287ea6609107373a96c57",
+ "candidate/resources/js/components/project-readiness.tsx": "b1ede2bcdea2eae2f408c52e87afab5b15fcf01cacc9e4325d1ba16b3383119f",
+ "candidate/resources/js/components/public-document-content.tsx": "d5487e2cbcbfa10161a10e59fc7466963dff006f79887689ea598479f4130fe5",
+ "candidate/resources/js/components/public-sector-cards.tsx": "858ba6235ef8b46461d416b3264436e4df2c9555b8e6d8c3644dbd8c55463484",
+ "candidate/resources/js/components/search-feedback.tsx": "305c9b51ce5a0f9a1ce47c1b9044496bb6325432395fe4586884c2908cf9dada",
+ "candidate/resources/js/components/search-state.tsx": "45cc210783625bcf96712064a0e7dd97f5681c499cdf60cedbe0e4127cba7aab",
+ "candidate/resources/js/components/search-usage-report.tsx": "a153727ddf7382be9c012fe70da1a479fc84f2907a24c614f59487c287b6f417",
+ "candidate/resources/js/components/sector-content.tsx": "4ee55554f8a88ba7db1ac0dc74259d4e66603979c3873f9ec897437830b8e0ae",
+ "candidate/resources/js/components/sector-entry.tsx": "5b014c706e79ac985e360805fdae71bea7d5ec353266e9cc1e0e16dfe9a71b9d",
+ "candidate/resources/js/components/similar-businesses.tsx": "1038de567e6360cce8fc6cb515a4f2f94bb41703a751b3be2e475485e9c791de",
+ "candidate/resources/js/components/simulation-acquisitions.tsx": "ec0a9d9c0f6a0924ccbb29b856759180d8792d07b36d4b422288b65265f39dbd",
+ "candidate/resources/js/components/simulation-act-sale-base.tsx": "dc483f23576eaa5c54a5292e28ea4b9c8ceb2e1c63cdd03c4c471f8989e1a6ab",
+ "candidate/resources/js/components/simulation-business-plan.tsx": "40516b8cfa2a63b90a1c126a189e5da0255437e58f8aa5b8b5d3b80bb2a19d3d",
+ "candidate/resources/js/components/simulation-cashflow-planner.tsx": "cf6decabb6458e95d8982d31451f4367f54842e4b5aad3ef31ec24a5eaf4c7cf",
+ "candidate/resources/js/components/simulation-commission-base.tsx": "71d516f527e32ad1c19172fe9ea325ae324990fbbefca9e1bb56134c6ab84ede",
+ "candidate/resources/js/components/simulation-composition-base.tsx": "8e77748f9ff5bea451db3c3ca23bb0aaf168367b7abb1beac081370c47f38ea1",
+ "candidate/resources/js/components/simulation-currency-events.tsx": "0ec74db2e886a37638ae090b96298b0fc62c4c9d55182763976995959d97f80d",
+ "candidate/resources/js/components/simulation-digital.tsx": "8dc8afffccbdc54ab7174b1cceac32c927dbb492e508bea8d94e924bcabdbdeb",
+ "candidate/resources/js/components/simulation-exclusion-base.tsx": "e1a732c34e1e0c3208f8c61621c53c0df086d0a42693808e62831e233a0da5a1",
+ "candidate/resources/js/components/simulation-financial-tools.tsx": "1275b72072d3f2b66822dbe6c1f5dd47e1a642d51460254a8871500035fa3b72",
+ "candidate/resources/js/components/simulation-fiscal-status.tsx": "0f20f2872ce9ca62a673de2f7e043234e58e7a4459ef86cff3dadb5e27181c5a",
+ "candidate/resources/js/components/simulation-foreign-operations.tsx": "af629ded0936a3af7d2db47019bfd7b02c925ecc7a5c851cad4ecf5a822c8c6e",
+ "candidate/resources/js/components/simulation-form.tsx": "7332ec8aaa8d1bfcb25d153557bbb26d36c9ad11b335d210e28fad304bb2c38a",
+ "candidate/resources/js/components/simulation-fuel-base.tsx": "b5ae1709ee19a20efe8120938977474f44d12b5547ffcc4bad57a5333c14fd1a",
+ "candidate/resources/js/components/simulation-fx-selection.tsx": "6cce50d449b258fac27155624c47856eaaa7bc3340acf391574d87c6e1aa519c",
+ "candidate/resources/js/components/simulation-goods-allocation.tsx": "d8e94c73704ca69f8441d401afc7d917e8859fa931984d9e671661b1b92b9bc8",
+ "candidate/resources/js/components/simulation-goods-location.tsx": "c5bea85177576005112a16eb07b1caee8dcc4108fca3cf7c1db42efd816b6a06",
+ "candidate/resources/js/components/simulation-goods-presumptions.tsx": "63c805538b02efa2888ad3a72afe24e541c829669bba5e89cf6213b2a5c0ca5e",
+ "candidate/resources/js/components/simulation-import-exemptions.tsx": "ac2796a5f22cb7ef0882d3d8e9cbf395f072361e7c721025200693bdc52edb9f",
+ "candidate/resources/js/components/simulation-irpc-annual.tsx": "d95a9581e5bc9f5b1a50907697c5b275e0aebc312145b20700abdde4dcc4375f",
+ "candidate/resources/js/components/simulation-irpc-assessment.tsx": "dc4e0e8d430a1e258a05f321b2aca4c29178555d71c3b7ffda3e6e861e60d85f",
+ "candidate/resources/js/components/simulation-irpc-carry.tsx": "84f823e52e15bb150354e81904e31b2f8298e9371b599a9c9501a195217c79c3",
+ "candidate/resources/js/components/simulation-irpc-costs.tsx": "3fa38aba1e9607194a9abb1d69a5c41f44083b40a2c48c8320c6bd060d2b5ff9",
+ "candidate/resources/js/components/simulation-irpc-depreciation.tsx": "fcc160f7add357a1af92b3eb90e3fde462679700d03d9229b06bf62b65eaa727",
+ "candidate/resources/js/components/simulation-irpc-economic.tsx": "9df9e471aa91a35789feeb6233789bf97ebccd24cfc9d462ebdeafa4c9f34928",
+ "candidate/resources/js/components/simulation-irpc-form-preparation.tsx": "8a496b0b0d3892089a69ae8cd6221c5117fb1dd3b1401e4d08f9db721b7c1e8d",
+ "candidate/resources/js/components/simulation-irpc-international.tsx": "98c0f62dcd7982705cc5fb6bcf3e17189d6d8b17f0e0b2036f503c5c6bcf2ad1",
+ "candidate/resources/js/components/simulation-irpc-mrfta.tsx": "fb9f2b431d85930d2af49a8c90b0299684ea58229dd3670eb7a7e146e7379aae",
+ "candidate/resources/js/components/simulation-irpc-normal.tsx": "1ece01024d68dc85d7959aaa56dd02802658e75b53db5b2c37e3a1e712feb2d3",
+ "candidate/resources/js/components/simulation-irpc-pec.tsx": "7fadee00557322312b7603359767937675bcf20246becf01ea44d2a330415e25",
+ "candidate/resources/js/components/simulation-irpc-period-fx.tsx": "351460f006968ff9f9e719bb6a0ce5050f5594b2d4df93a9a39779493bd09226",
+ "candidate/resources/js/components/simulation-irpc-schedules.tsx": "edb05a6e83c271953d6086323e49167778d346555177636a48d6325d5fe4a5bd",
+ "candidate/resources/js/components/simulation-irpc-special.tsx": "369c7e423ca29fb642a4c5726c75dc94db53e6569bff3f05f197effca88fde0f",
+ "candidate/resources/js/components/simulation-irpc-taxable-base.tsx": "70139d0857be20ce3ee4ccaf340d3f4a24e37b77deba9a64002e2839fa37d41f",
+ "candidate/resources/js/components/simulation-irpc-withholdings.tsx": "b8e50949ff245df79a48123ec532c46c6315222d05914673a5002194be9a00f5",
+ "candidate/resources/js/components/simulation-ispc-eligibility.tsx": "8dfc03cc3deb4d6a720af71a549ff5ab8e5028d1ddccd3ca74fc4d04cc03f690",
+ "candidate/resources/js/components/simulation-ispc-quarter.tsx": "099fd9e6469b1abd77505c7e0a62220537340923a7cd7a0a989691b91d475456",
+ "candidate/resources/js/components/simulation-ispc-residuals.tsx": "4f796f871af10b1ce4b3fe19786e2210c08d6576bbef2b8e4f1758afebeededf",
+ "candidate/resources/js/components/simulation-ispc-withholding.tsx": "0da7a9b43db56879827831abb24207420f534f93fc456ce03508284a952b92a2",
+ "candidate/resources/js/components/simulation-listed-services.tsx": "36ff48a0ca5b9b912152a7a36df16af3b453466bb536ac5bd89f665f4b3de1ab",
+ "candidate/resources/js/components/simulation-miners.tsx": "a3d9f3ba2f3ff95b54aaf7221cce87cae23930a9f74bb41d47a4c6a9064a68d5",
+ "candidate/resources/js/components/simulation-modelo-a.tsx": "c9473ee0696a985db31e65044b6ff3d348972ac5cfac2fb543d1fe4eae650dc9",
+ "candidate/resources/js/components/simulation-monthly-iva.tsx": "7cc1a0bd42f57a39eae1a5a8b520690433353b5c2c7a04ee57019d78d553545f",
+ "candidate/resources/js/components/simulation-noncash-base.tsx": "82b20ae1ed80dcb97fa00db2da059bf61277f61457c0e023f126e24b7f9b6bea",
+ "candidate/resources/js/components/simulation-objective-imports.tsx": "5fbf98d665041138be9a8640890d98d42aa800715da6af4481952708ab7ba610",
+ "candidate/resources/js/components/simulation-offer-preparations.tsx": "c97abc514e1d0e78d40ce7ff4629505e3d16cd7fb976683c921d1f58f6bc0e07",
+ "candidate/resources/js/components/simulation-offer-workflow.tsx": "b9b9e2afff9c53c08f8e72936c463ee0707c40206103aae9363320ba3225a906",
+ "candidate/resources/js/components/simulation-operations.tsx": "dde59e9ff3a0a53cf082e35a0c8d8eea5bd438b1fe06af88483afdc32541b005",
+ "candidate/resources/js/components/simulation-own-name.tsx": "459e27e49b0d685e294409a34d196f2c92c3a93d02495f7da1542a4247953690",
+ "candidate/resources/js/components/simulation-property-transfers.tsx": "9cadaa1e403ce9781cf0b3d1456d96d2a2b7787ad8fcb1a924d30446627061fb",
+ "candidate/resources/js/components/simulation-public-authority-base.tsx": "31b2c68e6c8d138d2af19b3962797bf1ddcad45d5c5d03b257b2432b81f393b1",
+ "candidate/resources/js/components/simulation-published-iva.tsx": "ae6eae0bcc69f8548ccf139ddfa74e934077b25fced700b5edb80a1916a46ec2",
+ "candidate/resources/js/components/simulation-reduced-bases.tsx": "f62c81271e2cfd085c829ac6bcf8064d56744466385d3ba85bbdf2823df7374b",
+ "candidate/resources/js/components/simulation-remission-imports.tsx": "2204af343d17811ba00c45ee438aa9a71783bc61bbc32226c82a47c97b4a327f",
+ "candidate/resources/js/components/simulation-returnee-baggage-fields.tsx": "3b405a16ec0d01abf8f1a73a6244ff37f0d29d27c94bdd5a714ad10debf56c44",
+ "candidate/resources/js/components/simulation-returnees.tsx": "0301004f52cd19b1a51f3d4aa04343471930fd7648747e67e6993093ecb95065",
+ "candidate/resources/js/components/simulation-secondhand.tsx": "72fd3b33ff5f6a08a4d6765074fbbd1c696743949c162cb9af42ef922bbc59cc",
+ "candidate/resources/js/components/simulation-service-location.tsx": "0843c2a577fd1dc6231328c973ea208ce392b688d92dc2c84890f3b0b09e0bc8",
+ "candidate/resources/js/components/simulation-service-normal.tsx": "f18d90c296dbc8d781cf35fdd6d4eaeca8bfb3c5e09e886da5945a45d1a23d27",
+ "candidate/resources/js/components/simulation-travel-events.tsx": "7d63a752127f442eb3d4632d419af9670b92aa5bd76b8be2a2da691dacb11898",
+ "candidate/resources/js/components/simulation-travel.tsx": "802fe76e3dc24428db446fb7dc3b2afb0d366a892363f7781468d75221c802e7",
+ "candidate/resources/js/components/simulation-value-review.tsx": "91b476bae52f126f975df1ec955d11955b944ca18a537bffdfa6fdaa0501e38e",
+ "candidate/resources/js/components/structure-geography.tsx": "e52c8860d737640d7f0c626b1e97b32dba8f671bd1011e37be0dca08eff3a1c5",
+ "candidate/resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "candidate/resources/js/components/tempo-brand.tsx": "27c01d317ec59c9a4ddb2a184c0a8a9427fcf92d34a916060287d07226364d02",
+ "candidate/resources/js/components/tempo-footer.tsx": "c4c5b87fac9f3509a037e56e7723be3bbf0571abdeba7e843b5cf6093cbf2b34",
+ "candidate/resources/js/components/tempo-header-tools.tsx": "c7cef323a0f0f8b27f53a77dbbc7eb14c70f4c43d9757824fe8af75f13573d4e",
+ "candidate/resources/js/components/territorial-source-evidence.tsx": "30ae75ad9d60fc541b9ea467eb0680007e4e83ecabacafc0052caaf9e39ccd11",
+ "candidate/resources/js/components/territorial-traceability-plan.tsx": "bd9ffcd4262bd45ec42073b11f75598ca64aa062b8aee3f2daf08992c972d73d",
+ "candidate/resources/js/components/territory-geometry-preview.tsx": "b4a3cb4e891921ac472e1b67fce6d164e4ed95ac587e4aab2669868584c6dada",
+ "candidate/resources/js/components/territory-search-select.tsx": "cd170cfc56deeb57faf09dca86a5860a1b71b40c8c938246ea938a8d41d97ff9",
+ "candidate/resources/js/components/text-link.tsx": "d0b1698349e777ed052f0292f44536280d9bb7559b9d5e4c5284d1d1b6565309",
+ "candidate/resources/js/components/two-factor-recovery-codes.tsx": "9384ae3987a58ae89018f2a997dec7faebec4f51f516ebbdc2b337c8e757f00f",
+ "candidate/resources/js/components/two-factor-setup-modal.tsx": "8586833e10310dbca8a097df80b86f40638f874170b7668fa476f0d7017a311b",
+ "candidate/resources/js/components/ui/alert.tsx": "ce9841beb06b4b3a2c88dbfb46f9635d198827870becdfd3e2619181e28fdf61",
+ "candidate/resources/js/components/ui/avatar.tsx": "1e8837e409f4ede09137c6a01d290047ac2c0c306991d4872cf499c77b9aff2a",
+ "candidate/resources/js/components/ui/badge.tsx": "da6d8f237f7fd88fd9dd0e83863d9cf65a473f3affaccb5547b1b6503bc815ac",
+ "candidate/resources/js/components/ui/breadcrumb.tsx": "fe3dd16bdc11190bd19d0b320496d7303749a4e360da98f345f93507058483fd",
+ "candidate/resources/js/components/ui/button.tsx": "1260ee658e71b21d59827ca3e86d87ce131a7846484146a1640acfa91b0b6706",
+ "candidate/resources/js/components/ui/card.tsx": "18889fc98cb42833b3d9e3534f891e5d05477533db42511b71ed667b59d316a0",
+ "candidate/resources/js/components/ui/checkbox.tsx": "8300e569667bfa905c5b1e1f0c63d0efeff87066203ed1750aebb2b3cf2eb08b",
+ "candidate/resources/js/components/ui/collapsible.tsx": "661444318605c90d19e47e4d21289a68b4c5f7f01782be70dafa80d3f7a4cd08",
+ "candidate/resources/js/components/ui/dialog.tsx": "abeb6df2254f0bf5f73de1c9b5aeb4e667afe8ac0319e8b9aa099a612cc70b8d",
+ "candidate/resources/js/components/ui/dropdown-menu.tsx": "f5f8b2a584f42085b647fe59a009d6238ddfc61d1aa1325561cb543f95d1189a",
+ "candidate/resources/js/components/ui/icon.tsx": "8b04f9bdcefe76ac7d9f31ab6f325e6d2725a83be29f1e4ccb47b16ab8d48f88",
+ "candidate/resources/js/components/ui/input-otp.tsx": "59dc19f93bd031e8320c7df571cd9509e8c1ceb6337506ef380d11b2e10e2550",
+ "candidate/resources/js/components/ui/input.tsx": "17da6ceadd3932f8c4269c34e29fcdad73e490bff5bcf76b6c57d47656631695",
+ "candidate/resources/js/components/ui/label.tsx": "883e35baf22dee1847066678ada2a6aabca32a91c1de4fdc074c6c48140498fe",
+ "candidate/resources/js/components/ui/navigation-menu.tsx": "6c08ab109f9a0285de6806714161b0e7fdca443aff9beb23d8ee06112af6f46c",
+ "candidate/resources/js/components/ui/placeholder-pattern.tsx": "91d8ef7a075067aab8d270c70391d37b75095433633b6738254e6a944afcfae3",
+ "candidate/resources/js/components/ui/select.tsx": "b4e61d449d531da0caf056862ecc214450672ca20c5abdd19f367962c3a0c3f5",
+ "candidate/resources/js/components/ui/separator.tsx": "54d4fb628c7a5c9edddd464b7c988f5690f7b831ea1375e5ba03a58b2891ee9a",
+ "candidate/resources/js/components/ui/sheet.tsx": "a525cc98beaf974e0dfe6cda1c5da1101798b6843ea355a758b3c5df5235f506",
+ "candidate/resources/js/components/ui/sidebar.tsx": "ca7677aa94cdcf8e973d281aa539273d81264cf54e8f7c3f2e4f99e7b37b053c",
+ "candidate/resources/js/components/ui/skeleton.tsx": "48687fbbfb522a48bdd3e0c93ae0fc4a1621641b4d048903dcfd3b80ce65d6c0",
+ "candidate/resources/js/components/ui/sonner.tsx": "61bd65543a0873ca4ccc4a75cf8421f96cb7f42f8494f2c7552798d6c478b83a",
+ "candidate/resources/js/components/ui/spinner.tsx": "5bb728bb0e6e2515801c71d55ee0829bce3c3a164898703da3a9d377fab5db97",
+ "candidate/resources/js/components/ui/toggle-group.tsx": "af297bdf6c9e996af24b27943d6d6cf07afd73d6189a03b71452dc8d8e952cb0",
+ "candidate/resources/js/components/ui/toggle.tsx": "9dab8dcb383661cb660482b41f22e819240d45519a6126232f0eaa35493da1ae",
+ "candidate/resources/js/components/ui/tooltip.tsx": "616e0392245fc59e083fda696ce3512c5fe395351550bfa54bd4b28fd33fd09a",
+ "candidate/resources/js/components/use-territory-geometry.ts": "46bc40ed776d566cd03f1c4ef9f397d07ffcf2edd5a1fa5ae932ae3c9eea0c56",
+ "candidate/resources/js/components/user-info.tsx": "d94732380d4339fcfeed37799c406a2bf63f36d43046fc0302b209eec40d829e",
+ "candidate/resources/js/components/user-menu-content.tsx": "9cb79c2a999bb363bd9d4fc1869b672c474b088eff23fca6e9f588ecae00d3ce",
+ "candidate/resources/js/hooks/use-appearance.tsx": "e91f589c28237176e1e7f5ec21b044c6ad7d9e57fba7afedce0174fd8692240c",
+ "candidate/resources/js/hooks/use-clipboard.ts": "815d9595d6489472581d27944f71d4a53856b1650028dc7dfec37b392d7fce52",
+ "candidate/resources/js/hooks/use-current-url.ts": "ea024f22b8b487bf8319bf884dba8ca5b22fef7d7a9cc8c3d9d58eef1ac5566c",
+ "candidate/resources/js/hooks/use-flash-toast.ts": "27964275a33cb65510e302721a3dc79650cf4eab10ca880adee223b5fdbcf5f7",
+ "candidate/resources/js/hooks/use-initials.tsx": "6d77fee1bfbe966d909725098d14a1e16e67974d1bb15bfa5f9a34bb11abfaf9",
+ "candidate/resources/js/hooks/use-interest-draft.ts": "bcfa63398793163c58d36bfb71dd22fbb63716a9df2bbb832eba90a3c9d2fb1d",
+ "candidate/resources/js/hooks/use-mobile-navigation.ts": "17bac38d056a8dba07f4e2e6e4f000cb7fbd1ff4cfb1f911e440f114c48c6e7f",
+ "candidate/resources/js/hooks/use-mobile.tsx": "c2e8f66c36554591115a5f8f5587d9ce4f84f45d0d13670db1064b18c4b38070",
+ "candidate/resources/js/hooks/use-portal-query.ts": "492356ab615e0ae8513a206c9cd252023622bfab9b4af44c2d4b3fc2ad1c8449",
+ "candidate/resources/js/hooks/use-two-factor-auth.ts": "16d9434379531f1994096e4d1fcfd778b2c829602cce5731d602a25ea9c0073f",
+ "candidate/resources/js/layouts/app/app-header-layout.tsx": "0ec583aa7c1702bfcce30ba759c80ab39a6b0bd6de4d89446fbc6d26d927bbd8",
+ "candidate/resources/js/layouts/app/app-sidebar-layout.tsx": "df2d82f693896922dafbb827da491b84956c16f3c1590179b97bf06c6d257e06",
+ "candidate/resources/js/layouts/app-layout.tsx": "ac429029d84184f1357f441ff1b605514832a6f7edc13e167eb6aecf785536a2",
+ "candidate/resources/js/layouts/auth/auth-card-layout.tsx": "2bbeed8068ab5aa3298448b06b642554df4aac5c58654b91126429ab5d8407ca",
+ "candidate/resources/js/layouts/auth/auth-simple-layout.tsx": "c08f01c58bcfdcbeb969acd2ec84033b7d9bd24c7102d3a110c333945b2815d5",
+ "candidate/resources/js/layouts/auth/auth-split-layout.tsx": "8fa78eb6e22f8218269cdba7fe94abdd1a527c04c955b19c0963428200c7a62f",
+ "candidate/resources/js/layouts/auth-layout.tsx": "aaa1eb9cbb9ef27690c24577c8479286397711afd897b3dec8a0b8ff5b4d49ae",
+ "candidate/resources/js/layouts/portal-navigation.tsx": "baf9445f913397583b6ee887e658f1d44ba0ec173414196a34318eec8a564d37",
+ "candidate/resources/js/layouts/settings/layout.tsx": "78ea66c1eb6cad907e23de9c81a4d309a127f251355f04771f72eb5689609a4e",
+ "candidate/resources/js/lib/business-financial-plan.ts": "f5b4deac7181fb63c5ce107153a97e3031089ddce2fe46ddd3e98c3c96a428b7",
+ "candidate/resources/js/lib/business-locations.ts": "0e37e9460e35f413200feed213d092a86c568821ab5d4866a55d2a8509eacbcf",
+ "candidate/resources/js/lib/catalogue-context.ts": "78902c7c1ea6d41e88c8576bfa262893167dc5a0842d76aaf8e4b4517adedce2",
+ "candidate/resources/js/lib/cluster-competitiveness.ts": "1ed496f51f020da9f0c02ab0aa324b58a9dd17fa34a10d8c1a90d9915800fecb",
+ "candidate/resources/js/lib/company-comparison.ts": "309440000d5ef9465790d0d617fa95eedf560161763894c1a938f9e62555557e",
+ "candidate/resources/js/lib/company-preparation.ts": "97eb37a3376213495de259a8715301384fa84e45ce7584a7d9a48f487e92a250",
+ "candidate/resources/js/lib/context-inheritance.ts": "094d237a7186744d704ab7f1952c9429a1a3b23a0e21668eabd4a5822da8a953",
+ "candidate/resources/js/lib/country-iso-codes.ts": "f2595823b6f6701925400fbd513aeddb19c303268b3fed6a2c44bb8059ba9d29",
+ "candidate/resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "candidate/resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "candidate/resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "candidate/resources/js/lib/csv.d.ts": "c0bb5214a11bc49a42622e7c4c591ff394b200ac535f3d9a0224aa7fe922608f",
+ "candidate/resources/js/lib/csv.js": "67deca744dc9cf35b4192d01f0dd79c819a09bd98ffc9a7f092f938f07d322ee",
+ "candidate/resources/js/lib/desk-checkpoints.ts": "1c654c04a46f383713ea6a63fec44976aa922d5b2148ba7e6326ae827ad7ca8c",
+ "candidate/resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "candidate/resources/js/lib/desk-field-visibility.ts": "958d6d0978c5f1e6688c84307ab3a9aa482d49bf660ef0910da7d74d042d272f",
+ "candidate/resources/js/lib/display-value.ts": "96d23210c16b2b87d343968173339b8942eda48ecf763ea4f2cc9212f2ec95be",
+ "candidate/resources/js/lib/document-facet-label.ts": "552bd684082dacbb763dd09b61342c04bfbe8870b8186f48017f35c0d12790e7",
+ "candidate/resources/js/lib/dossier-export-state.ts": "ac40e30134ba56b67c6c6a3b044aaeb110750cac53e0934794c8a7d346d745fe",
+ "candidate/resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "candidate/resources/js/lib/financial-calculators.ts": "f551ce4a818484459535d80b968ae77ee17d6baf4ae1e4f018a23e11ccb18fca",
+ "candidate/resources/js/lib/financial-fiscal-bridge.ts": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33",
+ "candidate/resources/js/lib/fiscal-claim-events.ts": "33ac9bd2edf36c451c76acb9bbd551adfaa179a98446db4807733c104e87a96e",
+ "candidate/resources/js/lib/fiscal-form-preparation.ts": "f015e5f701b8ea066ecc34843fbf79452e8307662e4f0abd19b58e19434d8174",
+ "candidate/resources/js/lib/fiscal-preparation-guide.ts": "54e2a3965d531b3e57f41c2a9e4cf20a58110cca5fc34e550c8042af85b8c45e",
+ "candidate/resources/js/lib/fiscal-proof-parcel.ts": "89b90206d433c281553e141654cfe962cb03e31005ee3689b19be9a1261e616f",
+ "candidate/resources/js/lib/fiscal-qa-preview.ts": "56313140e7c4b83fcee747e7ba796044e04ac03240cace3f5cc3daf7390db8f8",
+ "candidate/resources/js/lib/fiscal-rational.ts": "941408aa1cd92652507b5e675e307d0883ff25921a903e60365175d02be0cbdf",
+ "candidate/resources/js/lib/input-text.ts": "7148d3b1a2e221111c9d71ffe417c6efb900f227ccb63c9379da213bd9a70d08",
+ "candidate/resources/js/lib/investment-guides.ts": "3b82f6df939d322bb6a5a1f4c490d7b860fd258539f2d19f92bdf0035372a482",
+ "candidate/resources/js/lib/investment-land-preparation.ts": "ab9ec2977f43c6db2dda9bd7fb103caf154ed023e795dbad487f7ea8c9a5f0c5",
+ "candidate/resources/js/lib/investment-maturity.ts": "8202a8cb6aba756b5d94f0ff921476f7c650ef04b2d0e725fd8e9fccae3100ea",
+ "candidate/resources/js/lib/investment-roadmap-source.ts": "6ffbfb11b9819c867616e3591e46ad8aab7e81ab1e77b9f4c72db6f72de53a5f",
+ "candidate/resources/js/lib/investment-roadmap.ts": "1dae4942ad731bc25a61adcb2faacf2050d6bfdfa4a57435846d933540fb3263",
+ "candidate/resources/js/lib/investor-context.ts": "98b90bd0c29e90f5ab0f329913b2b11590e4e13dcf07e2c675f878d4cf7b6c6c",
+ "candidate/resources/js/lib/investor-guidance-finance.ts": "db9cac40c97f39e7326780e99b2e02ef58324c765172d6c5fb98d8e93d428876",
+ "candidate/resources/js/lib/investor-path.ts": "f25f86cb6bb6f6ef84a806ecb00234728ccc9c48ce5f962e6424edbba04c0f55",
+ "candidate/resources/js/lib/irpc-annual-settlement.ts": "b1b8db6abd785ff4f305abe53ef21265d226783822b28907e41128d4192ae57c",
+ "candidate/resources/js/lib/irpc-credit-carry.ts": "0f8c677b8f929b524c7a90e3549585a3b7e35436b1c05fd5738b082517fc9a52",
+ "candidate/resources/js/lib/irpc-economic-credit.ts": "ac505fc074cb93a4f152651effb1a7962511b483641415577cd80d11d28e6bbf",
+ "candidate/resources/js/lib/irpc-fx.ts": "5313d2df4f427c15546005cf96789fc7295f6ab551b506ad44749178d7889a61",
+ "candidate/resources/js/lib/irpc-interest.ts": "1df67f03883b9c0f4bb6fd52a3b17dd32402c45c18cd7cb9690407cf5fe5ace4",
+ "candidate/resources/js/lib/irpc-international-credit.ts": "553722c183d87d007e849c3eee75ecbf17a49a8a686ed93044b41f3384fa9016",
+ "candidate/resources/js/lib/irpc-mrfta-cases.ts": "b2f90ba34c2a75bb25ef48be56b5c5a1c74bdb0eab5ca3d15146d780c4e89c3c",
+ "candidate/resources/js/lib/irpc-mrfta.ts": "519642a4f857e2084616e01f0340d7235db6a800462ba839d1ec0bef13fd1650",
+ "candidate/resources/js/lib/irpc-normal-assessment.ts": "074b4525062e8e9a749e096b7e47035b2cda77b899c8ea6ae160885bd6ccfeaf",
+ "candidate/resources/js/lib/irpc-normal-base.ts": "0cfad3758efc6b4aa676baddbc1764119057c7380f4eca19d548d4cfd6213ac0",
+ "candidate/resources/js/lib/irpc-normal-costs.ts": "98e3d4f7b7eb24540c514d04859d199b7e5990c0a60ff75943ced1d477555468",
+ "candidate/resources/js/lib/irpc-normal-depreciation.ts": "766e99da66e61e40ea31fc83ad0f0a64aca174fe6f3ad352432333f5f1abf742",
+ "candidate/resources/js/lib/irpc-normal-form-preparation.ts": "982c689c0588bad37b3dfc146b260ffd24e05828069f1facac88a8cfa163b009",
+ "candidate/resources/js/lib/irpc-normal-forms.ts": "504c95891ad9d06478c2fe30416cf8d05e91f027d85cacaf0d4d7de9c8f04d81",
+ "candidate/resources/js/lib/irpc-normal-period-fx.ts": "277ab5b15f09d9e462490972ac266308da01e210d43339969fabd229e7cdb6de",
+ "candidate/resources/js/lib/irpc-normal-profit.ts": "72cd5e046e059d59463374f239a4cd43fdffa242e34cf5f152728f1dfc4083f2",
+ "candidate/resources/js/lib/irpc-normal-schedules.ts": "b5ee4808e244d1bab01b7edd55f33521a9c4116a74551655a1a7edd29d896436",
+ "candidate/resources/js/lib/irpc-normal.ts": "a8f6440303df021d868f1800daefa998560b0f1de61a0c0b1f1f5f164e7d4718",
+ "candidate/resources/js/lib/irpc-pec.ts": "267da009c95d0a53fd0956546872f779c1dafdadb0a1cd63b3eb35efe5e7d954",
+ "candidate/resources/js/lib/irpc-relief-preparation.ts": "ed2bd9afbd817c87fc6eb1b3013161d3952569d5c97eab11319faf6bb8b27c97",
+ "candidate/resources/js/lib/irpc-special-combinations.ts": "241ebfd7f390bc6095770a5414b9b3134a849daf4ea6a0ba93e4db64da3ed145",
+ "candidate/resources/js/lib/irpc-special.ts": "4cd9e44b58d4abac2bfdd3a95340ae2dfc72890f7ab0eeb9d80ab5075b44a827",
+ "candidate/resources/js/lib/irpc-withholdings.ts": "b751aa1a326960516c8abfc9ade637a205c7bf053cbaa98c2058f50d56ea0c0d",
+ "candidate/resources/js/lib/ispc-eligibility.ts": "d8a32ee08e27c6ffcead739f9917d3196da6ab83ce6aac9163ffb74478d7e2fa",
+ "candidate/resources/js/lib/ispc-quarter.ts": "5bce00353d58e503693550610aabcfb9e3e81c36109e831ac0532ca66ecb0e92",
+ "candidate/resources/js/lib/ispc-residuals.ts": "2a75ef9d9af88d209ff891b0b0a3c64cadc085de7594aec5ee654a8c9e40cde9",
+ "candidate/resources/js/lib/ispc-withholding.ts": "faac040b5c861a33e92feac2c83c769b47a391606d13952d30b06d2b09ea9214",
+ "candidate/resources/js/lib/iva-acquisition-allocation.ts": "b83bf5998c3d5d984ede9372291bd44a97ae210d2ddddd9502eb0ff771a41ed2",
+ "candidate/resources/js/lib/iva-acquisition-bc.ts": "1239552d60f291ace42d98df9b806770f47c045381ce210e9410b2b5023792d8",
+ "candidate/resources/js/lib/iva-acquisition-continuity.ts": "399e895956dc778e716961ba862ea2e63eec7080342cc2d09e05da8268952e81",
+ "candidate/resources/js/lib/iva-acquisition-right.ts": "6c79a1cac41deb17851de12da52dbf078b90fb7dcbaa687fb48dd1f059972cf7",
+ "candidate/resources/js/lib/iva-acquisitions.ts": "b8a8c4a72e35fea7026fd01b0e8e26d44248539eca1a77e8d58ca15a72f218fb",
+ "candidate/resources/js/lib/iva-act-sale-base.ts": "8fb878db50323f569ea5f7238703bf659f7299af3aa143d76fd231ae86756240",
+ "candidate/resources/js/lib/iva-annex-i.ts": "e48d13e83e9882b6dabe6b332aa45f847cf94295eb8bff003f5ecdc777b1e8ad",
+ "candidate/resources/js/lib/iva-beverage-allocation.ts": "9698c2df8c3945c912970274e76de4a1a31b928833838a984a7aaa64685dfc2f",
+ "candidate/resources/js/lib/iva-beverage-parcels.ts": "1f1d4902779f099e86377f4958f2b3e585f85fb74dbb3e00db923c98d6a7e051",
+ "candidate/resources/js/lib/iva-beverage-restitution.ts": "5a06c9e873e7d4166dc7a652c8e3f21ede501ce3d84f337b7345e449a18ac914",
+ "candidate/resources/js/lib/iva-calculation-gaps.ts": "b204dce0bec157e7f6ffc9fb0a2eefd7cfbfc98c236be18aedab7b59c9ee14b8",
+ "candidate/resources/js/lib/iva-closure.ts": "f82463d68f9809c067476af93f7d1abba72154d345f1896c4bd783b2e26e754d",
+ "candidate/resources/js/lib/iva-commission-base.ts": "ac0ea70b6de54092eaa52b7e9c2a78c11cb8cc2df5739630788b33da0454eb89",
+ "candidate/resources/js/lib/iva-composition-base.ts": "cf593b160b474c79ef0253b7425e190dd759f2cab70b4f3c79c92bae9072520d",
+ "candidate/resources/js/lib/iva-currency-events.ts": "70a786a65587a1898937467e2480b379107399a5a86f88ede0008f2780150c13",
+ "candidate/resources/js/lib/iva-diagnostics.ts": "b4503c967dc888f4ae4ba666841c6d9a462e3d831cc9dab0a2ab4318d88d98c1",
+ "candidate/resources/js/lib/iva-digital.ts": "804e478662d3a8b23273fb11e1533a63a94ddc97c48236bf4714d3a0c7bebf68",
+ "candidate/resources/js/lib/iva-exclusion-base.ts": "23c0646e729330cc96b7a620b25d906915c499efa0a481e8ff6de60bac6e1fe5",
+ "candidate/resources/js/lib/iva-export-beneficiaries.ts": "f074757e2e141eefe95d0def621799361d99c9d8369d9e2ba9b37eda1c986dd9",
+ "candidate/resources/js/lib/iva-export-operations.ts": "238b4cdb6faed858b2a0168a4272e4f312398e2d71d9a1d6400249b366051cef",
+ "candidate/resources/js/lib/iva-export-services.ts": "d1542553a44bf2c2edafe984478263eaf8a8517e9206f1c1dae339f29c7f8992",
+ "candidate/resources/js/lib/iva-foreign-operations.ts": "d31cfbe880ea642940ac5565ea1db95397d6befffa949359ec3c468c86aad6ec",
+ "candidate/resources/js/lib/iva-fuel-base.ts": "47df5f9df82efd378d72fe302faf68c21862a84972ec2f1fe8f2c15f04673c79",
+ "candidate/resources/js/lib/iva-fundraising.ts": "519132e6a29ae4dd246a525b6cd2737cab1a6a9b9fee98132b7111adc446c1c6",
+ "candidate/resources/js/lib/iva-fx-selection.ts": "078ec23d3e30b5b213936d9628a7058822eb732c2c773b04f2a526b5d2adb855",
+ "candidate/resources/js/lib/iva-goods-allocation.ts": "7b327cc417d25c6555a96c532d033b1890d84c4ff6f381f64e7ffc7f48664ffb",
+ "candidate/resources/js/lib/iva-goods-location.ts": "d850416c012384fe04da94b7dff32b7c6b40b5c4348d729185da806a56dcd5b5",
+ "candidate/resources/js/lib/iva-goods-presumptions.ts": "cb42cae9459029651ac15b8f99b798f648f3cef1fb533118c07fd1e43247c8d1",
+ "candidate/resources/js/lib/iva-import-exemptions.ts": "97ce6fa8ad007bc38ca86208e2834ccec489c4384b9e716fa1d5e10e9d63904b",
+ "candidate/resources/js/lib/iva-international-assets.ts": "df934c3670d2db2c641522dc54f1398dd8fc7f60dab1a54ce0524b4365fed102",
+ "candidate/resources/js/lib/iva-listed-services.ts": "ad4282e2e794e711b020592e3b96b19e27c4b190818e4ab64407d2cd6b5cdd40",
+ "candidate/resources/js/lib/iva-miners.ts": "ac3ce467ecde2b1cfdba34ff0b408db295ed45c94a522bb31c4131870e1e3c62",
+ "candidate/resources/js/lib/iva-modelo-a.ts": "e34cac6d3c0473a64e896cfc4641c1da29382aab13de2bd0e78e1ff33c770c87",
+ "candidate/resources/js/lib/iva-noncash-base.ts": "6744ac2d4b4a7c2ee17f988b7a0ba622648d9a7150925f69cb9b628b0541df0e",
+ "candidate/resources/js/lib/iva-objective-imports.ts": "4cb2cf2f6eec4778648a6a697ec0f8d9ac951fbeffbaca5026592a9f47099ba9",
+ "candidate/resources/js/lib/iva-offer-package.ts": "d821c793d131af3bc6fe08a0d5306cbc3631788c539987161e879044e0278fd5",
+ "candidate/resources/js/lib/iva-offer-preparations.ts": "ba29c588c8e857c10c7d6a40db2f5db94e09bc3ac706d98c33abe2fdcd29b83b",
+ "candidate/resources/js/lib/iva-offer-workflow.ts": "5050332af717be81eb641b94334cd3e61986f903edb8e6511b4323020ffcd3e7",
+ "candidate/resources/js/lib/iva-onboard-supplies.ts": "de2343b92a63ce0aee4357b9b2aed432ae20443a4b4e131cb20f1fe9bbd79850",
+ "candidate/resources/js/lib/iva-operations.ts": "87f616ea2b3a844dea352a6c4d2db25a8de612df3e4edab4c395cc8fa0297a50",
+ "candidate/resources/js/lib/iva-own-name.ts": "4a45987e3a38d8f7f2b9712e78d30e287a42d5de4322dc1e2ef49becc41ce68d",
+ "candidate/resources/js/lib/iva-pharma-annex.ts": "834f28aa3329a0be100c7f2283b76c995cfe52de84cbe8a16eec9d57505a6dce",
+ "candidate/resources/js/lib/iva-production-option.ts": "05fa5f7ce002ac08f9ebe43899691c051197178d66c1f660b464dd9209307b84",
+ "candidate/resources/js/lib/iva-property-transfers.ts": "1b38e25ad5a9454d9443f66fab411066f1ff79dd394116030f6f93d1bfacd75e",
+ "candidate/resources/js/lib/iva-public-authority-base.ts": "962f8fdd904b6ec5e7fa93495566db47b1d419cc8a6701a8c64c05d76da165f5",
+ "candidate/resources/js/lib/iva-reduced-bases.ts": "04586605ca184f7b7eb403491f7b4c7c4dbca0b67ad5f0b324a977678dd2657a",
+ "candidate/resources/js/lib/iva-refund.ts": "56659b58b5918057a7ee32a83e7d7d0be3398d77e4768cb34528a01d4761695f",
+ "candidate/resources/js/lib/iva-regularizations.ts": "4a0185b7677a540986b120eacb2478d99f04fde9ef029f0e1f358e7473f907b1",
+ "candidate/resources/js/lib/iva-remission-catalog.ts": "6c5b834a21e6a131bfd202e18a70467543db6f887481c70c21d747a3beab364e",
+ "candidate/resources/js/lib/iva-remission-imports.ts": "77adbd08180a2f6f2c29ac6640e2922348a9e084d0f4ce1cd88bae4641dc3b59",
+ "candidate/resources/js/lib/iva-returnee-baggage.ts": "12604832d0d76dfc49560338965dab209b623a388eb48fb53e5068a72ba7bf20",
+ "candidate/resources/js/lib/iva-returnees.ts": "500d08a64bcefd8db8d6bbe650379d28b31443373125c74bb21d521dfaeebee3",
+ "candidate/resources/js/lib/iva-secondhand.ts": "fbe50f8af6bb9b42713fb44387bd5e428614d7886a46bf1d2081e7ecc40411e6",
+ "candidate/resources/js/lib/iva-service-location.ts": "3e74543f5e2dc95fb56487879647b7228fc6c340aced993c66a5282611f48ffc",
+ "candidate/resources/js/lib/iva-service-normal.ts": "4a0c596b99bfa7b991d0ea9e991ef62d25753072e89e2bae2507b93f9412420c",
+ "candidate/resources/js/lib/iva-special-regimes.ts": "8d8d619e87b254a4f5444eac2b5ab78797921eed42fc234e336dc051fdb0e8a5",
+ "candidate/resources/js/lib/iva-substitution.ts": "f43379706842efb3d76092a39a632061e89129a8dfde614e73d91ea3808856fc",
+ "candidate/resources/js/lib/iva-temporary-benefits.ts": "5c4c25f009b7fd911c672d0e24d95a33278676097fcb5868dd3043d161e1f472",
+ "candidate/resources/js/lib/iva-travel-events.ts": "0c3118df5f56b7a59e1bcce7e303e207c14e819203350d65f71d5af8aaf13922",
+ "candidate/resources/js/lib/iva-travel.ts": "413af25cf35bf01b5b72e52b455a8fc1c47adc94b23042865424b31485e8c678",
+ "candidate/resources/js/lib/iva-value-review.ts": "3cc4b0e5d06cebee38f6a41d0fe7ade7634ecec4ba59a48e52f0639d9e59e509",
+ "candidate/resources/js/lib/l3-form-preparation.ts": "1209febfba073a783fad7d0fe73ce4e2d4f51d23a5a197ad058c475118d969e7",
+ "candidate/resources/js/lib/monthly-cashflow.ts": "dab0bbbea868e0dd3f654535a09415a21c8f1470c6d5f17926366e7f762055fb",
+ "candidate/resources/js/lib/monthly-iva.ts": "a80d0f7e2aa5735abe7ec76d0af1086b15747f17ec78891d8a9c37a48c1590cd",
+ "candidate/resources/js/lib/operation-key.ts": "2f7c38e13c2c77d5858b8a26022e3ad2fea4d84223c6928ac1bbb512046b5d55",
+ "candidate/resources/js/lib/opportunity-fill-flow.ts": "667b91a6fe48d19520bc8d6b68d5b50fd1af1411aec83f132bb5fbf4fbdac9aa",
+ "candidate/resources/js/lib/opportunity-selection.ts": "7f338517a8c40237c237af03b5d7f0755ae182589aee3d6cd4b1192c6f7ae635",
+ "candidate/resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "candidate/resources/js/lib/participation-identity.ts": "388f8eade50f619809b6c0561a8bd099fbaf791e6914cda13fc9871a218a5882",
+ "candidate/resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "candidate/resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "candidate/resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "candidate/resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "candidate/resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "candidate/resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "candidate/resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "candidate/resources/js/lib/portal-api.ts": "7d5e0d4bc217a6c5ace7914e6183d925863c9217684efba64e4b73b1223cd082",
+ "candidate/resources/js/lib/portal-navigation.ts": "46bcf52b1a59a61b65fcc6b906128d82b299fec993056a6f99cc4b6b9032ec86",
+ "candidate/resources/js/lib/portal-presentation.ts": "d774ac3982e95a2791cb7e58668760cf9c8f1d555f7d440569ae4cc1ea635bf9",
+ "candidate/resources/js/lib/proactive-investment-report.ts": "fd75a3161bb42519e87e41eadbcb0a4eb34d41cd28cf109d9aa0904b9036f32b",
+ "candidate/resources/js/lib/product-experiments.ts": "5e208a94ecfb175c2c6eceafb761325232e417f74699bffe479c06693a0db46d",
+ "candidate/resources/js/lib/product-usage.ts": "e60b3122d4840b56650c0340e955e67c40c0dd7d897e66b37b9fa103cc708078",
+ "candidate/resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "candidate/resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "candidate/resources/js/lib/project-dossier-document.ts": "f77b46b1768e0d5c80f3d10abc10b74a5ce00687dca3d08bd14c70e1f09677a7",
+ "candidate/resources/js/lib/project-dossier-report.ts": "3997bf09fe6aa34db520c519cc48a0fce0315656bb99d2f46503f278372a3bb3",
+ "candidate/resources/js/lib/project-dossier.ts": "f4fec3288dacac0fb60ec753e3192ba18d3ad16f192e97d03cde5e51b63bbc71",
+ "candidate/resources/js/lib/project-readiness.ts": "21b6f3e21169ca1ad47e0ffefdb5e5fd788db4e60294a36d2e12285c74bb3f13",
+ "candidate/resources/js/lib/public-business-offline.ts": "8a4910a9f3faf5f5364be35ead860cfbdabfd98bcd342ed2294aead547ca357e",
+ "candidate/resources/js/lib/public-opportunity-offline.ts": "159dea522e294f89018b0525706e1cb29ad6e5edeaa31f2ec103fbafcc772b29",
+ "candidate/resources/js/lib/public-record-offline.ts": "10788ba88585be26f0be4e3ab0ba3d7fcc78b30dba4e08c8d7ca36f0582b8690",
+ "candidate/resources/js/lib/search-territory.ts": "1b62adfd95eb3e9b06116cadcc3bf091f6d619917efb4c25b0ebefec05532344",
+ "candidate/resources/js/lib/simulation-api.ts": "e6c5529ea6c98c54dd2ade09e53b4167211eda6c53605146c95a1bcc97b5b1cd",
+ "candidate/resources/js/lib/simulation-contract.ts": "23365cc5dfe53aa02b051da69c0d565ad241d0ebe8cddc7a68707619dbadb24b",
+ "candidate/resources/js/lib/simulation-draft-etag.ts": "2e20541d51b516c4d21ea249e93c6f7ef9b8c6977b0aef522f112089487a34e6",
+ "candidate/resources/js/lib/simulation-form.ts": "030301d1cbd3bdafc6c08b53957ec53415487447b5e2f447ef2e1978e2296931",
+ "candidate/resources/js/lib/technical-incident-handling.ts": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "candidate/resources/js/lib/technical-incident-labels.ts": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "candidate/resources/js/lib/territorial-search-params.ts": "d8e43793184a6311916b02b10bbe602fe8e22fee3068d4e938114d8dd1f1a798",
+ "candidate/resources/js/lib/territory-path.d.ts": "f32f3245221e6bad9e6fda506c7fdedf709bc7a0aac492e6c737326fb8c7e72f",
+ "candidate/resources/js/lib/territory-path.js": "c6ed286f0724a2e7fb1d6eb566d0269ab001fae3d0b1de810979da0f1bd619ad",
+ "candidate/resources/js/lib/utils.ts": "69e09bd57c6975cdd8f2d573d92f04d1cc5529aacd83ec38be676a41344a9cb6",
+ "candidate/resources/js/lib/value-text.ts": "7afe5719fe9d96f66ef587fe0c65769f67ca076b2edb040b20c8fa36aa443e8f",
+ "candidate/resources/js/pages/ai/index.tsx": "92b65313d5be839d4468c4fe9e476a5391920b091ba41f245383bf278c28bb96",
+ "candidate/resources/js/pages/ai/labels.ts": "24bcca674adc01b17e6e82c7ba26941f72a1fc6e5dec71406eab543e4ffb7c11",
+ "candidate/resources/js/pages/ai/result.tsx": "6a860ed3bb95ca87a25268f581e55d6dd973d2453b62fd086567ebf94dd044e9",
+ "candidate/resources/js/pages/auth/confirm-password.tsx": "b1d0bc38b03940d72b180c7f9d97516de5ebd6aeaab965147a4878152e047d5b",
+ "candidate/resources/js/pages/auth/forgot-password.tsx": "6cdedca491d5a05dad0083fb637cd618d0b290bd6b48b98e7c6163dc0d740166",
+ "candidate/resources/js/pages/auth/login.tsx": "8468308dacd26bd94ee41683684dcb7719386a1a53196ed90496ca406b1b94da",
+ "candidate/resources/js/pages/auth/register.tsx": "1bc5f6c515f117cbe769a5e35f87cc5748138a31af4feafeb3a458867d9d984b",
+ "candidate/resources/js/pages/auth/reset-password.tsx": "f3561726ae5d7ee682d968a295bbf60ec9f8cbabba1721c33f48bafd80d1b20a",
+ "candidate/resources/js/pages/auth/two-factor-challenge.tsx": "0fd14dff2f0a572f4b99905d0fb152baa476eaa55a221998b67da85fa4787610",
+ "candidate/resources/js/pages/auth/verify-email.tsx": "ffc3220d0ee6cc243e8e08ea46f8b1637794626fa45d7aeaa77f54203692864d",
+ "candidate/resources/js/pages/crm/convert.tsx": "180e31528301fbe79555f2f4bccb744405e9f4c75bddb6f83b08acbe9942470e",
+ "candidate/resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "candidate/resources/js/pages/crm/investors.tsx": "5f7b25473616c9653710ffca3f0bb1c02fa8fce9298db51e342ef4fca9c4991c",
+ "candidate/resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "candidate/resources/js/pages/crm/leads.tsx": "b56122d8dfce7215519293902c09a240a380c3026557ce68542ab1465fd704e4",
+ "candidate/resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "candidate/resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "candidate/resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "candidate/resources/js/pages/desk/catalogue.tsx": "65d8441842ea525c4d22c3e6f36f4cb62e5d3c36a891846966663f3a9abfcab1",
+ "candidate/resources/js/pages/desk/install.tsx": "d0767112cf813569f64f836e32e620d6b9d905a06c71020deed8c419b015e571",
+ "candidate/resources/js/pages/desk/panel.tsx": "b854547d888050b21aaf9809cb47b416bb8f7e3b816f68fddfb2fb70b04d3537",
+ "candidate/resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "candidate/resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "candidate/resources/js/pages/desk/sources.tsx": "09a65801fc2dc3209681b96c540473551aac213d938e8135a6b412a9d13d19c2",
+ "candidate/resources/js/pages/education/analysis.tsx": "ed85602ec44ece0d57558a6312557af82f43f024f9cc37ed73f8e485d4c5ab14",
+ "candidate/resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "candidate/resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "candidate/resources/js/pages/funding/edit.tsx": "52c834f8c2eb4acc693a319f1d72cdc1435b6acbbd03dd2323db899b284ea509",
+ "candidate/resources/js/pages/funding/index.tsx": "e3111eb5da3bb49c4b46b4e07908cce723174eb91bc4d532e84aea547050a881",
+ "candidate/resources/js/pages/funding/manage.tsx": "514b9330750bf919b5cf56972390814819071f2518745ca2cb81dff53d0f2f28",
+ "candidate/resources/js/pages/funding/reference.tsx": "99a62c7d0815fc414f4ae989e2584a2a796ec4e499e10621c8b0a0dc2914b752",
+ "candidate/resources/js/pages/funding/saved.tsx": "a0c5b2c938a2e1f6a0a46a03920b1590824b75ccb591137fcc615b35368d632c",
+ "candidate/resources/js/pages/funding/shared.ts": "d4c2951b877ec95df076dd1a0a8f0abee008a0ba6cf0a504aa691d7e066296da",
+ "candidate/resources/js/pages/funding/show.tsx": "5fc036b7b1557810369b26be5c65a6292ff13a6a6a14f7cd10ec20f4143b8e97",
+ "candidate/resources/js/pages/investment/business-classification.tsx": "05a929733da48b4a3f1898c08aed25e124b8b064cf45241f0997dff1ce8cbad4",
+ "candidate/resources/js/pages/investment/business-interest.tsx": "2aa4ae236e0690e1b94b1094dbdcdef0a69b652c4363a189edaf9e3ad4ee7665",
+ "candidate/resources/js/pages/investment/business-marketplace.tsx": "566e101f7dc06762b70507d6431b4b1fe0e84cfc96209d38943dc8cd1c89d14e",
+ "candidate/resources/js/pages/investment/business-objects.tsx": "a22f742f80ec7f42304cf508368cf5e9726bcaff898d0537d6b2231bd049e37d",
+ "candidate/resources/js/pages/investment/business-opportunity.tsx": "580022357c27836599f0a6abf33d4cdfacb39094abef758f71c76d1144b69b82",
+ "candidate/resources/js/pages/investment/business-types.ts": "0964a8006b8e548c545c1528c6856487574b9cadb713de6e5c7d9ec924325f31",
+ "candidate/resources/js/pages/investment/business-verifications.tsx": "3d056d699860b866d5feed87eac103f88baacc6e899d460bf18dd451ab232fcb",
+ "candidate/resources/js/pages/investment/business-wizard.tsx": "60558466c6b4004ae573469e2328c253da53d30248e4d7d2db049a22861016e1",
+ "candidate/resources/js/pages/investment/business.tsx": "0e0c7f614b3ff9e7f3cb634ce52fb8959f1457569d2a2aea0e8db6485138047b",
+ "candidate/resources/js/pages/investment/businesses.tsx": "6b3a267b11cec5eb7161ac437d632f468d002a980751833b37b38a2d6cb3171b",
+ "candidate/resources/js/pages/investment/catalogue.tsx": "3371679dc219332fa630075bcbe0219fde882c66a250c25adfc7ac3f5929a41c",
+ "candidate/resources/js/pages/investment/company-comparison.tsx": "dc76af17341af793a6dbac990459990f989659deed86ec24125d7b57bf24cea2",
+ "candidate/resources/js/pages/investment/company-preparation.tsx": "0d10c933b3757822061b94650225a76e29068dd560c5cd057a462cd192403c7b",
+ "candidate/resources/js/pages/investment/context.tsx": "50b86276a3ac238b678f06dfb536b61ca3711a495453debae2e795082cdc0053",
+ "candidate/resources/js/pages/investment/conversation.tsx": "75258f0a0e36496ecfc39b9d4328ed5ce2cd3a1e3176db48a4a0b5b4f282a136",
+ "candidate/resources/js/pages/investment/detail.tsx": "f472ee0acc6402b688862625fa5375259a1d0497f2347091bad6037bcfcb7e15",
+ "candidate/resources/js/pages/investment/guide.tsx": "a67a4fa98cbb62f87c2f2652697fc2b03a831e4747acf16dcd1d7c198f589924",
+ "candidate/resources/js/pages/investment/notifications.tsx": "a3f279183ea4ec4e394b5577f996f12a21c2937118072f441af30c6801fb5ae4",
+ "candidate/resources/js/pages/investment/profile.tsx": "1beb04704b4579f9e27635054076dc6af8e0af873e83625b87a4c1660118dcba",
+ "candidate/resources/js/pages/investment/references.tsx": "d9d8402e6028d5762e17917b8abe5dba4bdb98856070cc980666ef412c87c05d",
+ "candidate/resources/js/pages/investment/shared.tsx": "3c0fc0ea735b8adccd30ab708f97a550da5435a63b8f2fa25d3332ff0ecd2aba",
+ "candidate/resources/js/pages/investment/submission.tsx": "b7eb3002a46e2bf47aff95ed4a028684abc7e3d04be1d8c89e23eed233b9755e",
+ "candidate/resources/js/pages/investment/workspace.tsx": "b3d66e759b97752b99b582e22ac09b02d50c404d674cc879808c5b7c0cc95dcb",
+ "candidate/resources/js/pages/investment/zone-attachments.tsx": "7cfc19a333814e62816409187b3db1482513bb4a5ea47182dbab24f7d023be87",
+ "candidate/resources/js/pages/investment/zone-map.tsx": "67748dff3e4c9e45f96f1ce816f7b08c359d4b3c52bb7fc07ed4623332411ef3",
+ "candidate/resources/js/pages/investment/zone-relations.tsx": "4c37d1f2f3cd1f5d79d20dd7341be7dfaf93fe9a8f0b405f579d405bf7edbba9",
+ "candidate/resources/js/pages/investment/zone.tsx": "fd7502f3b0eead8584280062247597c834419eea85b73992954489b4ead75b3f",
+ "candidate/resources/js/pages/investment/zones.tsx": "119ad0cad8918da333c84da54b083220a1edc79af4ad84a8f2db92fdf60174b4",
+ "candidate/resources/js/pages/investor-path/context-installation.tsx": "c0f51079aaa034ad816ae3854ea03d88b4a1e3a8eeb4c07318113cab4460d46d",
+ "candidate/resources/js/pages/investor-path/context-start.tsx": "7694d920cb2e4b709631f6a1706c9e409c4a5fecaf289b158a0fa20e399fdec2",
+ "candidate/resources/js/pages/investor-path/context.tsx": "bf8c9201796ffb30edfef8154fa4a6798adae8cada61318002febd5f8e358527",
+ "candidate/resources/js/pages/investor-path/index.tsx": "5def3fe1ce6bca0330c7eaa9aef6bd55f4a20e61a9296caf96dd44f0d2c63f6a",
+ "candidate/resources/js/pages/investor-path/show.tsx": "64f9dbdb709295bcfb53d5ca779cec086d2ffff3fefc5f40a568eb3f9cb5e3d2",
+ "candidate/resources/js/pages/land-assistance/blank.tsx": "a6a6aa46a84e56140396c0cc5f40f94ecfcc288876c48dc2a596b55e723daaea",
+ "candidate/resources/js/pages/land-assistance/case.tsx": "9026ad34d95a09e60dba4b928a02ff60d73c654fd173c92f4184912ee4f4201e",
+ "candidate/resources/js/pages/land-assistance/form.tsx": "cbc711667a5024a5c89cdb1e14a04e6278484641eee388abbdea97f273ac5a9c",
+ "candidate/resources/js/pages/land-assistance/guide.tsx": "76a7fce16dc4caaff9c686f25dcc296f2f75256011e0a8bf37addbe80bb9fb7b",
+ "candidate/resources/js/pages/land-assistance/management.tsx": "0da325efe885eaad9a8d05777506b640896a0c30d9f32ccc848f12b0f5a1054c",
+ "candidate/resources/js/pages/land-assistance/print.tsx": "7d74e825aab1ae87f6d50ad5a3e896ade279f9769d62695d3d235803d8557253",
+ "candidate/resources/js/pages/land-assistance/workspace.tsx": "53af95e1cc863b543e87977ab991a829a3b69f57417cdc8292c8ac74f34c0681",
+ "candidate/resources/js/pages/management/catalog.tsx": "d9cf92603e1f3eb67816f7171c206e5dc014f55bb339213f845035dc7971d0f7",
+ "candidate/resources/js/pages/management/content-hub.tsx": "678c26d483e6803019afdf023789c3ebc077bc734f0a14bd844fb4a1804f8f58",
+ "candidate/resources/js/pages/management/corridor-agribusiness.tsx": "f8579507be4b82797f1be5bf823942c25938391f0483f438baff4cfc01b716d9",
+ "candidate/resources/js/pages/management/desk-assignments.tsx": "1e558ab6fa1985b1fe5be04013b056661d5ce7f463c3dd5556505b93a83bbf32",
+ "candidate/resources/js/pages/management/economic-references.tsx": "01f7e557272d8dad1f188cdcef5b7b4c05fad7f5356609ca0d57d02a25066e85",
+ "candidate/resources/js/pages/management/editor.tsx": "608742dec5a0741d1528338cbba7911fb4921eeb666bbdb2d85b84d8540a3f80",
+ "candidate/resources/js/pages/management/experiments/edit.tsx": "34f2feee483657289f81879702d4f57e5718c62d12f7159de2f78fde6bc7dda8",
+ "candidate/resources/js/pages/management/experiments/index.tsx": "56928d6875e2fe40aaee4e2d414ff7ec8bb6002cb8460183f46dd68accef1ffa",
+ "candidate/resources/js/pages/management/fiscal-qa-review.tsx": "f450880a4cb4e3f711742bbe14ac7d9547db37a7a412474271e6150d748248c4",
+ "candidate/resources/js/pages/management/history.tsx": "e825d960893f7975a087577453c331df1e1f2237941755574e189643f9f88441",
+ "candidate/resources/js/pages/management/interest.tsx": "6a7b70fe44e6b97cfecfb464ac9d18f28a8c0ebb74772669990a8ecb83488574",
+ "candidate/resources/js/pages/management/interests.tsx": "173655307accb1ab4607795ae968a1d54759af0d035e5cbe8fba1e1b7b9e5d06",
+ "candidate/resources/js/pages/management/opportunities.tsx": "e4edaf0cd9f7767de744d5e6aafa185aa1f293acedd4297a277980c497f0e04a",
+ "candidate/resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "candidate/resources/js/pages/management/opportunity-install.tsx": "d430615dbe7c12831fc921a4bf3b7c58041c7df8f55b6551e7ac75d56df67a6f",
+ "candidate/resources/js/pages/management/opportunity-origin.tsx": "29935debe44d88543747541db18298a1b786e63952cb3185d3bdc745e8ea4637",
+ "candidate/resources/js/pages/management/opportunity-promotion.tsx": "29ab60aa34c1224b62a51e4f554d7294a8a97e87b2ccc2c3c44a8631766b9d06",
+ "candidate/resources/js/pages/management/opportunity-resources.tsx": "cab0e001de2099ece2b74eb6121be30ed84d9773fa3a89a4f695d4d86bad42a8",
+ "candidate/resources/js/pages/management/proactive-supply-review.tsx": "9b5f549affe44d1440d1b0a2078f7bade4a716ad953360fb4df507d0a012b1e2",
+ "candidate/resources/js/pages/management/product-usage.tsx": "1ae6e5376462ab2c90f2e223d080b5a286443ab7ae78d5b117cd07610ee5afca",
+ "candidate/resources/js/pages/management/relationship-repair.tsx": "8df4c0ef844585a9672119ccbcc37e8fbed020e2bc3112de4bfc11072674504d",
+ "candidate/resources/js/pages/management/shared.tsx": "675984a5d6c6a2d23235a1d06d600661c94c89b2c3dbb09754516dbb6b337eb3",
+ "candidate/resources/js/pages/management/territory-associations.tsx": "4097b9b92b0e1e8163f54df2884dfbf35dd7f54859bd106fac7c1a9b48f342bc",
+ "candidate/resources/js/pages/management/territory-geometry-import.tsx": "8dfc22071003fc6918c8008ffcf4dfd1a7cf2cdc29f330da9130dca7cfc2cd45",
+ "candidate/resources/js/pages/management-access.tsx": "bd43a21ed3e0acf0d226bff0f0d04d0da961700526529575f07502cd47295d42",
+ "candidate/resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "candidate/resources/js/pages/partnerships/catalogue.tsx": "3aa7755eeb53de99d6f5bb41ee5192ec62eacaac647c96a074190d274c2961d3",
+ "candidate/resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "candidate/resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "candidate/resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "candidate/resources/js/pages/partnerships/installation.tsx": "960b261e050dc0c1d201034e6263f2f030354279f6f9606c5670d2a2205a1afa",
+ "candidate/resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "candidate/resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "candidate/resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "candidate/resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "candidate/resources/js/pages/portal/about.tsx": "9d07cd8731243830e2eee8775a25c3c4208ccca58b5e6aea06fafbc9ec1cb503",
+ "candidate/resources/js/pages/portal/article-editor.tsx": "464559bbd16b472a5150ffa64b1e00f98757faa1d59a257d04fb2c8e2e2e7608",
+ "candidate/resources/js/pages/portal/article.tsx": "87f82306416594d8cbd47f2fa436c024ec7f104187ba465fdfb90d6faff8266a",
+ "candidate/resources/js/pages/portal/contact.tsx": "11315bcb6fe61331ceffa95e70783c16287cb1ac684804cf1481fec9a9d75585",
+ "candidate/resources/js/pages/portal/document.tsx": "2e99dd57a752e69721164c42217dd389cf530f07891ccecabc8f0649347ec272",
+ "candidate/resources/js/pages/portal/fiscal-forms.tsx": "661bc6c0d7289e33d191a9cb674a24e6762e62b6bb2a77104366528a2f458e71",
+ "candidate/resources/js/pages/portal/investment-contexts.tsx": "7a6446dfffb6f4a7ba900143a4b428bdf62356218ec2560b3f64d9d499c98342",
+ "candidate/resources/js/pages/portal/legacy.tsx": "1305aecb5d88ea690534e56e55098017fec21467c21b5b8668930154cb01904a",
+ "candidate/resources/js/pages/portal/manage.tsx": "0d2edd0e3fad32c762d45a00f08d2ee3eb089ae100d8e3995191d44809d83d65",
+ "candidate/resources/js/pages/portal/privacy-policy.tsx": "767a98e5d32a01033e75c2d05dd1561c2463bff0ed707d0b156013de5d343d5a",
+ "candidate/resources/js/pages/portal/services.tsx": "b3fd45983917e4bc2e1e1371f1696e1de526c02554bf0d2ff96d92ef8e1f6256",
+ "candidate/resources/js/pages/portal/terms-of-use.tsx": "642b1ec445ce051313c481078d0b71441036a6771e5eb7d0ad91f65fbef706d5",
+ "candidate/resources/js/pages/portal/why-invest.tsx": "474f6f4accccf20df5e4d5474d217212cd5abbb717747d413aaad07b6d6939ff",
+ "candidate/resources/js/pages/PortalInvestidor.tsx": "3d2804221b4ef3e284c951b8b772db35fa53a9bf0481146420932e10b5c90fe4",
+ "candidate/resources/js/pages/portfolio/index.tsx": "737eac8f3355ab92f919d91d15f78653da2c02ab43365d53c452edb980bd313f",
+ "candidate/resources/js/pages/portfolio/shared.tsx": "27b9d1c8dbced48532e7a57ce184810a32e3dea7cdc3a37a549dc7fbe8c04426",
+ "candidate/resources/js/pages/portfolio/show.tsx": "cf9f32e5851823a9d63aa66c128f27603c2f57ffff5b1f53580f20fec7a1ac2b",
+ "candidate/resources/js/pages/portfolio/workspace.tsx": "b61050f831ced1d04c21f48005c99cae95a7316cf5e1fc2bf68a30c445afec7f",
+ "candidate/resources/js/pages/procurement/edit.tsx": "6a247a278b8bfc43da3d04ef24f706c8889cd2f21b6771c8b4d118b082bc449c",
+ "candidate/resources/js/pages/procurement/index.tsx": "44de6f51f36f1619932f80558312cf52fdd705ca10ca937baae016a21afe553b",
+ "candidate/resources/js/pages/procurement/manage.tsx": "c0b97fa09e0ae5a3c583f7475ddd7112fd194d827db5d10d92936aa1f78a0fb9",
+ "candidate/resources/js/pages/procurement/shared.tsx": "8582819f0fa44d534a8e9713562dd514d639fad94ff19618be9b054dbf5fcd8d",
+ "candidate/resources/js/pages/procurement/show.tsx": "9f0f7db05c7e89c4f9ccbe11bb71d7725771be5bfbeceabc7a6c3d2d2355b5fd",
+ "candidate/resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "candidate/resources/js/pages/profiles/audit.tsx": "1a045abd321c47073f9615862b031cf197035974dcfb5cc60fdd6a58c8a6ae82",
+ "candidate/resources/js/pages/profiles/bootstrap-confirmation.tsx": "5d942a85e8bce4b8ded2dabd60b1e3926d77e6f89ea4e40bbe4f649861cb8bc6",
+ "candidate/resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "candidate/resources/js/pages/profiles/request.tsx": "4201b917a4811f8ef8e2c8f1513d8202cc1ce1350307abc36754297b578223f3",
+ "candidate/resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "candidate/resources/js/pages/profiles/technical-incident.tsx": "fc7cdaba8e5b892e61b03beedd1cf9377b723cf185cd2bcbaab1e343a38b1f58",
+ "candidate/resources/js/pages/profiles/technical-support.tsx": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0",
+ "candidate/resources/js/pages/settings/appearance.tsx": "638367104837b028aeeb49b4cad1d2c9a44a92d1b9aebe71c31995605e0479b4",
+ "candidate/resources/js/pages/settings/profile.tsx": "c599b1ca523ece69c3f5d3fe480a9f2ce4c323e97afb42095f61f2ddb7d4ba7b",
+ "candidate/resources/js/pages/settings/security.tsx": "39264620329657af975f990a50d657c42186ead57458cd83040aa07f9cd78444",
+ "candidate/resources/js/pages/structures/competitiveness.tsx": "8c4253cef8450b47245a918712bb81fe0ff2a333f54726a38239264a398f4fde",
+ "candidate/resources/js/pages/structures/editor.tsx": "c6d50445de3c1f18b266afe5898cd31198fc5946606770ac74a5f01e6e67b712",
+ "candidate/resources/js/pages/structures/index.tsx": "36601966212f14a8b4bdfa3d697f8e940f1bd9af7a0cbdf9433cafa7a1e52eea",
+ "candidate/resources/js/pages/structures/types.ts": "27bf2382317174f09c2ebd69a2f0f03c6cca69156bec23abff6ed03c2ec5516a",
+ "candidate/resources/js/pages/structures/value-network.tsx": "71b0807e28cb1df992eb89169c00343f1b2e2e5249b886e4b82353ccef5ee635",
+ "candidate/resources/js/pages/welcome.tsx": "52c0636bc46d5aacdcf6897877d9a44baa78349b7c2c5429589dca97760c1c9d",
+ "candidate/resources/js/routes/ai/index.ts": "41766837f98aa065376926a600076b425dcd36ad19f3a3c7071d30ff634026d1",
+ "candidate/resources/js/routes/appearance/index.ts": "8b17515e83262df25a2c77693afa12a86acb7ea3e7c29f7a5b62b685a158cae5",
+ "candidate/resources/js/routes/business-marketplace/index.ts": "fd0be41eb6b73fb7228753acac73c77c998fa616dd05f81301ec3083092fb33c",
+ "candidate/resources/js/routes/documents/index.ts": "61bf847ee705442223c982a70cb074d12902789a8e0ef2f6ec152038e1e37020",
+ "candidate/resources/js/routes/documents/malware/index.ts": "948b88228660fc82d89f591bc89d0c5b11b9a61b346ceda4a7d1d8937cd2737f",
+ "candidate/resources/js/routes/documents/manage/index.ts": "d0eaba5728ae6d1deff5a0c21ffb7dbfce209aef84516920bf1c7fedcaf22b1b",
+ "candidate/resources/js/routes/editorial/index.ts": "d83c21c242e37cf8eef939255dc43af0096ee1203bbb3c51a9ac45dc68b8efce",
+ "candidate/resources/js/routes/funding/index.ts": "dca450baa5592ff46dd131650504c808f21256c10871adc9f4aa9ea8a9e57f5c",
+ "candidate/resources/js/routes/index.ts": "bb505f41948a8f0c5608a87651254f6b7b4677c34f1c1fee50dd027b9cf23859",
+ "candidate/resources/js/routes/institutional/contact/index.ts": "2da8075819000b0a331331bac6d86a534ec4fe745d4f59b8534f9472fa1e460f",
+ "candidate/resources/js/routes/institutional/index.ts": "1e203b18631d0e5006e7a9022802161e6152cf16597161934a7cec1721c57072",
+ "candidate/resources/js/routes/investment/index.ts": "07e945bd1923e0245f9eb7542798e8e0d246aa7a860ff2010d1e3e64ce4c6a48",
+ "candidate/resources/js/routes/investor/index.ts": "fdb9cb18a9c39841264935db588c094252948870972be7f01dea4520b2adfaee",
+ "candidate/resources/js/routes/land-assistance/index.ts": "c7ab81b4458492c3e44a566ea061bc77ed877172d4ff7915e5c80aa1a7885f96",
+ "candidate/resources/js/routes/land-assistance/manage/index.ts": "9d9ef5835070b019c11df2e62edd631881e8f65fec28f9c20197531936817188",
+ "candidate/resources/js/routes/legal/index.ts": "8713c79f1edd3fdee2a059ba9b7c11250a59396d6fa4535ba3908a7bc5612775",
+ "candidate/resources/js/routes/login/index.ts": "adbac2c20773ada3a9ce8b57f6458ee749ad6648db4832bce06852034db2aeac",
+ "candidate/resources/js/routes/management/clusters/chain-links/index.ts": "e734767956f62a5d70b48fb4667eae67c2ab2f619864509d9c90287e06c4b1dc",
+ "candidate/resources/js/routes/management/clusters/chains/index.ts": "465623ec4e4be12881983ada14fc2b1f635b7b4b4fb9e9ecee46eb9a1c43feaf",
+ "candidate/resources/js/routes/management/clusters/competitiveness/index.ts": "21967d466c820df376035901a1866ca343cd710a972e789c9586d1d0ee3b0de6",
+ "candidate/resources/js/routes/management/clusters/gaps/index.ts": "7de98d2f02440cb5fa401ed1d3e82277e1a44f23cd2c078788fc1438f77ed2a2",
+ "candidate/resources/js/routes/management/clusters/index.ts": "4899e8b0ea01b6e54bc8ca07895fa9ce4d97d25fa742ad55d30c1c1da1df94d6",
+ "candidate/resources/js/routes/management/consent/index.ts": "0bcc83c774f942104804257370abf9c75184bda865d8e6f6e8731b627603c1ef",
+ "candidate/resources/js/routes/management/crm/index.ts": "5a1d56e6b8bae3f5fae12038c1120c9828fbde1a072898656938becd3d733b21",
+ "candidate/resources/js/routes/management/education/index.ts": "87da68340a01c350e0f15103244d0c68505dd657cc1ee3ecb95e21f230a541bc",
+ "candidate/resources/js/routes/management/index.ts": "446c9d2be28bdf8e40ee7036dd2fac1831d81b331fd68536f56a70cd18c19dd1",
+ "candidate/resources/js/routes/management/interests/index.ts": "54ce1d49504205d2f1ec63306ca14682f5e2a3876a7ee19b3bef8824a3cf4b00",
+ "candidate/resources/js/routes/management/opportunity-origin/index.ts": "dbd12d72ef65919310cecf3a6e31c5d7ad0841d226b2d8cf8f04398320edadcd",
+ "candidate/resources/js/routes/management/portfolio/index.ts": "474afcd64129841d5e3549f31cdd876dee77df1266a1d41d7935c697a0e8b2f4",
+ "candidate/resources/js/routes/management/relationship-repair/index.ts": "78188b6ccb529bbe3922d79072dc7f11ee2beac2aed866b26c009483a926eb2c",
+ "candidate/resources/js/routes/management/structure-relations/index.ts": "350aee87977ee9278632643127f46d6c92418e360f5aed3413e1ce41c15ba3c0",
+ "candidate/resources/js/routes/management/structures/index.ts": "34a5562410820b37026440387e18e13c85c1594c94f307141801f8c7b187f06f",
+ "candidate/resources/js/routes/passkey/index.ts": "0e168ce61276f7718312fd39531f70debc21cae4ddf03b93996e979af1236ba7",
+ "candidate/resources/js/routes/password/confirm/index.ts": "fb1f10fa1ead4de26cd3964c6c054afc1446cb8156bc1025da3d796f37c847d8",
+ "candidate/resources/js/routes/password/index.ts": "c971a65cae4b368ca98d09bd7337853d7dab4eb1b3fc3bdc8d35572a97279d93",
+ "candidate/resources/js/routes/portal/index.ts": "b3b0e11299f60bdd93eed98ec61af99e994a78e3b77ca1d5d0d7bd4c59d663c0",
+ "candidate/resources/js/routes/portal/sector/index.ts": "53d088c036490f429c538f7a187f746856b2bba83cc0a618af995844dd8182e5",
+ "candidate/resources/js/routes/portfolio/index.ts": "cb51ad984f6e55f65077f80b62cfea7de3978e0d36d078ab92b32442ce281fb5",
+ "candidate/resources/js/routes/procurement/index.ts": "563252ca5adf415a1b93d130a5e2db4274b542afa1d80353938dd51ac4476160",
+ "candidate/resources/js/routes/profile/index.ts": "3086b8e92735a84e84edb3d02a17a74bf6b04f89097fe58a763cb6a0405d42cf",
+ "candidate/resources/js/routes/promoter/index.ts": "9e151b9f8e03f0194d738d1c5537c176631fde92b68557da68e47d3ba279c635",
+ "candidate/resources/js/routes/register/index.ts": "869addfad90a6474580d5e93356d286069f7cfb6bb5d49c107cceb35090ae82f",
+ "candidate/resources/js/routes/security/index.ts": "76085bcc9d2872de9ab18c5dda1615403734bc48095edd750450e34f599922be",
+ "candidate/resources/js/routes/services/disclosure-authorization/index.ts": "aebee58e62b534e7fee4ffa4f0b59468f74e6d3241a3df3f6ec82cb0eeeb3b15",
+ "candidate/resources/js/routes/services/document/index.ts": "788fc49d84f061ac2a9463f0a426faa91a73672b7d1f757903d5ade5878304a1",
+ "candidate/resources/js/routes/services/index.ts": "c054234713b3a8ba7b100d3f81157311c2514a7da21f0f3ac1f3905b9457a04d",
+ "candidate/resources/js/routes/services/resource/index.ts": "7e3cd837228c7560eeab17119ffd3768d5a3c14fe78dde165ef25136e3720f28",
+ "candidate/resources/js/routes/services/simulator/index.ts": "4b3c3348d305728d8e137d3f00fde12302cdbcf18169a0c0eb009e12e552fec9",
+ "candidate/resources/js/routes/storage/index.ts": "1d45f745879fa7ee2de5fb19ea5dfd7f2db9751193b713df537975076a000ad2",
+ "candidate/resources/js/routes/storage/local/index.ts": "f9de215ee854b5edc57cec4b5faaba4134f964cc9444f88ce23c5ff3373855a3",
+ "candidate/resources/js/routes/two-factor/index.ts": "bfdce831ff89c0a0e2ea60474402c8a77207aea98c2b1202595b12c2a59e990b",
+ "candidate/resources/js/routes/two-factor/login/index.ts": "e8792a1cd96507c87d196b3e654081a4dd29d15ed4b2c80f8bd7ab8612103319",
+ "candidate/resources/js/routes/user-password/index.ts": "9a45ba5c7daaedfbd0609906aaa51388fed3dfce74497fe3e5e315a6118bf272",
+ "candidate/resources/js/routes/verification/index.ts": "39c3b48994c5a4e6a4882d3d589e89399cfa3bab50913dc97b22604cbe764da0",
+ "candidate/resources/js/routes/well-known/index.ts": "99b75be2f38dacf9bf6967d35547f6d8c8b8c4024662a8b14ae98013ee6098e6",
+ "candidate/resources/js/types/auth.ts": "68aa8fd778c6de04e926827acf5441d600daa088e5dbbb45b5a783c9ddca68c0",
+ "candidate/resources/js/types/global.d.ts": "18312397eaab4634bec6c20782b82fb05df0941559247642f155450362b2895f",
+ "candidate/resources/js/types/index.ts": "fbf32df1cbb06868339accdfacaba99dc3a64ba7237bc0eeb514cf4a6a37155e",
+ "candidate/resources/js/types/navigation.ts": "73331b328a9882fc02009322b4a7b87ccb6d6614ae12602c031ffe35269360fb",
+ "candidate/resources/js/types/opportunity-management.ts": "2714ea554d8096403092b3a83e3c32180689c0513821cf13dea762c8e5c813e6",
+ "candidate/resources/js/types/profile-access.ts": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "candidate/resources/js/types/ui.ts": "946e77884f2cf6cb152633033c88f21de4a7d49bc32dd186f45d86b5c200e47d",
+ "candidate/resources/js/types/vite-env.d.ts": "65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5",
+ "candidate/resources/js/wayfinder/index.ts": "3efc1c9f2eaa4828a4169414a1239420fc1bea8d3752fbd7a95b4a6da4a60d11",
+ "candidate/routes/api.php": "f0b1b2b6943d23d27d54f6ffc58fd5caca46760ecec97a6da85faf477e5fef4e",
+ "candidate/routes/console.php": "d0703e20fdeff03067521ccc5458cb98bd3fe6fcca58ea2b75e6775ab6ff205c",
+ "candidate/routes/existing-business.php": "ed8056dff6733f19574e021e7a18b0e099375828b3341dc906ecfbdb0af6dce5",
+ "candidate/routes/funding.php": "faaeb262ea7f488d640e2c142262505ba60c69008315081ad3726d3c5a0ed1b7",
+ "candidate/routes/investment-zones.php": "58d4f22ae503ac0f22694fe057082bc2a34d2af53ae06a0dd0af19cd9c443da8",
+ "candidate/routes/investment.php": "4b3ded8f81a347948278ffc677861d2b9d269f537cafcba61927332c9b470579",
+ "candidate/routes/investor-path.php": "55a5e93e072d5a95f95fb0779f6fdb08fcf4bfcc60eea108f06475b7f094e0ca",
+ "candidate/routes/land-assistance.php": "76522b6b78ab1a0319605aea5b57cca188e60a09ec2b5a6af4930ffb464b2410",
+ "candidate/routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "candidate/routes/procurement.php": "cea8e634e33dba8bf5210385f12a15a447d8ae50d71a81f7884d78a90f101e48",
+ "candidate/routes/settings.php": "db0137dbd4b668aca2367c8eeaac7eda168c307b4d8a9f24fd367a1fc9bd7f79",
+ "candidate/routes/territorial-registry.php": "f857f6590b09677f8625a937d2ab5da76baf409207b7ffee7900ea71ff46e3c1",
+ "candidate/routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "candidate/routes/web.php": "fc5e05a242a30865111c25f477cd5f94066450c17e9038ad68beb14f9164aea7",
+ "candidate/config/app.php": "a01f552093570f8744f7b874392824c15b5a6b49d61759273a658e8660a1d240",
+ "candidate/config/auth.php": "c7e204e9785c9f596d66fb884b493f658f2327f157646bdb4088efd6b3a7773f",
+ "candidate/config/bvm-admission-guide.php": "ad83d8937e684ed418726ba22605660946f77e82ed21e682ae0c033092add144",
+ "candidate/config/cache.php": "ee4ad2bba1edfcff52e9599f37371f2370d0b167cc226ce72d46cdf6edf2dc55",
+ "candidate/config/company-comparison.php": "403f441cfee35afefb79afaa380debc71b632afb7c9b94d223af69a3a355a4cc",
+ "candidate/config/contact_messages.php": "6e60e70736c2c8fd7bc6fef2bb0afb2a6f5b2dd3ffbaaad45dcba405e718590b",
+ "candidate/config/database.php": "02cd62f589b43d33f9ceac740705dac1dec9740eb2bb9e6e202d4b66a15244cf",
+ "candidate/config/document-requirements.php": "b3ccc0f1158314384b7a992a40def1af195b45c81fe1d4d62b57bf1264402356",
+ "candidate/config/education.php": "beea0a59c1078f3da63d9f020ac61ce8d1bc2310789feb314f8543cc8c32884a",
+ "candidate/config/existing-business.php": "c2c46436ad32dd52cdba99d2082fb8bd5d22e9aa486f89313c14bdc5eb6c3137",
+ "candidate/config/filesystems.php": "7e51d9aed3ee11bd8e15b6cdda38d02eebb378166cbe7c9f23980e1e6e3964b5",
+ "candidate/config/fortify.php": "bc7de1df10d3f66d02885afef6f133f54bb8e922fe5f7ed4088a16eaf13a6598",
+ "candidate/config/geometry-correspondences.php": "6eec57e1a108e82c51c9711bd2436f67e062e0c9058822efeaeef88a666b5cbc",
+ "candidate/config/geometry-import.php": "6bbbe72577bc3fd1123570a268af02015a3cc02a6bfedb2649d43e21e5b0f6f1",
+ "candidate/config/homologation_editorial.php": "2f68a471fd08e8b93443df559ace6ab08f98daf7f84967031e2f99dbb78d90ca",
+ "candidate/config/inertia.php": "80c68e12bf6cb64e39931e2467b43909893cea3eb6d04c3c1e68bdcb1236dfb7",
+ "candidate/config/investment-guides.php": "2a708217b108272def3da4d1ce8d9c08238241cc599672ea548dbb2591fbdf60",
+ "candidate/config/investment-zones.php": "415c39d3587e069989c211c6267a3ea7e224c501899dc59c028af6700119e646",
+ "candidate/config/investment_corridors.php": "b03ddd73013cc55d209180719bbecd4d24fce01282fa78f416db5f38970e3819",
+ "candidate/config/investmoz_ai.php": "587590b129e3dbd8c62b226cfbbae369763aa83b5cc098bf433e49daacd5324d",
+ "candidate/config/investor-path.php": "5ec167a443030389921973e4b3eb4319c8a79cf30496f67d9bbb8139e3ce88d9",
+ "candidate/config/legacy_content.php": "6d9377dfe0d3d2e3313c73b0b9ade2277056a8be2a3d6232fea7ee4a4b6381b9",
+ "candidate/config/legacy_content_aliases.php": "9f11923b98e1c4313af29db00ef1a3d590972546ffd3ee8356a415da79cec3d7",
+ "candidate/config/legacy_editorial_resources.json": "2a532f690e1dc029555057f14b1c74c4bf1f44761bbf6bbd7dd9f33e45e2743c",
+ "candidate/config/logging.php": "beb1ffd0db910f6f0b4f75214c3d5aa385d692733ece8a450f4c169d2c99ce38",
+ "candidate/config/mail.php": "2d0879e0900bdc95dc6611811a6eac4f88aefd1a1607f33349aee6faf9cfe381",
+ "candidate/config/partnerships.php": "bd38c86021ba6f92c904965f3f1f92ab482b636c730a8fa165162f1bd955d1ab",
+ "candidate/config/portal.php": "3dde63d0df01518aaa50772b6a94c77a38406fb3e790e1631f2ab7e6a3d990db",
+ "candidate/config/portal_profiles.php": "2e9e3d40277980c9fc139a51eb33212fe3df71a74397c353fe355a5642f99a07",
+ "candidate/config/procurement.php": "5ab2e43535db7895626e6a6cb87ffa189ae41789bbc7ad6e770c1b23db6d1bc9",
+ "candidate/config/product-experiments.php": "2d97d7f982c9c880af6667be8441d8f4375f03e433a859aa4344a58abea781b0",
+ "candidate/config/product-metrics.php": "b71947c445a1c32c0236979a9e301e26240f1ae43ef508657de42eac60dc98db",
+ "candidate/config/queue.php": "02cb2143bde722caef3d682474a07675cbc8b97952c632110a4e17058eaa3a9c",
+ "candidate/config/search-metrics.php": "0fead6254803180916c2fb3851e1551ccc1ff8a1a4d875592f258d8529382af5",
+ "candidate/config/services.php": "13bfdbddf1c35fc9a5cb3a8afa4564191e7f396183215be8772a1ff4f7559a8a",
+ "candidate/config/session.php": "272de4fd3ad8b806f5726a34d2a4ad11cbdbd4184fcad17143280ee2a8d4c7d6",
+ "candidate/config/simulation-fiscal-consumer.php": "25851d8e8be5453d10d1add27cbd8cf234f5f8a4ca95b3328fe69431eab2dc97",
+ "candidate/config/simulation-tax-governance.php": "7093ae54db600c42d18a97d00330d637ba8a6d76a12094209850c0cfed457a3c",
+ "candidate/config/suitecrm.php": "f217a1490dc597900adfac7bee2de00cdf8c8ecc2a78d5ba0b0f89beacc4b674",
+ "candidate/config/territorial.php": "7f5376cc8fe31e22cfb741a76545faca264b9879fdd02fd4af51458b0f67d6f6",
+ "candidate/config/virtual-desk.php": "e8dcbd93c06fdcc8de93eac9d9ac5d0959332cd35d2468123b542d289045174d",
+ "candidate/database/migrations/0001_01_01_000000_create_users_table.php": "10d79883bc08ce46510f9ad8b1830b4d06d586dc56ae2c8bac3b3e491f69a90f",
+ "candidate/database/migrations/0001_01_01_000001_create_cache_table.php": "fbb4665e5a977e71df4e74ec75b3c06ca4f17ad0de7138fe9786639189978e77",
+ "candidate/database/migrations/0001_01_01_000002_create_jobs_table.php": "df4910687180313a14a3f96a8bddd808ae145ed1b107cd772caf865c0dc2b746",
+ "candidate/database/migrations/2024_01_01_000000_create_passkeys_table.php": "3c866281584abdc808b6b6fe1d28aae55d997d3f97c5dd2d07ae106ff58531fc",
+ "candidate/database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php": "79f22594944d826286ad1dafb13217967781e104dbb021a1c85fbdf9270db4a5",
+ "candidate/database/migrations/2026_01_01_000001_create_sectors_table.php": "7c14fadbf9fff20df321e4e04cfabd63f6c73ef1a60bf9c16d9bf2d80b2662f7",
+ "candidate/database/migrations/2026_01_01_000002_create_opportunities_table.php": "6d3c9c9ed11bf20751e3deef2a67a07087d58a235c5611724f397e01de3dca7d",
+ "candidate/database/migrations/2026_01_01_000003_create_interest_requests_table.php": "a7ea8a534af29639254f8c2ba49ed80c5b9fca92b5be76d93f5b1c84b5b1a5d9",
+ "candidate/database/migrations/2026_09_24_000100_investmoz_extensions_functions.php": "3daa494165853ba673f99012ed5651cfecfba153c676ae4b7099b9e6596ade38",
+ "candidate/database/migrations/2026_09_24_001000_investmoz_identity.php": "f644b0369b17b2954b05f563a569d92533ae1bb06f89bf1cc8454d069b733b96",
+ "candidate/database/migrations/2026_09_24_002000_investmoz_content.php": "9f3006caa7092eb3651033d7756982b176a54c79ac47a9cf9a67c306e369a81c",
+ "candidate/database/migrations/2026_09_24_003000_investmoz_geography.php": "405a75432fb9b90b4472c697a9239fc8d59907da8defbb985cf81cd3da958ee6",
+ "candidate/database/migrations/2026_09_24_004000_investmoz_projects.php": "7b7f652cf323299c346133e7fda6564722eab60e8bba193387f8fa2af8bf2d35",
+ "candidate/database/migrations/2026_09_24_005000_investmoz_clusters.php": "93dc9bff75f759fc209f00b1bbb2d6727fbf4d3014fa368db394254789ad7df1",
+ "candidate/database/migrations/2026_09_24_006000_investmoz_corridors.php": "8061e16466dfd505785bdd233851216cd01a62397d144da2f9c996a15b5481cf",
+ "candidate/database/migrations/2026_09_24_007000_investmoz_crm.php": "ef49c4e0b15f1a0e2eaccc6c60b578e88a616aeb42e3a420865bb29aa83009a8",
+ "candidate/database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php": "f64af9031e071ff30b94df64c13f507800928d3bb54e5d7d0bd6a8f2c495cd51",
+ "candidate/database/migrations/2026_09_24_009000_investmoz_education.php": "fa6245b9a0a07dadd3512099450230919cfaa134c98b81c6362fb76abc9a3ea0",
+ "candidate/database/migrations/2026_09_24_009500_investmoz_document_links.php": "68601d5dec9410609ae34050b137b46af3d8e09e3510a331aa824fc58d01ed9f",
+ "candidate/database/migrations/2026_09_24_010000_investmoz_governance_ai.php": "c66ce3cf351a97f164c325c87941260a448b2b301ed037d251e0562143e48f85",
+ "candidate/database/migrations/2026_09_24_011000_investmoz_integrations.php": "3bab367d76ae5d3a9ef5836a95ddc41d01b35d24d119c7f1380b9153f4055b38",
+ "candidate/database/migrations/2026_09_24_012000_investmoz_indexes.php": "ff069e7a2cd518b104671bb2879444aba1df504fce6664cd61cce80038901eca",
+ "candidate/database/migrations/2026_09_24_013000_investmoz_triggers.php": "a41f8563aada3f3dba8882e67c3647fd1e9edc88f11b382af59399d380f6b83e",
+ "candidate/database/migrations/2026_09_25_100000_extend_crm_intake.php": "3a3dd9daa6d33f574ddb4b4ae10106785a5d4c32033d2df26370ab5f353930a1",
+ "candidate/database/migrations/2026_09_25_110000_create_investment_gaps.php": "ac63e17c82ffe0f3b7f8b123ba7b7758f84f81746446147b324b4c8aaae24d36",
+ "candidate/database/migrations/2026_09_25_120000_add_interest_submission_receipts.php": "d91b496f157bb4cfef1d4c3f90a9cbbfc58c4825a2b849cc089daacf199f7ff5",
+ "candidate/database/migrations/2026_09_25_130000_investment_portfolio_journeys.php": "fb568a7542308c8d547383a46178df65482351114cd11c79a36be53c02377988",
+ "candidate/database/migrations/2026_09_26_100000_education_intake.php": "f1be568973d1d36fadaa4596be3913d97915b78f749ceca67223b43eedf4860f",
+ "candidate/database/migrations/2026_09_26_110000_education_investment_proposals.php": "cb5424ac06378922e88c2e078a4dc43d7399f90ccb09bfc08b222f753acabd11",
+ "candidate/database/migrations/2026_09_26_120000_investmoz_ai_foundation.php": "a46234f6e9c6f4e7a9183591f1061109a579551c83596f8a5f05677d508bc114",
+ "candidate/database/migrations/2026_09_26_140000_portfolio_owner_approval.php": "581a459ebdbc13649926dccdb1510c0d18d098cb61d14b829d7e29128b28bf4f",
+ "candidate/database/migrations/2026_09_27_120000_public_portal_services.php": "78b52a15cd5ff297ab894ab11d2a76c46ad42b91622b866bb7c885e96f00fea3",
+ "candidate/database/migrations/2026_09_27_140000_investment_unification.php": "13f7dfefb524b60ed5e64d04a74961c942484e7bb2dfd88bf05847aca6f8ff23",
+ "candidate/database/migrations/2026_09_27_150000_investor_workspace.php": "e0a8e15f190c167d9ee8003a126ca04b63e8403d1cdd2bcd80f1e32a2e445005",
+ "candidate/database/migrations/2026_09_28_090000_version_investment_dossiers.php": "0799712b2fa00243f51a61f67333946fe88806d1aaf2a4df844de9f3e70b0433",
+ "candidate/database/migrations/2026_09_28_100000_investment_zone_foundation.php": "13272489c8d63a4691a59ede5c9d051e27c71d4f6d622fc36ec093e7645ceef0",
+ "candidate/database/migrations/2026_09_28_110000_zone_geometry_review.php": "ed1350417e63d83c568b526d5dc853f04629de5c45507ba6376505668d740331",
+ "candidate/database/migrations/2026_09_28_120000_investment_submission_zones.php": "005df60312dacd190f11c5fccf34ed7d499778fecac22e319b73d6f038d67680",
+ "candidate/database/migrations/2026_09_28_130000_existing_business_foundation.php": "70a11a505c2bbff501f8e175d60a1dc5dd31df127cc6fe33c908bfdbe4fddf7d",
+ "candidate/database/migrations/2026_09_28_140000_existing_business_intake.php": "0b438174960ec39b905ec352d227c1eaa475a11e122069bcd6bb9aa3b1b78fba",
+ "candidate/database/migrations/2026_09_28_150000_territorial_registry.php": "deec29bc66e1c3c3f3f36d2345d822665192620d6af8e5931000b5efa1bec274",
+ "candidate/database/migrations/2026_09_28_160000_investment_primary_territory.php": "5aef6eade1a1ef59aa173941d62342f526edc5075262f2812cf00605455b1981",
+ "candidate/database/migrations/2026_09_29_100000_territory_integrity.php": "e01f43328a121f3b8e5ad3e1e2b38cf5ae6cddda3a7e7266b57619a1b82bc92f",
+ "candidate/database/migrations/2026_09_29_200000_existing_business_form_sector.php": "ceb4080d5fdc8235a400d8b665156f1aed81c8f96ce92cff41325e5a00e40f6c",
+ "candidate/database/migrations/2026_09_30_100100_skills_education_1.php": "024c510fc512d642628bdd50e1b7cb6d11b6f7af5a2e31927b626615cc7e1bd9",
+ "candidate/database/migrations/2026_09_30_100200_skills_education_2.php": "00aaf84c56e041072ca3203fd39edc81fe2c353e4fc70b715e7c290c1e3c2280",
+ "candidate/database/migrations/2026_09_30_100300_skills_education_3.php": "d009706676e62a9ee3fca6b208d3b13c17141d8fd701f647f32e6404cde0b2f4",
+ "candidate/database/migrations/2026_09_30_100400_skills_education_4.php": "c8b2a61c5faa6b0b55a7188f0273b4f7cf2e33fab83a3bbc67db7be96c34658a",
+ "candidate/database/migrations/2026_09_30_100500_skills_education_5.php": "5c6fda4c6fb80cf37ebed1a39f16b2d86e8c96ef10640abbbd10dea65468e27e",
+ "candidate/database/migrations/2026_09_30_100600_skills_education_6.php": "2d46e02f41242f7045d0b230c9bfaf1d701a3baa2834e8c40708e6001412daf9",
+ "candidate/database/migrations/2026_09_30_110000_project_dependency_integrity.php": "f249120f0f643093a1c640cbbe18124b78e5f09e391527a5a662e457efc8d1d9",
+ "candidate/database/migrations/2026_09_30_120000_extend_existing_business_marketplace.php": "92e2720c44dec895b52cc4a29b779c1c51164bd925cdf50aeee79f125de20ca1",
+ "candidate/database/migrations/2026_10_01_000100_create_reference_catalogs.php": "8eeff960ac42fbb6032cc4012630f72c420f665a834d6ebda42c577267a60acb",
+ "candidate/database/migrations/2026_10_01_000200_create_simulation_execution_core.php": "1468ce4dbdd95b17c2d70c135b0a56a0b505bed5f6646de599326779e2557ea4",
+ "candidate/database/migrations/2026_10_01_120000_create_simulation_form_drafts.php": "3fc94c8302a6dd812c8e8d4be020b23697274bdc261755e77d1d2719de2ff988",
+ "candidate/database/migrations/2026_10_02_120000_allow_owner_to_read_soft_deleted_simulation_drafts.php": "d595329fe3a6139d71005e4921f315a505cc2994c320a07f0fac8254144f15df",
+ "candidate/database/migrations/2026_10_02_160000_extend_existing_business_opportunity_types.php": "bcc18791582d2d3d971ff17e2c880bb05ed7f4933780bb6d9723c1dd9fada7c9",
+ "candidate/database/migrations/2026_10_03_170000_create_simulation_tax_rule_governance.php": "45ff5ddc7605cc0d240c3c8f93b8a73dfc1a721cc3ea1841b365c2c6403b90fb",
+ "candidate/database/migrations/2026_10_03_180000_govern_investment_structure_relations.php": "af7c896a3c198ecfc9e186542bf22cf99e9f81ae0981caf4101038d0944366cf",
+ "candidate/database/migrations/2026_10_03_190000_allow_public_read_of_published_tax_parameters.php": "0ecf6107cb21a8af02b4b80c2804799a934bf5f90a599dc8d0fd6388596e5a53",
+ "candidate/database/migrations/2026_10_03_200000_create_land_assistance_cases.php": "d02e00e88ff9566f71e734651c5fc4f6f8d1963a94cca0e57f71f0de3815ce5e",
+ "candidate/database/migrations/2026_10_03_210000_make_interest_request_email_nullable.php": "0f4e014ff0ac76ed9b2e7a7d3d815c10dbaae7e0b9e08d78a955649a2fca2bf6",
+ "candidate/database/migrations/2026_10_04_120000_add_opportunity_geography_scope.php": "f877d0e33d85a27051038ed952d0e6fdc532f6c29e6a7e4ee8ac052663926563",
+ "candidate/database/migrations/2026_10_04_120000_add_simulation_draft_continuity.php": "9c2f83cd5d3257b4ff63c91bf92c859432635b1f53b16bdd1037457916e9ada2",
+ "candidate/database/migrations/2026_10_04_130000_extend_investment_zone_records.php": "bd7fb6af86073cbbfb03e219c8401225eb09618a0b538245a2d0f581c945edf7",
+ "candidate/database/migrations/2026_10_04_140000_create_investment_zone_attachments.php": "f5bb1afb2fc90379749b1e294b73e6c383ccbbd4f68417a5612c5d3e78619a9d",
+ "candidate/database/migrations/2026_10_04_150000_relax_zone_operator_publication_requirement.php": "807d4c8a7c143a8c01058dd73e607c0d805c67aea7fd20ff108365b87a11e46a",
+ "candidate/database/migrations/2026_10_04_160000_extend_zone_development_and_area_scopes.php": "041c09d968c921aa27ece295f3a904feb701117fca42053133ec09e56dfa0fb1",
+ "candidate/database/migrations/2026_10_05_120000_extend_portal_document_catalogue.php": "d799fc0feddb6839060c3997dcfdbd32283b23b24d3ab5fb2626ab070eae9490",
+ "candidate/database/migrations/2026_10_05_130000_add_document_malware_scanning.php": "6e968d047ed54ecd88b37689e1b2885e23cb51b67596dd982902d2db26ab09ab",
+ "candidate/database/migrations/2026_10_06_140000_allow_unapproved_private_portal_resources.php": "4683ac0861dc0b66f20b8b6dc06369ad007272b1cdaadd7410efb987b0c9458d",
+ "candidate/database/migrations/2026_10_06_180000_add_document_applicability_dates.php": "6f3389c323741d2947bbbbd5f2002db18aa9babc4d20c63d4a3d48bde8923e08",
+ "candidate/database/migrations/2026_10_06_200000_add_document_requirement_evidence_links.php": "935d36cdd2d08487a31a426a9676642c37f1262fa30ce78c91d203a925c8f867",
+ "candidate/database/migrations/2026_10_06_210000_allow_informational_zone_publication_without_second_publisher.php": "fe33d216608040be464cab06d75efbc23340d4e7ccd259dfa7d0b909802a08da",
+ "candidate/database/migrations/2026_10_06_220000_add_company_purchase_business_modality.php": "7df04852ef45a7c33238f23a8274f63e2d187d58f56b7376b037e4931d655ce5",
+ "candidate/database/migrations/2026_10_07_160000_extend_internal_partnership_exchange.php": "558ae77d99ad35b32719462bc773e159c62a390101eecc827d7f8b74fc129784",
+ "candidate/database/migrations/2026_10_07_190000_create_internal_virtual_desk.php": "4a91b9ae313084feb913533f79ce2c61662c2110d38dd5effd98f6cd6fa1bd3f",
+ "candidate/database/migrations/2026_10_08_120000_extend_desk_investor_guidance.php": "bec56cead85748e3c28bba21f79086984d177d63b5194a38b385d7b2e19ec4b5",
+ "candidate/database/migrations/2026_10_09_020000_extend_opportunity_management.php": "8a804748cc6b2b537bb7c0e10e09dff3dc4d89b6c974b9f909a198adb2dd048d",
+ "candidate/database/migrations/2026_10_09_030000_extend_opportunity_resources.php": "d4e5c753ede8216e1d383865178c6db37c5422c21c3c8e7458cd4ee1e68659ed",
+ "candidate/database/migrations/2026_10_09_190000_prepare_investor_path.php": "939c2b2e5f9fd6a454fe7f8dd4f4373fd7df53f80e5c5f169db08e6e4c676728",
+ "candidate/database/migrations/2026_10_10_040000_create_portal_profile_authorization.php": "797c27b5f201b65e825fbdea6fd0ea49de2f9d48b1a9bf210d76af285224cc93",
+ "candidate/database/migrations/2026_10_10_050000_extend_organization_country.php": "1f4556f9c38c4b3aa85e34281ba3fc4113a61eab0f1d64193711a67e7ab18d30",
+ "candidate/database/migrations/2026_10_16_120000_extend_economic_reference_hierarchy.php": "c9ec8925487ac530a763dab50450457888dc6956a7fd561db197256f02e362a6",
+ "candidate/database/migrations/2026_10_16_130000_add_investment_zone_editorial_draft.php": "4cfadc6c3d3a7211c276d8df75e1ca687d5386c65d94ce4d025ba4153b31d8ce",
+ "candidate/database/migrations/2026_10_16_140000_add_investment_zone_operational_details.php": "22d78b712b39da0044aff727c49c68ebc32cca80c2cedec450c27a9e3804e13b",
+ "candidate/database/migrations/2026_10_16_150000_create_investor_navigation_preferences.php": "4239847d4828f2c0dda0dc609e420bc0683e7a73633a1eac84eee8e0b87f2aff",
+ "candidate/database/migrations/2026_10_18_160000_add_portal_editorial_content.php": "9a1ff7ed29c081d8b5cde60a349921e63998653e91f3277738ad921a54cde2c1",
+ "candidate/database/migrations/2026_10_21_130000_correct_fiscal_maintenance_actor_constraints.php": "49aad23e494914ce939f29929a0a934251c6096ea88d85f0ffdfcf86944af61b",
+ "candidate/database/migrations/2026_10_22_230000_create_portal_tenders.php": "03f8ec30add71a355f7ac6a55d4b0f4ab7d70f298142788a4ddceb2106f5fe9b",
+ "candidate/database/migrations/2026_10_28_180000_create_proactive_supply_observations.php": "9058739b3305490f6184899d19505760a07df1fe5262d638e0cde12b92a99669",
+ "candidate/database/migrations/2026_11_02_190000_investment_opportunity_alerts.php": "df8494f35f06be6a355f4e71d266c1ad65bfdb65e03ac805fe832f99dbe0ab10",
+ "candidate/database/migrations/2026_11_02_200000_investment_tender_alerts.php": "02fda526c23e68775fa21d7576f9208e73ba7363980c17c53b6b8eba49054200",
+ "candidate/database/migrations/2026_11_02_210000_funding_programme_catalogue.php": "e03539e09c65706904d224a0c93b793ece1487f8f993b4482ba227fea3baf429",
+ "candidate/database/migrations/2026_11_02_220000_investment_funding_alerts.php": "c754b81c45031b7921ee079ff9057d24c53307a6fc619c8ebff8426c4f60e3c6",
+ "candidate/database/migrations/2026_11_02_230000_education_declaration_drafts.php": "58e5bbe5ad1f613eac731e46977e9c8f35827b74854e6dbd30b13954529692df",
+ "candidate/database/migrations/2026_11_03_000000_existing_business_location_sources.php": "9c22cebb812933d7d9d35e631f9a9fff1759b879b8adc07406229a197384d4d1",
+ "candidate/database/migrations/2026_11_03_010000_desk_service_effective_dates.php": "dbc7b1da1f25be4d0bb85bd599e39fd4008e9a568c7b6a26d3211dfec941c73d",
+ "candidate/database/migrations/2026_11_03_020000_create_product_experiments.php": "fc85caabce7d24ab74963d343c0b49ca8fa96c0abb8566668026a9cb503f0e20",
+ "candidate/database/migrations/2026_11_03_030000_create_product_search_counts.php": "4538fd1a259d42122e301fef8ccc4968dde1af9aa2ed61e4a9520812823c5676",
+ "candidate/database/migrations/2026_11_03_040000_create_desk_request_checkpoints.php": "8b56e42c04fa2f541beb649d94420dfd9936357a4adbf5298b4fa3453d5e822b",
+ "candidate/database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "candidate/database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "candidate/database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "candidate/database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "candidate/public/build/assets/about-DOwzawT7.js": "59f401ee0512c936b14870346bb28ef0845744b8123b7810df3e87d0d9720d4d",
+ "candidate/public/build/assets/administration-B8fo3qS_.js": "77ee0ef3e5722182ff7f7ed17f08e98651009f826cfd16718c951a9e815d2ab0",
+ "candidate/public/build/assets/agreement-history-ChQ1_TWp.js": "327e211f0e58daccf71bcc68c0fdae10122e4a863420dc5fb5b5f1fdd61eecdb",
+ "candidate/public/build/assets/ai-oIebomFY.js": "d3dc433d9b4a140be858da9f875fed93cb7274a069641a00935144d22aa9b662",
+ "candidate/public/build/assets/analysis-BgRHQNk5.js": "79a4c30e4285d8c2608359bb9545fc126761905ce0a543d869af3fe49c0bfe83",
+ "candidate/public/build/assets/app-7htJG41G.css": "bbf1f9146ebb19cf9692cf9564966d237fadbde08dc90c6f5f2307b15757f4b9",
+ "candidate/public/build/assets/app-iIWdvtwu.js": "f181d1659b82f015392711775a0d81ebc53bff83aa1d46fd092c609f2efb4615",
+ "candidate/public/build/assets/appearance-BF-hcFc6.js": "146c19c641aaf4cb0b66fd873c72ba0625cae5b984cf5c3707f4ef482153ed16",
+ "candidate/public/build/assets/arrow-left-DMVHIw8Z.js": "9ec58ec8d9c54614b5ce470c5bbd97bfe9e572373df898de313269f806d863f7",
+ "candidate/public/build/assets/article-C8DAcoBS.js": "3f70becf434756f204adb9ee281aa4b3295b4a294936b26424295e8f45a3c004",
+ "candidate/public/build/assets/article-editor-B5f_0blS.js": "b4b04f303f41c53e65dd3204340fbe214ed56be5c76b73d2ab98bbb587be3000",
+ "candidate/public/build/assets/audit-DLb9-pPr.js": "046c9126ada7432bc6c181e07cfc03090a58e1b117c90de69f6cc232adb25f61",
+ "candidate/public/build/assets/blank-2jFZEe2q.js": "9e53a0a455027f070e3041db1f445e8b63702f83e264442d8df87e20048ccbe9",
+ "candidate/public/build/assets/bootstrap-confirmation-COhDFEZl.js": "6e2ca38729f03f8fd71994899ddd0523c7f809d34b428567a5428b9dc81066b0",
+ "candidate/public/build/assets/business-BaLef040.js": "d54228171bd0e4387301719a56b2ba64f0e83d9bc82e948ad0b90879e457c93d",
+ "candidate/public/build/assets/business-classification-DFSuI_LZ.js": "ec3c30705a6017502b2dc2e5fc59e19398222b215c59f29beeae200fb0ba7eda",
+ "candidate/public/build/assets/business-financial-plan-2g7oFAFp.js": "02c2a5a04fe050505078b72161b4b370b37ff0fec001f9a8f3e7f1ece090586b",
+ "candidate/public/build/assets/business-interest-BOsQXwrP.js": "abc184244db732f2599866a1bf6f1b1115dc1d633754dffcbf197495fbdef665",
+ "candidate/public/build/assets/business-marketplace-BBA73gh8.js": "0a7e7ee05f86b89d6b777d6b5012dc8b3dc1fec02b47268da448fbc174479493",
+ "candidate/public/build/assets/business-objects-Cr7GHu56.js": "932f9cf0970ab99d12b3841316096bb7d1e192ead627a5a74273b4bab0793867",
+ "candidate/public/build/assets/business-opportunity-Dm3vHwnF.js": "571cc5d026cbbc663a7e5fb4c77187cd8d4354608a297f3dfcbbcbf1c33218ba",
+ "candidate/public/build/assets/business-types-SGCXhH6X.js": "c792ab88a79f57c74d865c47e89e7f2b9aea190acb5c8c676071d4b0a802d58c",
+ "candidate/public/build/assets/business-verifications-nL074577.js": "9d005317fbe188bcffc80998c16fed139d773be76466b8d9464cae42f47f7b17",
+ "candidate/public/build/assets/business-wizard-Dh-jU1yW.js": "b43191c72e1f34e806c575b5b971ce5a5dd772a1307e8fbb98bc6fdc7df4a785",
+ "candidate/public/build/assets/businesses-CZ0eKwCp.js": "a8254e5cd0b44fbc0002938e2c546d944916858c9d2e3fa245d3df17b4291804",
+ "candidate/public/build/assets/case-CduRUkJN.js": "f47d435bf1316961439756ed489109977aec74e678db30ecb5a674261fd4b56c",
+ "candidate/public/build/assets/case-wwTeoOmv.js": "639eae3b1487dc2626b306bd76a5a3d7b0302f769f2eeee75f62dbef2b7e5d52",
+ "candidate/public/build/assets/catalog-DxYT65lu.js": "9c1c5e064c37db790a72725d7b61da3d10c2892c224803d6757ffcb8ac5a217f",
+ "candidate/public/build/assets/catalogue-B63U8wBk.js": "c87dc373ddfe4ab758a33dce5e077389b4c7ef2944c5b5a6081aa217166dc3b2",
+ "candidate/public/build/assets/catalogue-BKq_HYhp.js": "647da0881c7d4819943db41f23589e719f95e7f6c1efedf6cba5e37f3333257b",
+ "candidate/public/build/assets/catalogue-C3g8uqsw.js": "bf33e6b5f040d1807ae88a42098e8ebd82b9b676c43002ed5f7fd3e90d0e8f3c",
+ "candidate/public/build/assets/catalogue-context-QGgogMVM.js": "254973fe69ad46969b1fea47a4aa3097b3c597a94b9e265ccccfa05d4b5e8953",
+ "candidate/public/build/assets/catalogue-investment-map-km-NBIOE.js": "7ba5590400b6e56bdfd217c63b6103158ad6fb461beba78d0ee3aac7c7bd7fc0",
+ "candidate/public/build/assets/check-PcBNn_NG.js": "402150a0f6387f9f098fea689a3282723ee063c84e57651f25d35729cdd85063",
+ "candidate/public/build/assets/circle-alert-uV7omYjr.js": "15d17f7b316f92a6971a471dc51b80ac7c0117a7ba2454e57937ad5b179d4b48",
+ "candidate/public/build/assets/cluster-competitiveness-hNV0FaaW.js": "78ed6d7f859143cda02cf336c53b71bde73e268a9a13d765c43b68030e8a5cae",
+ "candidate/public/build/assets/company-comparison-Co329y7j.js": "195026c6e8eab13804d9be1b823383d5f679069eccc0d5fce68186e0aa89aeda",
+ "candidate/public/build/assets/company-comparison-qLTgpXjz.js": "6ff7e8725be0a2c1249f1c323a60ceef2d83df3e8a8bda6de6cc4777fa4f30d5",
+ "candidate/public/build/assets/company-preparation-fdrONzay.js": "d422b274fa99bf536d74f20dc22fb5a11b3dc11a853eed2150621235cd650eb0",
+ "candidate/public/build/assets/competitiveness-BEx21JDJ.js": "ecf95fcdf4d46b47b7be7c097d834c03802ba5e9012715337dd535d9471dbba3",
+ "candidate/public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "candidate/public/build/assets/confirm-Culw9Q-x.js": "263fd058f1562c5729a4091d5d60f5365cc3957ad2cfcb5ffdec04a28f1858c4",
+ "candidate/public/build/assets/confirm-password-CuSJNS5u.js": "be5c36e13901e647330468fa4f9f532050eefbaa9dcede2cfe50aeeb7b606c2a",
+ "candidate/public/build/assets/contact-Bv4XesVC.js": "0592fb1a2a1d4a6807370ce4fdda51a2751cf355cb0d6b404eff25b221311a3a",
+ "candidate/public/build/assets/content-hub-BUgwQZim.js": "31945643862bbd2714d6c8184a9bfaaeed013f6e19598af0b73d820f5dac30d7",
+ "candidate/public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "candidate/public/build/assets/context-1jzAPrHy.js": "b4a0757285083571fda3365f0f685ef1d31b196972810cab66fa7c29d551252e",
+ "candidate/public/build/assets/context-documents-Bh7vrWBo.js": "8a00d391cfbd7abc9d3420856489ae2c7d322289204095c3e1a1b534c5c1efdc",
+ "candidate/public/build/assets/context-inheritance-CL4H6SWl.js": "931a8eefd5578ef1f2e446c5dd0905abecbc914da5cd3075ee722aef9d3fef0c",
+ "candidate/public/build/assets/context-installation-PunBLE_R.js": "db21eb14bd18f7de48c3328c401524d18f039978d842761620517d229c41b95e",
+ "candidate/public/build/assets/context-lnfS2wDm.js": "9f7ff4936de8c34bce90b8eb1d205a134842863eb13833744c177934970490d6",
+ "candidate/public/build/assets/context-start-CXLZGLOm.js": "6f4d814623cb05e02a1992775f75b561386cdeb5ebb611a39ef85d47c0d7b4db",
+ "candidate/public/build/assets/conversation-Cd3rNlTM.js": "5166a80f6e5c1e86a25c8249f0d0dbfccac77f96f4a0bd11879d50cb8f0da650",
+ "candidate/public/build/assets/convert-DxAfmqdS.js": "052bb7eda95cc3ba8e9e9bc9084f68c0de50a2f2c36cdbd9540f33fccb526164",
+ "candidate/public/build/assets/corridor-agribusiness-Cl8IHWhu.js": "f39ef0a25b478f18fcc0535966342e7f2500ce567dfc40d344e69030f52b8c99",
+ "candidate/public/build/assets/country-select-4uP5BvMf.js": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "candidate/public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "candidate/public/build/assets/crm-edit-comparison-Db53T7I7.js": "c383a7770e8b3be85a2d42feb7ce013755e789a3233a2d970f7f83603ddb49dd",
+ "candidate/public/build/assets/csv-BGyW-a44.js": "329cfa841754ed2a3db324cdb749a0ba328bcd4b412610cd9dfcf9d413bd88ad",
+ "candidate/public/build/assets/dashboard-BoSJIVob.js": "8d33873de6564d8e963230687894754197cfa8ab7cc1afe0e5a58543a58ea59f",
+ "candidate/public/build/assets/dashboard-BUJx7y5Z.js": "49adb43cba4f7b4c6288bb03bf80b2acc3fe846b50ca5263d08f37aa39bfaff1",
+ "candidate/public/build/assets/declaration-DIeC65eL.js": "220b257d1fa0f0f4ee6b6abb5af697783086d30a4bd3d4d84088497d056c99a1",
+ "candidate/public/build/assets/desk-assignments-CfWpiIpK.js": "13e7d419df2a123dbc27c470e72a86f69160e7ae5f9316ef5736f65dda57fe2a",
+ "candidate/public/build/assets/desk-internal-operations-DUX7k4fw.js": "96212aab299e612f7ca13539b0f9cdc77ab03f1f21e67cadc2001ef93d00c624",
+ "candidate/public/build/assets/detail-CLHJjbji.js": "0b13e47f10e7b17a8cc090adb2ad2ee451045bfa068bdfc8067b419ded76e909",
+ "candidate/public/build/assets/detail-DyDsOeRn.js": "e0ad6fa6a6cedf7626b71745bfe896f6eb106e6e300fd360e283c11e3c25bdc5",
+ "candidate/public/build/assets/dialog-C_UQ3Vkt.js": "8365312eab699593e7e2a99771f67714006a0d2a7a4f0b8114b594c2e83af2bb",
+ "candidate/public/build/assets/display-value-DRR1EAAK.js": "202c77561454ec7c1ef9cb39faa4f1833ea066dbb83e17f0eb4440b314b189f6",
+ "candidate/public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "candidate/public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "candidate/public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "candidate/public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "candidate/public/build/assets/document-tkyG9y70.js": "4e6ea2cfd5d769f56d0eab650834b3fcb563fd6e5a71bb88281758497f426cc3",
+ "candidate/public/build/assets/document-word-CqTGSyXu.js": "f29119ef757da76396aa9791b64a284b8e274ee2d8f0e54817ee2711c7ccfe4f",
+ "candidate/public/build/assets/document-zip-bqFSTgG4.js": "0d06e6e95ad699cda332b2a993375adec500000c16cfa1e9e7c945791da204da",
+ "candidate/public/build/assets/dossier-prefill-CrneMRwc.js": "510b03d010820ef0026b1acf3bd5287f45624343e91443eccd072c1f9425c9c1",
+ "candidate/public/build/assets/economic-references-CA8ZhsBm.js": "bb35e6d93b60f7d0c469750cfebbfbc97f6e038e5bbac96fe88788450dc16828",
+ "candidate/public/build/assets/edit-7eCRz1wR.js": "61b0f962183460dc38131518ccbafab80e7182bd6135a7966644402d2b6a0e11",
+ "candidate/public/build/assets/edit-B4I1udA-.js": "1a444d1bc17a22a24db612cc9408493176e6697d6de8fc2aa24b247e7bf1cbd8",
+ "candidate/public/build/assets/edit-CPt5XV9w.js": "b9a0b5c3f0872a15e3e3db528036978dbe0ba91df3c9ee379867a647926b2866",
+ "candidate/public/build/assets/editor-BkQqIBb_.js": "8065543098560a2f2ddbf44781ce34faa26348ac0421d9489547f7acd14e22bd",
+ "candidate/public/build/assets/editor-Cosf-w7f.js": "f892ccff1cc487b363a706b94f5dc4c69f8437d9d412b8d3272b64185eac6e90",
+ "candidate/public/build/assets/editor-D1erSdsA.js": "b43a5241bd2d18f1530a1ec098de773e131d1e06a4886311b68d69b9c98d9c4d",
+ "candidate/public/build/assets/editorial-reading-DUFQmJtD.js": "5cb94547cb7ab0aec62d2411afcf5cf430683389a3e4ea6946adb8f01713343a",
+ "candidate/public/build/assets/education-BBFCVE0z.js": "1f8b3180e90143ae2f4610556ee75e5a6430f0251d5b2c743dbacc4328dd8e82",
+ "candidate/public/build/assets/educational-article-card-0rCqZ1kX.js": "e726dc23f99c4aaeddef1676dcec9ba9cf4ba0198da907be17b224c2f05b83e7",
+ "candidate/public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "candidate/public/build/assets/experiments-Bom5IAgn.js": "ed5237eb608164dc74958a88c5f817bd4485b95bc29fdf68b881bd34ce354e71",
+ "candidate/public/build/assets/eye-CmcEBfxN.js": "dd634c29e3dc10966aae3025c0ed635bd2aac44904936dc620f5fd1974c15676",
+ "candidate/public/build/assets/file-text-_AOa_djl.js": "1d6dbbdc3a8c4d4eb587a1ba015ea67257078b28a6116a7e67a27653baffe738",
+ "candidate/public/build/assets/financial-calculators-Dd58p61y.js": "0996f34a3629cfb938de84034c5b7e53e78547080b524392e0da09e544ca2f73",
+ "candidate/public/build/assets/fiscal-forms-CJhSTy20.js": "46f3640ec5f583f4bb2807e583ba378c74affcb61b69c7739c1f5cf5279f5686",
+ "candidate/public/build/assets/fiscal-qa-review-H7aeeTzC.js": "fbe5808328753ddb74173a28cf61972cce791c166055c481196be900c893d1aa",
+ "candidate/public/build/assets/fonts-C9MNnjVw.css": "3846a9bb60bfad92960eadcccaf0b4e129d74b11d48791506c8d1a827a385cc8",
+ "candidate/public/build/assets/forgot-password-CA7-ONOZ.js": "70812fbf1beb9172cf3f09af99cbe37b05ca347c70a4ab45ba8eeda4623fa762",
+ "candidate/public/build/assets/form-BY3eswO9.js": "9ef14ccda1b0e9b69fa53ba5adb9854e9f9b9f2c8ee9802ef02e81786c1d6ca4",
+ "candidate/public/build/assets/funding-Cm2s-Ywy.js": "22d0f15ff3fc3175524721fa6c4a6b89e052c36c5cda4e6d87a3974168fac780",
+ "candidate/public/build/assets/guide-AUMqcYba.js": "852aea0f775cb6799da0cebe3f1d82c45924936d731e1a41744cda76489d1e3c",
+ "candidate/public/build/assets/guide-mndEuKFT.js": "fe519ab69363e83bb705b7dee5ab3fe17249eeb53687846b539668c435ccbd2b",
+ "candidate/public/build/assets/history-B6qv9JxG.js": "74303512e23bd37cc51879f4ec4cebf197445d46312a2535bf84050a505b23c7",
+ "candidate/public/build/assets/input-error-U1QKS0ED.js": "4acac92fa624552b14ac1a390e961f9e387d6eefeac384ad4e95bc73fdffa86e",
+ "candidate/public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "candidate/public/build/assets/install-DL9LxGxj.js": "05e38e5292843f439a7d103db522fc990aac36f766051a5bdf592a988336c8da",
+ "candidate/public/build/assets/installation-CAP0qPX1.js": "f83d3905d880d23cef2db033593f91c414b2aab247758f1be21fd3f9e98b04c7",
+ "candidate/public/build/assets/installation-DO8A-JbS.js": "1f2a46ff0f6f7e0513b46988156b3c95baa7faaa46170e6c6aac527d8aa6a57a",
+ "candidate/public/build/assets/instrument-sans-400-normal-D1W7dsQl.woff": "797bd3eaa70edbd4757650ab44dad75fbfbfdf18bacedb4b71022c04621d30ad",
+ "candidate/public/build/assets/instrument-sans-400-normal-DRC__1Mx.woff2": "9a91efaa3599a6ef01b2f49e9ec670e3a2f39baeef09c73198f1052cf3bb0850",
+ "candidate/public/build/assets/instrument-sans-500-normal-Dk9ku72i.woff2": "9d3547da16d950d12a677c772a3ff9b69846e60e7dcd1b5efd540993f7286532",
+ "candidate/public/build/assets/instrument-sans-500-normal-Z6ESRlEs.woff": "bd6a8dc8b0dc0cced0c32d3eda93f0e0e82c58ddefea8b53b3307b0c48da3089",
+ "candidate/public/build/assets/instrument-sans-600-normal-B7fBEWYG.woff2": "efb770916eda95a0e31d80cccde9651d4e8617010b21220e9f227c4820d675da",
+ "candidate/public/build/assets/instrument-sans-600-normal-B9e8oLYv.woff": "9b4ce1f2b26be7cb087fd87d6f99a202136292ec820af75bd38ab9e53895cf28",
+ "candidate/public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "candidate/public/build/assets/interactive-investment-map-GeBxoeSM.js": "502ae8a66dee0f547c58eeebfdddeba680ac7849a18cd69363b42ca75fe99ce1",
+ "candidate/public/build/assets/interest-BHQ_zfa4.js": "95e7179b9b87637ad1afaea1e2c46ff43dead1e7a17a90befd4d6d390f495b6f",
+ "candidate/public/build/assets/interest-history-C8RlGZ6v.js": "f7f0319f7c93cea05b6dd88058dedea3017e0ff5964c6f21f79bb17787087b96",
+ "candidate/public/build/assets/interests-Blp9QYQM.js": "70485e8c6d8ba3c9dc1fa3b106018ab2a5e4a0faf7b9db5ac93d0cc87a61d720",
+ "candidate/public/build/assets/investment-complements-CUtqhP3r.js": "e2a8b6a29b7e4c56e7cb03b86b44fd6df454c146f003206d43fb86ad26a3aee6",
+ "candidate/public/build/assets/investment-consumer-identity-Cxp_hGfX.js": "fcba768df7186f983eae0102e0e5a96192a55cfba205f890d884563c57e179f7",
+ "candidate/public/build/assets/investment-context-cards-gJe_oyxw.js": "ab0861f87f03c6aaf02aeede85a3ebd274a857bbf64c2c712a6f7a7b90e7cfb4",
+ "candidate/public/build/assets/investment-contexts-BQGiwu9n.js": "f4b3e7365c1001ced3794ac21d6995db2d33021e666d7a82af8994de20f51ec7",
+ "candidate/public/build/assets/investment-guides-DO58L8zr.js": "4d24d02865b3c81513def6e3c24c64d39af8bd5dd2996eb531b1834d49136274",
+ "candidate/public/build/assets/investment-land-preparation-8mamsDvk.js": "81ec3e3b379a9904beb1e7626c10eecc00d5ac3f3409b715857bd34c00f20104",
+ "candidate/public/build/assets/investment-map-panel-DRYv9Yq6.js": "43b42a5af74ba4257bd004b5fd7de46acc6590746a170f911d9b88225ff47e2c",
+ "candidate/public/build/assets/investment-opportunity-choices-DQK2kRcc.js": "e62be89cacaea627c5ad412c6e09bde25ff2001ed2c4691524a57cb16a447319",
+ "candidate/public/build/assets/investment-territory-DzvOIog0.js": "02f7f13644025eae10f303a71a001dcc4e10c0d1042a3d830d08671eb318b127",
+ "candidate/public/build/assets/investor-CDW7bifs.js": "c4dc84b4d3e2bbd622eeda7a1843f4ade3c3c86985f59d434e8ba7f4c4c850d7",
+ "candidate/public/build/assets/investor-path-Bj5dvU9U.js": "3ddb0b365c5b8837459626def7f17a7963c495ef471f5f103774401b65c8e73a",
+ "candidate/public/build/assets/investor-path-E7BRXPOg.js": "5c7dfa213ee480e2cf446da2ca7e1d3f69107373b7988321e3bb80f577ad045f",
+ "candidate/public/build/assets/investors-8LvOMHEx.js": "ddfd9150d67e5cbc2e6092f497f8e1f41faf38e384f24d6bdf551e4747f6c3d6",
+ "candidate/public/build/assets/iva-modelo-a-Cjl2qj1l.js": "4e4c8072266e94a36f8cefbdb3e0218d6dd410ca591d47307357ca25a7fd4c1a",
+ "candidate/public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "candidate/public/build/assets/label-Dpfg_IeY.js": "1bd84f39cb2df49df7c2a4ea94a73a5962504273dd6d39a5db37ac5842d97141",
+ "candidate/public/build/assets/labels-DxqjesIG.js": "deace12e77e3f2e0515b1090cbc376cfeff29b59f57b1a2561b1145459c531b8",
+ "candidate/public/build/assets/layers-2x-Bpkbi35X.png": "066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf",
+ "candidate/public/build/assets/layers-BWBAp2CZ.png": "1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6",
+ "candidate/public/build/assets/lead-C1SgbouT.js": "ad94144009dcaa311ddb615e2cf5e93dacbc4d84edbd6f83e87d8b5aac10d1e8",
+ "candidate/public/build/assets/leads-BM_69p-W.js": "aeafe2f04911a2663f54af5efaee521609740c5ba4f2a9d1a58a9aacbf193ed8",
+ "candidate/public/build/assets/leaflet-src-CUWrUTR2.js": "a26eda55b9706e8778766e4d32038202d20411081d7da16faaa39b977af36245",
+ "candidate/public/build/assets/legacy-Cgz97_0u.js": "e9928c58abea8ea831c42f30fa4618de92ed15e040bad5f930ddb70ddb5f7ea6",
+ "candidate/public/build/assets/loader-circle-DS8Tf4er.js": "cd9fb22e9d7d12342d5e0941aac953ebb5184550cc8008b5c0f8f5ea6acd8ed2",
+ "candidate/public/build/assets/login-Dl_Woyau.js": "116129ee46280ed72549418f0342821589cef169166c7d2b8134a614e558a1e6",
+ "candidate/public/build/assets/manage-D0t5bG7Z.js": "d58bc085040f334d1e678a6662e840bed45d989e46e87037d30da4dc62e16da2",
+ "candidate/public/build/assets/manage-DpkEhVZx.js": "6d52f0912f72d158d2cee436728928fe15256081574ba52ee4a2c5396a686817",
+ "candidate/public/build/assets/manage-Duly8FAl.js": "e2737830f5197b5efc24f2b6db6a0dc72fe53c55ab8d2a41786a673986770f7c",
+ "candidate/public/build/assets/management-access-D4VE9LUB.js": "7ef7be4f6d73ebcc387e98df969fe192429e8c0443f761677a83e5dd59794ae7",
+ "candidate/public/build/assets/management-CvdeRZYq.js": "0c193b26e40abae535aa6b51d1734bd930e4d2570dd0033cf0b41efc47aa16cd",
+ "candidate/public/build/assets/marker-icon-hN30_KVU.png": "574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437",
+ "candidate/public/build/assets/notifications-DVbWwZQz.js": "20a846db0d10c178e703426c6d928c8c4aed35763d2dc1c8f5f85f01a6e1e1af",
+ "candidate/public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "candidate/public/build/assets/opportunities-Lyn7IR21.js": "04cb94e293d37c2702d0114e31da268df48b0d4122fda2d6bf631d329581a85f",
+ "candidate/public/build/assets/opportunity-classification-BoQfr2Xg.js": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "candidate/public/build/assets/opportunity-draft-Cv8gFHnK.js": "a9f97f980b731cdfff97bd210591c34a40ed8f6c9bd5c902463d2d0086a4b225",
+ "candidate/public/build/assets/opportunity-install-CEd0Tc-c.js": "1914c39ef5c497214afc66ae9938e21ce0fe98e0af7c6e9f2b76fe03421ac3e2",
+ "candidate/public/build/assets/opportunity-origin-CEtX5_9r.js": "c1d44faf75dd194047ffe414efba77d3747dffc56653493dca12c2c83ff32b2c",
+ "candidate/public/build/assets/opportunity-promotion-T3JDCJL1.js": "68975685eaa07d2e2186fc641b1bfa4bc5a5eee859a4f9a5fd4ff0eab6c8192d",
+ "candidate/public/build/assets/opportunity-resources-DDMA7NYD.js": "6da6b96f5ea96935d8734aa8cd3b859d5dd44d61e187c209c3b244a87109baf4",
+ "candidate/public/build/assets/opportunity-search-filters-BAz7FaMh.js": "76a31b86ffe2d09cb48dd23c10f90e83d872aed0fbf830516144700e74e994d6",
+ "candidate/public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "candidate/public/build/assets/panel-BsyGB-pj.js": "79bcff75644158d9776b48a763fd1327aba06ab3804f0622d81f0a96de7ff910",
+ "candidate/public/build/assets/participation-identity-BWabb4yN.js": "653deb5bab449a215c14ce515a0bd6edb2671cdb957942421ab626adc255b540",
+ "candidate/public/build/assets/partnership-agreement-instrument-CCnuZNBy.js": "428f576c3f28fc665002ef48e6e3633fc09a93249fa347dc526bb6c1d65a866b",
+ "candidate/public/build/assets/partnership-history-CfclSLAo.js": "4668cf773996dc3ac4444a5dc066e6486ab9759120203bdce4466c1579dd9c56",
+ "candidate/public/build/assets/partnership-source-links-VfrXk2FZ.js": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "candidate/public/build/assets/passkey-verify-BuysdaU7.js": "289b72706453d029b2b598a4ff2e97efcf4dae99479e700989b02c14d92adc84",
+ "candidate/public/build/assets/password-CB_NxgQN.js": "4415e495723009fc084111bafd2b7714221a3712e5f1d2a4dfa0e698f6308c7a",
+ "candidate/public/build/assets/password-input-gMQR9TR6.js": "3b9f2fd751f432f5249d7492ed6ec32d2be238dfe6ffcfbc89ebdb68c0c3b187",
+ "candidate/public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "candidate/public/build/assets/portal-presentation-fH7FShU8.js": "09952abb82d5ecc757c02ea3bc67f72c1ea9cb0a54d332c0059095e28f5fe291",
+ "candidate/public/build/assets/PortalInvestidor-B-clIHAH.js": "eae45cc42f99e978d05327e3813d4109817d408db76d0a26f080943cab8a19da",
+ "candidate/public/build/assets/portfolio-D5Gf-Mho.js": "3361b7611799c01c9c3bb1641a2aae3ab154d158a8d8329c55f838606aacfb2d",
+ "candidate/public/build/assets/print-Tn3aXHlY.js": "b9cc8b260726c0343ea6bb6ccce45dddcca50d07dbe7a2e9be75627c0d799c08",
+ "candidate/public/build/assets/privacy-policy-LI1lpUCK.js": "8822f4ef73992d1644410803666637a0b606228179f1d93f9233a541a4bec580",
+ "candidate/public/build/assets/proactive-investment-XdN3JLTR.js": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "candidate/public/build/assets/proactive-supply-review-C8hRKc3X.js": "8827704c89dafc7a59954f7ea7c647b27207e46ca3622704b2071ff78a10bf23",
+ "candidate/public/build/assets/procurement-H0bYoKh8.js": "b3a2787fb5f3fe72d98ff236858fdf3458e0eb95eb1b7d851cb4a0830f45d06a",
+ "candidate/public/build/assets/product-usage-CHhCL93_.js": "f099c8d7928bfaf4bccc0381e37c7ac46368c7610627325bc3944e0e48b99370",
+ "candidate/public/build/assets/product-usage-CZ16blHQ.js": "78f3821070aa4b393d2297aada29c20ace679d52f8daa1b04a2d74081154cfec",
+ "candidate/public/build/assets/profile-B-5rgN6n.js": "b576f0420cf4eff24d7801265f770f49ce83c85b3304d587a1d57bd1e52146f1",
+ "candidate/public/build/assets/profile-C7C-Iq75.js": "3b4e5d0077cafec6b3f493025134a8c5a3458bcef057512f175e634102984ff0",
+ "candidate/public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "candidate/public/build/assets/project-dossier-document-uWvGORGc.js": "a8ec4e64270e139b0acc89ec7cd0a24ca06a7864abd121a8b72973cbe628d1ed",
+ "candidate/public/build/assets/project-dossier-QdCAJHX5.js": "a2b8367881f64d8b4c83082bf508eb8634240cbdf006a5320446390d7cf57cfc",
+ "candidate/public/build/assets/public-document-content-BHvs9J7S.js": "372e43f9a2edf3b745b16c57edcd4432f1417924c07aab4d315f8093328e2f32",
+ "candidate/public/build/assets/public-record-offline-BmjvnSLE.js": "2d203901b248446a540a734a4109aacabe160b7877a51248bbc1c0c437e66596",
+ "candidate/public/build/assets/public-sector-cards-Esb1aTm6.js": "7e7df738c7f39b0f338d14e9dc4976b160489d97a0fffb7ab71b4472d5132618",
+ "candidate/public/build/assets/publication-history-3y8cULAx.js": "d86a0cbcd3144e91009e37a58fe8950d32c147550a7924b953e56c91a7372637",
+ "candidate/public/build/assets/react-CjVep8xp.js": "3378f8538b0d8c51e3051e5005dfaebb8fec48c35789a3ba63945fd724f48e6f",
+ "candidate/public/build/assets/reference-CjMd0YHr.js": "f82abf3c5adfadfa621f1019d97ab67dbc7647484e454fe8a56f276414994d54",
+ "candidate/public/build/assets/references-Dc3NDfFI.js": "3f30879cdf3131ea5296a394465cb78dad82ec63b460c6dac2934ffe9fe7ef3e",
+ "candidate/public/build/assets/register-BU9hjY51.js": "6823843766486e3c62fbc3219be317ce28c5afe1946a6a736f247e4c435742cf",
+ "candidate/public/build/assets/relationship-repair-B-gXYFtU.js": "0c658b4b849dd588632e8551938341dfe969c8c65f76a872f72030dca58bbd0e",
+ "candidate/public/build/assets/request-lE2Drvq8.js": "70b44a0b57f29e2a3b22ff53e93acf7aacc715087a720a8fea33520741f7c8fb",
+ "candidate/public/build/assets/request-tQLizHEk.js": "9c91115bfb70d73f1f6623e8ef9eece9adc956a6b9f5def1d95c7fbac6f1aa74",
+ "candidate/public/build/assets/reset-password-DtPaSSLz.js": "aa83ed07160a4a4cd21df596dc261f745201a69b3bc61a85f359db6100616085",
+ "candidate/public/build/assets/result-DlueJzlu.js": "c25da08652122a40fe09d84c4f52eb54e43a59f06f2a7e1483350bfb67c9a56c",
+ "candidate/public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "candidate/public/build/assets/room-SPczVFbd.js": "b4f1d40ca9d1d8610c32842ede454a2bcef5bc7b0bbeae6cc8fa6b23755551ae",
+ "candidate/public/build/assets/saved-6Mv1FCAX.js": "37de0817ff58d9577c3fe2b7788e240f818cd34780c06fcf6ee9695adcd3ca7f",
+ "candidate/public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "candidate/public/build/assets/security-kNDSNMsu.js": "900b17d018b0e41055eb9371a2bec4875a281a438216221c13824fa8b256806d",
+ "candidate/public/build/assets/service-editor-DTNoKIC0.js": "408931a406f0827c7b313d3efff4add85496d5c70f5f038d86a857c83ba641e5",
+ "candidate/public/build/assets/services-CMSGrtvy.js": "07251aa9b5db86911b33a8ee0723ba03511d4a6d05746410541111cec8219904",
+ "candidate/public/build/assets/shared-3QGErCo-.js": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "candidate/public/build/assets/shared-B-QpuOU2.js": "29719badfc4da34d6447f6ef1588e953d3914bd4646284cea929cc9b8e4991b5",
+ "candidate/public/build/assets/shared-Bj5YmPzB.js": "941b5e35578918585f956d2650b3867fb10e3959a10011e75c511d790de84a03",
+ "candidate/public/build/assets/shared-CM5jsaLj.js": "08fafbb6c43685339aca5096af664a64276ce1d3ffcbc7e9cbe0917d965816d6",
+ "candidate/public/build/assets/shared-DXIXdF9G.js": "bc61ea4766e5a7bff469b524ee3840b3a5bae5e06211357feab4964094da81d3",
+ "candidate/public/build/assets/shared-zFtuFRLm.js": "8fc19b04d9565be87485552efafe4917ba1588eb43092b8ddb2b46497376bfa9",
+ "candidate/public/build/assets/show-Bc7bKlSF.js": "f29161eea47fefb68d16aa799d54b3a2524aec3e8412355b07cbadb7d0323b9f",
+ "candidate/public/build/assets/show-CfEboGKj.js": "4097940cc17c530743d594ff3468f8881c654d07173fafb674feb8eb1d997dd1",
+ "candidate/public/build/assets/show-D-aShraG.js": "0dc095be5e35df349638bceabcee3234eb684162a216494bb63c9f208191ad54",
+ "candidate/public/build/assets/show-XbnaZI3I.js": "14e850453ad1e4c9cedb93f6c37b363c03162590f7869c5a56ede7e3dac9cab8",
+ "candidate/public/build/assets/similar-businesses-HTwQGVGQ.js": "e29893bd96b9d1a0e8d0684363924794406377339aba69a93c604afbf3180821",
+ "candidate/public/build/assets/simulation-form-DxbfH1Rl.js": "021af834775bf76cc33cd178af566c10bb58d31a1dc69d7803798b836e5e0c2d",
+ "candidate/public/build/assets/sources-QaYmiipJ.js": "b7e211c5c689734c51a2195bb5bfefe2fbd492e3e30687798cceb0050047217e",
+ "candidate/public/build/assets/spinner-Dmx1j41V.js": "8935d05f362edccefab2741b25dd4a03bac53ec59e6057c73b6c991dcd12d43f",
+ "candidate/public/build/assets/structure-geography-CXavm01a.js": "20d109dbf150a7da59c2d688ab5d0c16746d153e1f355896b632adcd67230a0f",
+ "candidate/public/build/assets/structures-C500AmW9.js": "6809503fff292ff77d37c4a4e06aa5ea0728638df6a29701a9183dce931bca51",
+ "candidate/public/build/assets/submission-CuvAjagS.js": "f553d22f818a40e090eb4d36ba7afeaf0fce93e38d882cce5aa7622189a98960",
+ "candidate/public/build/assets/support-installation-BYIiRJ2p.js": "fcba0afa78498591d2f7c3c5f1d4fbc07cb0c18758ddfec689cc21cef81124cd",
+ "candidate/public/build/assets/technical-incident-aGCrOhry.js": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef",
+ "candidate/public/build/assets/technical-incident-labels-BiFC6llC.js": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "candidate/public/build/assets/technical-support-Dg-ZQ0ws.js": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "candidate/public/build/assets/terms-of-use-CUQdwKes.js": "5c98fee7fd189841a9881f63465ff0ad063e509063309e94436830b588440500",
+ "candidate/public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "candidate/public/build/assets/territory-associations-BJwnVqH5.js": "aa145627492be2ca68932948c3b200029ccf3c048fbdf13a880d1fcc2cc1a35d",
+ "candidate/public/build/assets/territory-geometry-import-C1k0D7rx.js": "a4cd28cfcaeb1da9d465433e461debf02af8d368a3c1543899cbe741d518acec",
+ "candidate/public/build/assets/territory-geometry-preview-TxdPJ8dB.js": "0e7901314ede7495c89c313ac56e96ce9a619036ee8058586962bf897ce616b4",
+ "candidate/public/build/assets/text-link-BBvcP60s.js": "0e7b5234d766855dbcbd5a78fe3e8c54fa6ffa1ad6163009d7b312eafd19f307",
+ "candidate/public/build/assets/two-factor-challenge-CyuaDuYg.js": "57ab00e87b277cd47300622569315c77eadcf6efc854b89e7564620c9a6d2f42",
+ "candidate/public/build/assets/types-BoD_IJFv.js": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
+ "candidate/public/build/assets/types-Cxp_Nskt.js": "cf4ae8cb539c697ca751dcf96e1db3af9eb1ff00807c088268dd859e7c4a5dab",
+ "candidate/public/build/assets/use-interest-draft-waHUBAew.js": "e0643f7c121fcc07c3dd8c1928485f563158fa595dbd1a8bd5d572e25b8d9b02",
+ "candidate/public/build/assets/use-two-factor-auth-D9w0KtSq.js": "0cb71f1946e32554e6106b897a14ba2659818a4e4bc11dde3cb25a91ae1453b1",
+ "candidate/public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "candidate/public/build/assets/value-network-BngmKAiu.js": "2a3b4f5c0d905e3922b05e6b33245748f85b38df9468e5d085fa112e73090f1f",
+ "candidate/public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "candidate/public/build/assets/verification-BOcn3HIw.js": "10addac3d8f1865e855943e0685e88a268ffd8013ff7a7d51fb89d755b12074e",
+ "candidate/public/build/assets/verify-email-CKI8UccQ.js": "36d56706b52cf25050c5c265c9385700137b4ffd93148104e60e4ed98ee3b156",
+ "candidate/public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "candidate/public/build/assets/welcome-dV8I6ajq.js": "8809a6616ed9af55ce6caa1f664cd4655d2e094853a682219cdef876053470d8",
+ "candidate/public/build/assets/why-invest-lDNA5gOy.js": "a547bbaa507b27dca4e2bc1651c7e8f7054fd11ffe759f47058e83a3ffdd13a3",
+ "candidate/public/build/assets/workspace-4_R1CLYI.js": "5d4c742569d9ad33ac7bac01c6433c646f79f939d2f57b7878860c0d25dcee22",
+ "candidate/public/build/assets/workspace-C2cGJeua.js": "cd2e7a53e17d50d1047f3a4ea55d01fcf03b7cf9d2ca5c803c56389c477f5a3f",
+ "candidate/public/build/assets/workspace-DWMQ6ei0.js": "d704ee2c32f2e380c607a703193028e3e9bdaeb82847d6e15ed7b88070a0fdfb",
+ "candidate/public/build/assets/zone-attachments-DsApjlI1.js": "0b5328390030b767ba358fdb850988a050e73ce3631bfbfe110148f9c9bdfc0b",
+ "candidate/public/build/assets/zone-BLi4MpIQ.js": "140aad13cb25288bedb3cb055d82d68554ff0b12d50164d304358f01b31abbb1",
+ "candidate/public/build/assets/zone-map-CQMiZb-O.js": "960c1d3a1b2fdd8002bb594d6c5bebea7533f5c8b2a64a60ab4b71c1c92b6d4e",
+ "candidate/public/build/assets/zone-relations-dwRj1vCl.js": "3d1b22a78e673f7adea88eac56b44311e73bc2ef53deee8a9e186b301d703f89",
+ "candidate/public/build/assets/zones-DI3aHGs9.js": "86fbd5d92c9e5791097bc29f00ff77d4b438ddf74527401c8dca77034e3abc30",
+ "candidate/public/build/fonts-manifest.json": "66edf17c93351fe01158be7414a441a762f106417c74351881876b405b8b10ca",
+ "candidate/public/build/manifest.json": "a7a10abce64b2273bda77f87c57da5aeef967ee6b0cc033417e540732f616bbc"
+ },
+ "proof": {
+ "verified_at": "2026-11-03T18:59:10+00:00",
+ "target": {
+ "database": "support_profile_installation_operational_20261103c_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "code_hash": "fa8eb8dbbff6345812ce83617088dfd7fd29c9c8c1c7b8661abe77d189924303",
+ "restore_verified": true,
+ "files_verified": true,
+ "compatibility_verified": true,
+ "qa_passed": true,
+ "dump_path": "C:\\laragon\\www\\portal-investidor\\storage\\app/private/support-profile-install-operational-20261103c/database.dump",
+ "dump_sha256": "f039302f082dc0057712eb6cb8bb1da61a7e14d973fe389fe69e1751b7d638cc",
+ "files_path": "C:\\laragon\\www\\portal-investidor\\storage\\app/private/support-profile-install-operational-20261103c/files.zip",
+ "files_sha256": "89edf0360b2f1c55bb8cd344994d0040cacd638da6ad63f1b67f4b80a65dc7c3"
+ },
+ "feature_log_sha256": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "same_receipt_on_retry": true,
+ "business_and_authority_preserved": true,
+ "support_grants_created": 0,
+ "qa_migrations_applied": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "scope": "Retained synthetic QA service rehearsal with current actor authority and MFA; actual pg_dump/pg_restore and candidate/private archive restoration; not active installation or customer acceptance."
+ },
+ "operational_existing_guard": {
+ "result": "failed",
+ "error": "Existing QA database will not be reset."
+ },
+ "checks": {
+ "phpstan": "passed_level_7_without_suppression",
+ "pint": "passed_test_exit_0_with_fresh_cache",
+ "types": "passed_exit_0",
+ "check": "six_sources_format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "607281f4294c776253607a1c8d60a3f51f632b399922bf08f4610380e0847096",
+ "app/Services/OpportunityTechnicalSupport.php": "0c4f0cb1e087de63bb69c8e2c2941c9ee4d1c8a1e17eb38a27ab14541eee1490",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "routes/web.php": "fc5e05a242a30865111c25f477cd5f94066450c17e9038ad68beb14f9164aea7",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-support-profile-install-20261103.php": "1812157417e2b56c0f0e036c45ccd297be7d5dc0a989bb7147032a7e188896f3",
+ "storage/app/private/check-support-profile-install-qa-20261103.php": "956af3bd7e12e58dcc3f5390e08607bc6db6816d86233e01e8a9444beccf195f",
+ "storage/app/private/create-support-profile-install-qa-20261103.php": "6d44d99814709557380ef5d5b2752b892d9993a245f58c387adff2381beae64e",
+ "storage/app/private/verify-support-profile-install-operational-20261103.php": "b7404bf5e1a1cd240940d9429080981c6f95b06aa5bd19a7a79fbaa9eb21269f",
+ "storage/app/private/record-support-profile-install-20261103.cjs": "3241f9e8ad554d4989e1f793a7df8af302576229ee6050bde62d878898a7c53c"
+ },
+ "logs_sha256": {
+ "support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/support-profile-install-build-20261103.log": "837c06c22c6f721ece01d6074fa734966340b6247163b2021834365b568ca824",
+ "storage/app/private/support-profile-install-check-current-20261103.log": "0a6d967468e3d0618a047b2c39805e8a4f909e3bfe07df41f50d7da07fc7333e",
+ "storage/app/private/support-profile-install-check-fix-final-20261103.log": "782091d7d8bbaee3f0b5872679702ab0230d8d7ca19b4b148331ab9b355c63f3",
+ "storage/app/private/support-profile-install-check-format-20261103.log": "d821888d909ae44727b424a50bfbbb1bdf6358c27043da6633023509b1d622c8",
+ "storage/app/private/support-profile-install-check-format-current-20261103.log": "fb1af5b29932a78fd9bdd4f5d387f1917d7c51db60cf74bb452896454202387b",
+ "storage/app/private/support-profile-install-feature-current-20261103.log": "a8c5c02b7ad1c14be989b5623e15027def7d8c7249f334e25a470b692ded1451",
+ "storage/app/private/support-profile-install-frontend-current-20261103.log": "c3cda850d55326a03f0e24a350ee7fe8b7618f9c8ba46eaaa15d53a4aa7c86a1",
+ "storage/app/private/support-profile-install-frontend-initial-20261103.log": "e17d9e8db6f2813c43ca55e7700b81b6fbd26a529a5f20a5ecfe865ec03208ac",
+ "storage/app/private/support-profile-install-operational-initial-20261103.log": "4eaf4513366ce40ddff401573bb0b91130f47791fc4fced33cab707445464ea1",
+ "storage/app/private/support-profile-install-operational-replay-diagnostic-20261103.log": "139c8f578996a99cf3626ffe6129333d99df7598a4ad0fd19d18963f70170e92",
+ "storage/app/private/support-profile-install-operational-rls-diagnostic-20261103.log": "32a2dcb8e8df82a331e4aee73c3c09507ee0a6b53692def8a754a16bb0d3cb79",
+ "storage/app/private/support-profile-install-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/support-profile-install-pint-current-20261103.log": "3692d92f9dc2fbbe1e8e75031ebb97e38d173452a15e169e4fa9609767721ada",
+ "storage/app/private/support-profile-install-pint-final-20261103.log": "3692d92f9dc2fbbe1e8e75031ebb97e38d173452a15e169e4fa9609767721ada",
+ "storage/app/private/support-profile-install-pint-format-20261103.log": "e98cef22f33276b910dc3ba2e998b35050a865a6ee2501446c70deee81a5ca58",
+ "storage/app/private/support-profile-install-pint-test-format-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/support-profile-install-pint-test-repair-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/support-profile-install-pint-test-uncached-20261103.log": "dbed775c4fd2a537c02211a7bf806c356d345b52b0556c0245ad5407120451c7",
+ "storage/app/private/support-profile-install-pint-tests-20261103.log": "0da17b10a60cf3fb275cc5a9cd471c911ad067f17f59bb3d376a4226360c274b",
+ "storage/app/private/support-profile-install-pint-verified-20261103.log": "3692d92f9dc2fbbe1e8e75031ebb97e38d173452a15e169e4fa9609767721ada",
+ "storage/app/private/support-profile-install-prettier-current-20261103.log": "b92de795ab956cfd71b43066baadedb4e82a38cf00e91a879e47ed7b55024126",
+ "storage/app/private/support-profile-install-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/support-profile-install-prior-receipt-20261103.json",
+ "sha256": "6f109c1095990966199f430acaefd8a3dbe1d0871818d6a534bdb7f868458e1a"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "24fdff12544570144f4a6955408ca22a9e249c9fadf68f8d733b81ede7b97909",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "app/Services/OpportunityTechnicalIncidents.php": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "app/Services/OpportunityTechnicalSupport.php": "dde836a4e0c1244b85344ee6fdb3e99af7e5849665701b74ba89592ff5ae185b",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "resources/js/components/profile-navigation.tsx": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0",
+ "resources/js/types/profile-access.ts": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "8d1100fb70697ffde53396aa25e92d8d2e2d86fc5edd9289e77ae2eb103e0765",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "resources/js/lib/technical-incident-labels.ts": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "fc7cdaba8e5b892e61b03beedd1cf9377b723cf185cd2bcbaab1e343a38b1f58",
+ "tests/frontend/technical-incident-handling.test.mjs": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "174642a20b257b8045048ee986a69ae44ace04322073880f90396242c1de5193"
+ },
+ "prior_code_deltas": {
+ "routes/web.php": {
+ "previous": "24fdff12544570144f4a6955408ca22a9e249c9fadf68f8d733b81ede7b97909",
+ "current": "fc5e05a242a30865111c25f477cd5f94066450c17e9038ad68beb14f9164aea7"
+ },
+ "app/Services/OpportunityTechnicalSupport.php": {
+ "previous": "dde836a4e0c1244b85344ee6fdb3e99af7e5849665701b74ba89592ff5ae185b",
+ "current": "0c4f0cb1e087de63bb69c8e2c2941c9ee4d1c8a1e17eb38a27ab14541eee1490"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "a7a10abce64b2273bda77f87c57da5aeef967ee6b0cc033417e540732f616bbc",
+ "public/build/assets/app-iIWdvtwu.js": "f181d1659b82f015392711775a0d81ebc53bff83aa1d46fd092c609f2efb4615",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/installation-DO8A-JbS.js": "1f2a46ff0f6f7e0513b46988156b3c95baa7faaa46170e6c6aac527d8aa6a57a",
+ "public/build/assets/shared-3QGErCo-.js": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/support-installation-BYIiRJ2p.js": "fcba0afa78498591d2f7c3c5f1d4fbc07cb0c18758ddfec689cc21cef81124cd",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/technical-support-Dg-ZQ0ws.js": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "public/build/assets/technical-incident-labels-BiFC6llC.js": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "public/build/assets/technical-incident-aGCrOhry.js": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "413308aebb5417410d4a6f9a2197597e65a23a404d84e21655da168ea3f5be0f",
+ "current": "a7a10abce64b2273bda77f87c57da5aeef967ee6b0cc033417e540732f616bbc",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-3dDpHpeP.js": {
+ "previous": "c25d89c9766aec79fcfaee617d59fd9209e13c659c761b58af25e484a373af54",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-KXCC-PON.js": {
+ "previous": "efe416b80cb3193dfd394eca2ed0b7bf1c72517c6719c3a126a04f844a368c02",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-C1tzdaXj.js": {
+ "previous": "454b427892c1c2bbeeafe14aa4646e73862205bb9cfedd0bcf6020e8db831d0c",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-VLDr8qfP.js": {
+ "previous": "e0300425b9a11c550a69b81fd5e7f6b899e1c3439afb213fb08a7c43156208be",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-bL9P_CZM.js": {
+ "previous": "292e39901c3931dca69b22f380ebe0a94d32134224183004ec196ab55e60dfdd",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-D8eE-r-w.js": {
+ "previous": "8d56511b2940f5a8410b38c977876398b1f14704ccd3575dd7514fa02a141e53",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-3QGErCo-.js": {
+ "previous": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "current": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-BoQfr2Xg.js": {
+ "previous": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "current": "0efde373d35dd8e385f0a267376f0dc173d70d3223d30ee52f3f307f85947718",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-D2sQnQMb.js": {
+ "previous": "fcf7cda1f7a5fe15af8cacdafb4fef80049318560f34945108f7ac4cb6ac7f65",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-XdN3JLTR.js": {
+ "previous": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "current": "97c00ff7fabc0d3b8f80faecb724d5eb304c081c2f3074d41207757a685f82a8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-Dg-ZQ0ws.js": {
+ "previous": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "current": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-BiFC6llC.js": {
+ "previous": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "current": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-aGCrOhry.js": {
+ "previous": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef",
+ "current": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migration_files": 0,
+ "qa_operational_migrations": 1,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Preparation is page memory only, not durable after page loss",
+ "Synthetic operational service rehearsal and HTTP/component tests do not replace active installation or browser acceptance",
+ "Actual archive restores this candidate code/build and a synthetic private original, not customer files or production configuration",
+ "Own alerting, health/other failure boundaries and applicable escalation remain pending",
+ "Module installation never grants a support assignment; existing explicit administration remains required"
+ ]
+ },
+ "support_incident_notices_increment_20261103": {
+ "recorded_at": "2026-11-03T19:13:50.922Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 25,
+ "passed": 25,
+ "assertions": 376,
+ "duration_ms": 85455
+ },
+ "initial_server_diagnostic": {
+ "tool": "phpunit",
+ "result": "failed",
+ "tests": 43,
+ "passed": 41,
+ "assertions": 664,
+ "duration_ms": 371505,
+ "failed": 1,
+ "failures": [
+ {
+ "test": "Tests\\Feature\\SupportIncidentNoticesTest::test_own_consultation_is_private_idempotent_and_changes_neither_treatment_nor_business",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\SupportIncidentNoticesTest.php",
+ "line": 79,
+ "message": "Header [Cache-Control] was found, but value [no-store, private] does not match [private, no-store].\nFailed asserting that two strings are equal.\n--- Expected\n+++ Actual\n@@ @@\n-'private, no-store'\n+'no-store, private'",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\SupportIncidentNoticesTest.php:79"
+ ]
+ }
+ ],
+ "errors": 1,
+ "error_details": [
+ {
+ "test": "Tests\\Feature\\SupportIncidentNoticesTest::test_current_scope_revocation_expiry_and_auditor_precedence_apply_to_notices",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\SupportIncidentNoticesTest.php",
+ "line": 117,
+ "message": "SQLSTATE[23514]: Check violation: 7 ERROR: new row for relation \"portal_role_assignments\" violates check constraint \"portal_role_period\"\nDETAIL: Failing row contains (c086a328-ae6d-4f65-80bb-5fd9ba40a3b7, 10, technical_support, f509bde0-be47-490d-bf46-5756c61559d4, [\"investment_project\"], [], profiles-technical-support-20261103, synthetic-support-treatment-fixture, null, 9, 2026-11-03 19:05:11+00, 2026-11-03 19:04:13+00, null, 2026-11-03 19:05:11+00, 2026-11-03 19:05:11+00). (Connection: pgsql, Host: 127.0.0.1, Port: 55441, Database: support_incident_notices_20261103_test, SQL: update \"portal_role_assignments\" set \"expires_at\" = 2026-11-03 19:04:13 where \"user_id\" = 10)",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:857",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\SupportIncidentNoticesTest.php:117"
+ ]
+ }
+ ]
+ },
+ "new_feature_cases": 7,
+ "frontend_focused_tests": 31,
+ "new_frontend_cases": 9,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_handling_and_incident_cases": 22
+ },
+ "qa": {
+ "result": "passed",
+ "database": "support_incident_notices_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_level_7_without_suppression",
+ "pint": "passed_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "eight_sources_format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Services/PortalProfileInstallation.php": "a46d5468b0522ad9d55bb89281a3c08574d47a719efd3f427ef9efb87b84e061",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "resources/js/pages/profiles/technical-incident.tsx": "be497b6d24fcc7aa8eb9b4da851d1d60d8c1776600e54f16dde4339d1d4a742c",
+ "resources/js/pages/profiles/technical-support.tsx": "78014c10332566683ca6aee223c92ebf36079ba1a173408236cd8e9f0cf6eb1c",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "88fc235ef358817ef2a53ffc1d7788108db8d3ed366184cf41de88799409647a"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-support-notices-20261103.php": "5458d43ed11916af4f98f80c9799e9ae006280e1f8180e46183cd46cbbf4b4d6",
+ "storage/app/private/check-support-notices-qa-20261103.php": "eab6c715cdfbdb56c637238c68ccad900e85f21c8346d1b574ebf8d069705d96",
+ "storage/app/private/record-support-notices-20261103.cjs": "24e5e98b737bc7132d7a9e6395dc7142912c20dbd2f06ffc62d60541d0014c20"
+ },
+ "logs_sha256": {
+ "support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/support-notices-build-20261103.log": "8909f135136e9b23022c6cd81aac01dd911b7f08275b3292a0f6fa1ec3c6206f",
+ "storage/app/private/support-notices-check-fix-final-20261103.log": "e117aaf0e515f065f87c9a7087e3025bbf202f6f12c72c8a3468c5d3f1b62faa",
+ "storage/app/private/support-notices-check-format-20261103.log": "18cb62f99c37ee0a0438c5052942ce5c804a601d179787bb786e2eaff8c1d533",
+ "storage/app/private/support-notices-check-verified-20261103.log": "cfdb19d15793ab62e7ece1d222f6c65a56d00eeb40a3679549d035f169085b39",
+ "storage/app/private/support-notices-front-format-20261103.log": "623c2455fd5e17451d4541139b9e8c460fec8c865cc7347f09630529400754b1",
+ "storage/app/private/support-notices-frontend-final-20261103.log": "b797d0d139b9ddc1a7f012813d446e9923cc00bb913baeb3f031de8df6731672",
+ "storage/app/private/support-notices-frontend-initial-20261103.log": "e6b3a700a5134f7ac1b9b9e5b799548af67621d23f0c664f83b6e85edaa638d1",
+ "storage/app/private/support-notices-pint-final-20261103.log": "2797e97521dca6d77d183706ef94ee9a73e047004a752a40c2999d5600a17592",
+ "storage/app/private/support-notices-pint-format-20261103.log": "7cc3061d5ad45573c0df32710bb3b91ed1c71af4139eef5ea34d48cd2d78eb19",
+ "storage/app/private/support-notices-pint-repair-final-20261103.log": "cd25fb11c3faf8d290d2db3588259ac057fa93342a4202ebc7b544bcf54ad500",
+ "storage/app/private/support-notices-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/support-notices-types-20261103.log": "085c34dc980164e9c54f12e5d52aff1c03111c5f2b7f5e5166c3336c3d25dbac"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/support-notices-prior-receipt-20261103.json",
+ "sha256": "2ec0444761d8964f6823f5097e09b78609fc75caa30f53bad25125f92f50d4c5"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "fc5e05a242a30865111c25f477cd5f94066450c17e9038ad68beb14f9164aea7",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "app/Services/OpportunityTechnicalIncidents.php": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "app/Services/OpportunityTechnicalSupport.php": "0c4f0cb1e087de63bb69c8e2c2941c9ee4d1c8a1e17eb38a27ab14541eee1490",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "resources/js/components/profile-navigation.tsx": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0",
+ "resources/js/types/profile-access.ts": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "8d1100fb70697ffde53396aa25e92d8d2e2d86fc5edd9289e77ae2eb103e0765",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "resources/js/lib/technical-incident-labels.ts": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "fc7cdaba8e5b892e61b03beedd1cf9377b723cf185cd2bcbaab1e343a38b1f58",
+ "tests/frontend/technical-incident-handling.test.mjs": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "174642a20b257b8045048ee986a69ae44ace04322073880f90396242c1de5193",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "607281f4294c776253607a1c8d60a3f51f632b399922bf08f4610380e0847096",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc"
+ },
+ "prior_code_deltas": {
+ "routes/web.php": {
+ "previous": "fc5e05a242a30865111c25f477cd5f94066450c17e9038ad68beb14f9164aea7",
+ "current": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d"
+ },
+ "app/Services/OpportunityTechnicalSupport.php": {
+ "previous": "0c4f0cb1e087de63bb69c8e2c2941c9ee4d1c8a1e17eb38a27ab14541eee1490",
+ "current": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58"
+ },
+ "app/Services/PortalProfileAccess.php": {
+ "previous": "f716565de9aeb3b67643c05be6636e82e1f78317305c059275254d2306646be9",
+ "current": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538"
+ },
+ "app/Http/Controllers/TechnicalSupportController.php": {
+ "previous": "2d8e53470c0c05716e79abe6d0e85c395e2d48b4616451d5880a69d6f406b2fe",
+ "current": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9"
+ },
+ "resources/js/components/profile-navigation.tsx": {
+ "previous": "d7121c53879ce4d2d982286453a0be5df7f796e94a92a69b2377d1fa553815ad",
+ "current": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47"
+ },
+ "resources/js/pages/profiles/technical-support.tsx": {
+ "previous": "0e8561de7bfc3c64370b52b90b604b856e8f3412219fe9f836c724e386df86a0",
+ "current": "78014c10332566683ca6aee223c92ebf36079ba1a173408236cd8e9f0cf6eb1c"
+ },
+ "resources/js/types/profile-access.ts": {
+ "previous": "02efcd834632872b35e0eddeaf052701aebdf6519add4f894b12542e32f46120",
+ "current": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5"
+ },
+ "tests/frontend/opportunity-technical-incidents.test.mjs": {
+ "previous": "8d1100fb70697ffde53396aa25e92d8d2e2d86fc5edd9289e77ae2eb103e0765",
+ "current": "88fc235ef358817ef2a53ffc1d7788108db8d3ed366184cf41de88799409647a"
+ },
+ "resources/js/pages/profiles/technical-incident.tsx": {
+ "previous": "fc7cdaba8e5b892e61b03beedd1cf9377b723cf185cd2bcbaab1e343a38b1f58",
+ "current": "be497b6d24fcc7aa8eb9b4da851d1d60d8c1776600e54f16dde4339d1d4a742c"
+ },
+ "tests/frontend/helpers/technical-incident-handling.mjs": {
+ "previous": "174642a20b257b8045048ee986a69ae44ace04322073880f90396242c1de5193",
+ "current": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0"
+ },
+ "app/Services/PortalProfileInstallation.php": {
+ "previous": "607281f4294c776253607a1c8d60a3f51f632b399922bf08f4610380e0847096",
+ "current": "a46d5468b0522ad9d55bb89281a3c08574d47a719efd3f427ef9efb87b84e061"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "d4fe438648f16cc4822aba3c335df7d684b522cb443f7785fc7b74c471739aa1",
+ "public/build/assets/app-DVrYkLVS.js": "4304626297dad1d74dfcea097eb26b3309010f4d9ef99bc55bf60e3344ba77e7",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/installation-DODMrWIz.js": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "public/build/assets/shared-B8ohIVwy.js": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/support-installation-LpR5Rkrn.js": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/technical-support-BJ-vEZG4.js": "16ef6809f08e0c7f3afd7e7f519f600b2c96be8b181c4c287dde1780595f2918",
+ "public/build/assets/technical-incident-notice-Dsan5aMt.js": "cf44165e8b986b7269923cd0830f57d4d586af5808d82642c45a9e22d36f904d",
+ "public/build/assets/technical-incident-CVxJoisC.js": "ad452acac9a6320af7eb19256bb47f01bac229af7a015339568d5bae4947df7f"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "a7a10abce64b2273bda77f87c57da5aeef967ee6b0cc033417e540732f616bbc",
+ "current": "d4fe438648f16cc4822aba3c335df7d684b522cb443f7785fc7b74c471739aa1",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-iIWdvtwu.js": {
+ "previous": "f181d1659b82f015392711775a0d81ebc53bff83aa1d46fd092c609f2efb4615",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-DO8A-JbS.js": {
+ "previous": "1f2a46ff0f6f7e0513b46988156b3c95baa7faaa46170e6c6aac527d8aa6a57a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-3QGErCo-.js": {
+ "previous": "ebc537a03b43e97beb6f0d9a6bbd0d297c030e7aab74a3d26f1b3290850146ac",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-BYIiRJ2p.js": {
+ "previous": "fcba0afa78498591d2f7c3c5f1d4fbc07cb0c18758ddfec689cc21cef81124cd",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-Dg-ZQ0ws.js": {
+ "previous": "bfb38684acffa8a3e920d7f113d9caf5649984844dc5118d68808938d0607c62",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-BiFC6llC.js": {
+ "previous": "57249ecc4a55004afb6670d76f46c8075c18fa7317fb9b75bd8f736444f04b1a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-aGCrOhry.js": {
+ "previous": "2bf4c485684376b865bab8f368d7eb0282d9e3ac0f2cac9431f737ecbe08fdef",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Own consultation mark is per actor/root, not incident resolution or notification of each treatment update",
+ "In-portal notices only; no new external channels or organisational escalation inferred",
+ "Unconfirmed treatment preparation remains page memory only",
+ "Deployment, browser acceptance and other failure boundaries/health remain pending",
+ "Previous actual backup/restore remains evidence for its archived candidate; not a fresh installation proof for this source fingerprint"
+ ]
+ },
+ "resource_technical_incidents_increment_20261103": {
+ "recorded_at": "2026-11-03T19:37:16.694Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 23,
+ "passed": 23,
+ "assertions": 285,
+ "duration_ms": 89129
+ },
+ "initial_server_diagnostic": {
+ "tool": "phpunit",
+ "result": "failed",
+ "tests": 27,
+ "passed": 25,
+ "assertions": 408,
+ "duration_ms": 227606,
+ "failed": 1,
+ "failures": [
+ {
+ "test": "Tests\\Feature\\ResourceTechnicalIncidentsTest::test_expected_validation_scope_version_and_quarantine_errors_do_not_create_incidents",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\ResourceTechnicalIncidentsTest.php",
+ "line": 106,
+ "message": "Expected response status code [422] but received 201.\nFailed asserting that 201 is identical to 422.",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\ResourceTechnicalIncidentsTest.php:106"
+ ]
+ }
+ ],
+ "errors": 1,
+ "error_details": [
+ {
+ "test": "Tests\\Feature\\ResourceTechnicalIncidentsTest::test_cleanup_preserves_referenced_originals_uncertain_commit_bytes_and_failed_reference_checks",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\ResourceTechnicalIncidentsTest.php",
+ "line": 141,
+ "message": "SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"status\" of relation \"documents\" violates not-null constraint\nDETAIL: Failing row contains (f28157f2-0248-475d-a6b6-29d92c360072, opportunity-resources, null, 1, internal, null, 2026-11-03 19:20:33.937636+00, 2026-11-03 19:20:33.937636+00, null, synthetic.pdf, application/pdf, opportunity-resources/c564e025-df34-48a2-9006-4135c95d7fc7, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, null, 1, null, null, null, 10, unconfirmed, null, pending, null, null, null, null, null, null, 0, null). (Connection: pgsql, Host: 127.0.0.1, Port: 55441, Database: resource_incidents_20261103_test, SQL: insert into \"documents\" (\"id\", \"source_system\", \"file_name\", \"media_type\", \"storage_key\", \"sha256\", \"size_bytes\", \"uploaded_by\") values (f28157f2-0248-475d-a6b6-29d92c360072, opportunity-resources, synthetic.pdf, application/pdf, opportunity-resources/c564e025-df34-48a2-9006-4135c95d7fc7, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 1, 10))",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:857",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\ResourceTechnicalIncidentsTest.php:141"
+ ]
+ }
+ ]
+ },
+ "new_feature_cases": 8,
+ "gd_unavailable_case": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 1,
+ "passed": 1,
+ "assertions": 2,
+ "duration_ms": 72637
+ },
+ "runtime": {
+ "gd_process": {
+ "php_version": "8.5.11",
+ "gd": true,
+ "webp": true,
+ "active_configuration_changes": 0
+ },
+ "normal_process": {
+ "php_version": "8.5.11",
+ "gd": false,
+ "webp": false,
+ "active_configuration_changes": 0
+ }
+ },
+ "frontend_focused_tests": 37,
+ "new_frontend_cases": 6,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 31
+ },
+ "qa": {
+ "result": "passed",
+ "database": "resource_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "checks": {
+ "phpstan": "passed_nine_application_sources_level_7_without_suppression",
+ "pint": "passed_ten_php_sources_test_exit_0",
+ "types": "passed_exit_0",
+ "check": "nine_sources_format_and_lint_passed",
+ "build": "passed_exit_0_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalIncidents.php": "3222e4165b60733d57b89b501e8c92cd602d492c66657b4ac3d3241a1a78c4c0",
+ "app/Services/OpportunityResources.php": "b02b838c78b9d925a43899e617d65ce96c87a09f75df226f158fcf093da422a5",
+ "app/Services/OpportunityImageProcessor.php": "a7a553de933b239e2eadec3fa46e93b98f3d9bb587a39b588fa907d0cdb68986",
+ "app/Services/PortalProfileInstallation.php": "6fc4dbd981692964f82616c47214ab57f3c8e9b46fad1fc136c05092cac62cb1",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/lib/technical-incident-labels.ts": "cfccbe565cc58353c76d219018aeedc05a13995eab41037b60a7b6f21fe12172",
+ "resources/js/components/opportunity-technical-incidents.tsx": "bc22cb190b300752597775fc49d23142da813d0e8d22736ab07abe5b155ec26d",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/pages/profiles/technical-incident.tsx": "7cc1cf48c053f90804dd062c8dd498988306bb54f3dae0fc254e0f496f08b2ac",
+ "resources/js/pages/profiles/technical-support.tsx": "b4bc4cbb8ced0d1804a568de537c463785c04ab3ac85d35c97848c90aa10d187",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "3d328fa77955028b2fb6d2f374f9d6cdb20a130f78f6598e93d4878a73174d9e",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-resource-incidents-20261103.php": "ea81b20237383008031cea42a8196c467c5828199e915659b64708faec54f1d1",
+ "storage/app/private/check-resource-incidents-qa-20261103.php": "763fd8dbdc7530a84d55573f0fb87058cad42623a41070308e425d3163f7f3e1",
+ "storage/app/private/inspect-resource-incidents-runtime-20261103.php": "76a94ce470b42ee7f31590d3819ff4934697ea52e38634ccdd6e0c0dc72d53cb",
+ "storage/app/private/record-resource-incidents-20261103.cjs": "8a6d02c43307952080250826351ae72e09c01891868da589cdbbfdaa5ea9268e"
+ },
+ "logs_sha256": {
+ "resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/resource-incidents-build-initial-20261103.log": "a42cdadeabb68a625ec430d6514c4f50191cfc6bb9432bdd040807dee0e90966",
+ "storage/app/private/resource-incidents-check-format-20261103.log": "e51aa2350e8982fc679f5760db1ca59af7454815b2729966fd123e5d28f74bab",
+ "storage/app/private/resource-incidents-feature-before-rls-20261103.log": "cb06a1dcc582f248103bccf97cf205a37dc1548bbecafa84bcc1df178e2b4c7f",
+ "storage/app/private/resource-incidents-form-initial-20261103.log": "0580a1463b409e20b708ed15693419aef80fc44aad681ae176cde9601a9bda6f",
+ "storage/app/private/resource-incidents-front-format-20261103.log": "d4a2270c3cdcfe6e1d5d47fbab84c8f7bcfd6e305872a0c27610a1ed28b273de",
+ "storage/app/private/resource-incidents-front-format-final-20261103.log": "4fcaf510cdf75ca7f2b59501ac72222041302266e4d583d161c1ac32b2cc7154",
+ "storage/app/private/resource-incidents-frontend-initial-20261103.log": "99466935fb60cd171d6061dac0142439483341a86e47893523abb48350040e3b",
+ "storage/app/private/resource-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/resource-incidents-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/resource-incidents-pint-final-diagnostic-20261103.log": "3407c96a61258709de44886f73a8609fab340707c43e1e29d2937a53d97d53d2",
+ "storage/app/private/resource-incidents-pint-format-20261103.log": "464253b98a48900af91b0982c3a09d54d6d2b117bfe2cd4438c5e9ff4eb11488",
+ "storage/app/private/resource-incidents-pint-initial-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/resource-incidents-pint-repair-final-20261103.log": "4323566bdfd241b3efec2b027369ab75ea3aac83830efbb2c396e7ee4ab29933",
+ "storage/app/private/resource-incidents-pint-rls-format-20261103.log": "6d43bdac7dea8cc0b175803fd118af8d7b79cb367ab0c3102f2a1b6164b10f92",
+ "storage/app/private/resource-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/resource-incidents-prior-receipt-20261103.json",
+ "sha256": "35e5bd61c0d3340f86a7fe924204267cc66c0d0385ae70d7975ca92dc74fd228"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "app/Services/OpportunityTechnicalIncidents.php": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "app/Services/OpportunityWorkflowExecution.php": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "78014c10332566683ca6aee223c92ebf36079ba1a173408236cd8e9f0cf6eb1c",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "88fc235ef358817ef2a53ffc1d7788108db8d3ed366184cf41de88799409647a",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "resources/js/lib/technical-incident-labels.ts": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "be497b6d24fcc7aa8eb9b4da851d1d60d8c1776600e54f16dde4339d1d4a742c",
+ "tests/frontend/technical-incident-handling.test.mjs": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "a46d5468b0522ad9d55bb89281a3c08574d47a719efd3f427ef9efb87b84e061",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101"
+ },
+ "prior_code_deltas": {
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": {
+ "previous": "be0627a528b311893b1d1ef610647b9f2896a99ef28a55093f4955696f7b2f63",
+ "current": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67"
+ },
+ "app/Services/OpportunityTechnicalIncidents.php": {
+ "previous": "a5383233a1555995289e9e6b0d20ec941a6f03216bbe0396b4b921f430eef074",
+ "current": "3222e4165b60733d57b89b501e8c92cd602d492c66657b4ac3d3241a1a78c4c0"
+ },
+ "app/Services/OpportunityWorkflowExecution.php": {
+ "previous": "c7068a1115866e0a8086049ca9fc086b65cb362ce5cd13de64c206ac5b8f64dc",
+ "current": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd"
+ },
+ "resources/js/components/opportunity-technical-incidents.tsx": {
+ "previous": "786e53bdaff6dae759285904c3a4e02d5da183ce6a93c26de6332a8acf62b27e",
+ "current": "bc22cb190b300752597775fc49d23142da813d0e8d22736ab07abe5b155ec26d"
+ },
+ "resources/js/pages/profiles/technical-support.tsx": {
+ "previous": "78014c10332566683ca6aee223c92ebf36079ba1a173408236cd8e9f0cf6eb1c",
+ "current": "b4bc4cbb8ced0d1804a568de537c463785c04ab3ac85d35c97848c90aa10d187"
+ },
+ "tests/frontend/opportunity-technical-incidents.test.mjs": {
+ "previous": "88fc235ef358817ef2a53ffc1d7788108db8d3ed366184cf41de88799409647a",
+ "current": "3d328fa77955028b2fb6d2f374f9d6cdb20a130f78f6598e93d4878a73174d9e"
+ },
+ "resources/js/lib/technical-incident-handling.ts": {
+ "previous": "8ef59e392530a937bcbf3be9c25549de1865f1044aa3680dc3be1976e963bdf6",
+ "current": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e"
+ },
+ "resources/js/lib/technical-incident-labels.ts": {
+ "previous": "342a3d7554bddf8f6e3d0a313a46c9cb24afab4593b5560ee4161a1b718df085",
+ "current": "cfccbe565cc58353c76d219018aeedc05a13995eab41037b60a7b6f21fe12172"
+ },
+ "resources/js/pages/profiles/technical-incident.tsx": {
+ "previous": "be497b6d24fcc7aa8eb9b4da851d1d60d8c1776600e54f16dde4339d1d4a742c",
+ "current": "7cc1cf48c053f90804dd062c8dd498988306bb54f3dae0fc254e0f496f08b2ac"
+ },
+ "app/Services/PortalProfileInstallation.php": {
+ "previous": "a46d5468b0522ad9d55bb89281a3c08574d47a719efd3f427ef9efb87b84e061",
+ "current": "6fc4dbd981692964f82616c47214ab57f3c8e9b46fad1fc136c05092cac62cb1"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "b63511e2a153e2b6d3819b99e12e962fe6445de7277650e201cd3816ee36d563",
+ "public/build/assets/app-4F_6daqD.js": "8e644c5b7ae9ac0a65ed92da0b931f49442566ebd1c7d53b0652434397bb959e",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-Bu4jlmPt.js": "6de9ca07ef09bb8ab5770922c3cb3aff7e6d30b8e4dab28b1098a0fd096aba93",
+ "public/build/assets/investment-territory-DsbO1KyR.js": "0bb069c4aa3c58fd8fa3dcdf8d581b7ab64358cb3e6def89ea209f3f52059199",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-BAm5W4N2.js": "17b069d447c53c6832a0b3576d4febcd0f922d596dca4b8c7185af25847afa4a",
+ "public/build/assets/territory-geometry-preview-Cqt6mz47.js": "9ce71dda422f944216bd97a4c7b4e19c5a2da8fd3e094fff35feaea1d29ce726",
+ "public/build/assets/interactive-investment-map-B5fE2qFe.js": "abb6748144113240ae80ac204883954dca05955a27eb68f9b4a5042e635209f9",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B8ohIVwy.js": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-BxBfkMrN.js": "4eabe851cfad6de81bad03370f8acae79d82d74ac9ec25782cbe23931847c6b3",
+ "public/build/assets/technical-incident-labels-D5ZcAmdo.js": "cc8154f8c7eb00c17c48b14cabc0682e0a8b1c797213a56f1f58c7c394fb2ab9",
+ "public/build/assets/opportunity-draft-Vro-OJNh.js": "7c044fef2db4e9d991804096e77ed2542632068817c5868df99fbf7061875eaa",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-hpwqS0Fy.js": "0f1e33a81ea1a501f9fa95a0c92e3a096b58661442f1451915b2a150294694a8",
+ "public/build/assets/opportunity-search-filters-Dw1eeMXn.js": "2fc7cb97f544c2727b39489c5c73c420184003a6bc37f95db36a8a7e877708cb",
+ "public/build/assets/proactive-investment-PRv8PwaN.js": "82a8a5997981585b5829eb2db7145b238ba452b645c475a364b294e254b45131",
+ "public/build/assets/installation-DODMrWIz.js": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/support-installation-LpR5Rkrn.js": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/technical-support-BiqOlwLy.js": "562a3949c274029c3eeeffe4e9247dc6c2a86ff8111747d2ff6bf6aa45f2c5a7",
+ "public/build/assets/technical-incident-notice-CwVG4hrN.js": "8917cfcd5abaa159be5e6f1c19f37226ec40a880875b75514c8f70d42d60bdd0",
+ "public/build/assets/technical-incident-19UMhdgf.js": "f63e7be1bc0ce10b3c9eed4294ca826c9d71657316375b9869772ed498744e89"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "d4fe438648f16cc4822aba3c335df7d684b522cb443f7785fc7b74c471739aa1",
+ "current": "b63511e2a153e2b6d3819b99e12e962fe6445de7277650e201cd3816ee36d563",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-DVrYkLVS.js": {
+ "previous": "4304626297dad1d74dfcea097eb26b3309010f4d9ef99bc55bf60e3344ba77e7",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-DODMrWIz.js": {
+ "previous": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "current": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B8ohIVwy.js": {
+ "previous": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "current": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-LpR5Rkrn.js": {
+ "previous": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "current": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-BJ-vEZG4.js": {
+ "previous": "16ef6809f08e0c7f3afd7e7f519f600b2c96be8b181c4c287dde1780595f2918",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-Dsan5aMt.js": {
+ "previous": "cf44165e8b986b7269923cd0830f57d4d586af5808d82642c45a9e22d36f904d",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-CVxJoisC.js": {
+ "previous": "ad452acac9a6320af7eb19256bb47f01bac229af7a015339568d5bae4947df7f",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Uncertain-connection retention is verified by fault injection and observable bytes, not an actual network-disconnect/commit interleaving",
+ "Retained bytes after uncertain connection, active RLS, failed reference lookup or failed deletion need reconciliation; no automatic purge is claimed",
+ "GD/WebP was enabled only for an isolated CLI process; the normal runtime and active configuration were not changed",
+ "Existing resource preparation is page memory, not durable after navigation/reload or loss of the page",
+ "Scan dispatch/workers, other failure boundaries and health remain pending",
+ "Deployment and browser acceptance remain pending; previous actual backup/restore belongs to its archived candidate"
+ ]
+ },
+ "scan_technical_incidents_increment_20261103": {
+ "recorded_at": "2026-11-03T20:18:28.586Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 30,
+ "passed": 30,
+ "assertions": 365,
+ "duration_ms": 88882
+ },
+ "initial_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 42,
+ "passed": 42,
+ "assertions": 574,
+ "duration_ms": 116032
+ },
+ "new_feature_cases": 15,
+ "frontend_focused_tests": 43,
+ "new_frontend_cases": 6,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 37
+ },
+ "qa": {
+ "result": "passed",
+ "database": "scan_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "document_malware_scans": 0,
+ "jobs": 0,
+ "failed_jobs": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "worker": {
+ "result": "passed",
+ "identity": {
+ "database": "scan_worker_operational_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "queue": "scan-worker-20261103-test",
+ "separate_process": {
+ "result": "worker_finished",
+ "worker_pid": 6412,
+ "producer_pid": 29712,
+ "same_process": false,
+ "remaining_jobs": 0,
+ "failed_jobs": 0,
+ "output_sha256": "9b5d5b00137840f45b44277199d8a53d399f7c36a5bbca804de657a014ded4d0",
+ "active_writes": 0
+ },
+ "table_count": 190,
+ "changed_tables": [
+ "audit_events",
+ "document_malware_scans",
+ "documents",
+ "jobs"
+ ],
+ "baseline": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "d7b8f10bc1355f7d1e618572419b0f8629b983562e0cc07c18f81c5116e0f689"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 1,
+ "sha256": "eea25f708843613c861baa9b2aff7c925dfc97ff17982d1600d97d1862ad36fc"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 1,
+ "sha256": "bcba01cb1dd08a8bdf7a06bf3bdacab266788df37c4afef56e8e5f5417bdf779"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 1,
+ "sha256": "05303683b80ae2c16565d13f79d8e3c8e35ae41826c095c7aa8212d8b42bbc35"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 1,
+ "sha256": "1d082780539c6823f96095a40434bafc3929345ef60015cf6f7eb2d3d158a5ff"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 1,
+ "sha256": "5f2ac7711a258241fe1fc4d17eb319f12264d37d3cb7469cda44de98af4e4d7d"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 1,
+ "sha256": "90937747aaed86edb56f4178ad3ede255c8dabc43ed18d24ee7d59fbb9adc0df"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "c1da33219032881bbb64f5d300779046792208810d5256e732c3a27f2de6bd18"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 2,
+ "sha256": "5a4f5bb99a46fe459dab799156754db99f59a1cd7879a96aa2769980cc0a39f8"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "0f1c9538720b3e15ed671e7c0c9ebb7fc2205a170d3484687532e53bd43cef9d"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 3,
+ "sha256": "f1858767460c7a1e5b3a1211fb8365891669e369e662cca1f8558663f0b8bbcb"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "d7b8f10bc1355f7d1e618572419b0f8629b983562e0cc07c18f81c5116e0f689"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 4,
+ "sha256": "c28f7ba5e638227c01aa452567f91d6826f10ce596a37e7596633bb4bbad4877"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 1,
+ "sha256": "8a2202865118309491809307e5adacabe2ed63c8ff030bc54beacc0e410ef0f0"
+ },
+ "documents": {
+ "count": 1,
+ "sha256": "6842d7fcd0c8e48d34805cecb4f187ed6899164278adafd9e1a86aae62dcca80"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 1,
+ "sha256": "1d082780539c6823f96095a40434bafc3929345ef60015cf6f7eb2d3d158a5ff"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 1,
+ "sha256": "5f2ac7711a258241fe1fc4d17eb319f12264d37d3cb7469cda44de98af4e4d7d"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 1,
+ "sha256": "90937747aaed86edb56f4178ad3ede255c8dabc43ed18d24ee7d59fbb9adc0df"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "c1da33219032881bbb64f5d300779046792208810d5256e732c3a27f2de6bd18"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 2,
+ "sha256": "5a4f5bb99a46fe459dab799156754db99f59a1cd7879a96aa2769980cc0a39f8"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "0f1c9538720b3e15ed671e7c0c9ebb7fc2205a170d3484687532e53bd43cef9d"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 3,
+ "sha256": "f1858767460c7a1e5b3a1211fb8365891669e369e662cca1f8558663f0b8bbcb"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "snapshot_role": {
+ "rolsuper": true,
+ "rolbypassrls": true
+ },
+ "incident_reference": "5395f1d7-fb1a-4a8e-8afa-105ac0acc88b",
+ "system_actor_is_null": true,
+ "reported_for_initiator": true,
+ "scan_results": 1,
+ "scan_status": "inconclusive",
+ "scan_reason": "scanner_unavailable",
+ "malware_engine": "ClamAV",
+ "scanner_host": "127.0.0.1",
+ "scanner_port": 1,
+ "original_cipher_preserved": true,
+ "private_temporary_files": 0,
+ "current_author_and_scoped_support_verified": true,
+ "code_hash": "6ec833fd7d1b56890fa55566c66bf63b203681e34aa44186efa021f600fdff78",
+ "active_writes": 0,
+ "active_migrations": 0,
+ "external_messages": 0,
+ "scope": "One actual database-queue message consumed by a separate Laravel worker process with the real ClamD provider deliberately unavailable on loopback; no clean certificate, active installation, real user acceptance or load claim."
+ },
+ "checks": {
+ "phpstan": "passed_seven_application_sources_level_7_without_suppression",
+ "pint": "passed_eight_php_sources_test",
+ "types": "passed",
+ "check": "six_sources_format_and_lint_passed",
+ "build": "passed_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Jobs/ScanDocumentForMalware.php": "7c9e3e8b55a3b635b39c1834953184dd413aacdebf5a5d7a29cd3b35a8b6055f",
+ "app/Services/Malware/DocumentScanAttempts.php": "55ea55ad4def90e6244fd64d49b3492c2afaad60788af8c7faa542cd4bfede65",
+ "app/Services/OpportunityTechnicalIncidents.php": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b",
+ "app/Services/OpportunityScanDispatch.php": "650a9849c613e26658227c52dbbfdd1ef08ce9e6cfcb3d2e08a24ad3c504581c",
+ "app/Services/OpportunityResources.php": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6",
+ "app/Services/OpportunityImageProcessor.php": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711",
+ "app/Services/PortalProfileInstallation.php": "7daee388dfa39acce3a70bd114d93467870929a1c7f2810bc39ca3873980dfc4",
+ "resources/js/lib/technical-incident-labels.ts": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c",
+ "resources/js/components/opportunity-technical-incidents.tsx": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e",
+ "resources/js/pages/profiles/technical-support.tsx": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff",
+ "resources/js/pages/profiles/technical-incident.tsx": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a",
+ "tests/Feature/ScanTechnicalIncidentsTest.php": "6eb53d7f0a0c6f02968229e10473f9a2f3f5e9b3a11ea4a6aa4d7a1f7775d153",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60",
+ "tests/frontend/technical-incident-handling.test.mjs": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-scan-incidents-20261103.php": "a5febcdfc89e57e8eb45d14d3416e2eae308d9e2684e9fa8877d222c4dce204e",
+ "storage/app/private/check-scan-incidents-qa-20261103.php": "1c2800bbf8f30fa460fc4da17e8c4f58b5dd58fd2a614c31cf1ba006c58c8c01",
+ "storage/app/private/verify-scan-worker-operational-20261103.php": "52e6bbbdb59b402d23c4e563ed7a0380ef2a80637b81e46e8857e03990a4adf0",
+ "storage/app/private/record-scan-incidents-20261103.cjs": "ca6c0920d1c22b1ad860f3162d6e0b626757658923f841ef35aeba86f56a4726"
+ },
+ "logs_sha256": {
+ "scan-incidents-feature-initial-20261103.log": "34c0d09fb3cef0583c005a5a21e9cf198e1d4e1b2629208184c100d56b3ef159",
+ "scan-incidents-feature-final-20261103.log": "de586fd101f083af0976b37c8bf80ebf29a22cf7b92e274fbbe67c308e710d35",
+ "scan-incidents-frontend-initial-20261103.log": "6250c3ed8c6ab9fac2dc5f3cb3f757022ac7b2971d5d359a628aabc1209c78b3",
+ "scan-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "scan-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "scan-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "scan-incidents-check-final-20261103.log": "b605db485894f33b655ec2682f241160d4b03ff0389c8aeebbf27af6eb056df2",
+ "scan-incidents-build-final-20261103.log": "66c51148e850059b6404940f3189399230caa994993d63defb72ad2bd61ec921",
+ "scan-incidents-worker-init-20261103.log": "d1d0ba14bc20a77a8dc85236f9401ce85c9b0f9b93fa65ce875deb95b464380d",
+ "scan-incidents-worker-process-20261103.log": "ba3e512c805f7bb0852c62dd871dae76858919d822587c32208f6118f0e00d12",
+ "scan-incidents-worker-verified-20261103.log": "115c2047c614e5d8faf2ae5d1363d2661f4b092519c3a65501923f2f1fec9f59",
+ "scan-incidents-worker-existing-guard-20261103.log": "580207ff6534089bfa4bbde910e584aa8c55d390689f1095b8e5bf0c6d5ee363",
+ "scan-incidents-qa-accepted-20261103.json": "b23a6f89d98a2c43c32fae97c6b99ce9beadcfaeca610461a467d79895c825e2",
+ "scan-incidents-worker-proof-20261103.json": "8fa6fa596c5c51d20ea42eb8160788479b35e122f29e29ce167d802dcff893d4"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/scan-incidents-check-format-20261103.log": "c632cbdbaff7d5cb4abd5463b5e0c0660ff1c903efb945036dcd8d707526d77a",
+ "storage/app/private/scan-incidents-feature-load-diagnostic-20261103.log": "f3db7854978b77966ab1e1815fc342dee72020d9abcb3dc5a70c07c00a01555d",
+ "storage/app/private/scan-incidents-pint-format-20261103.log": "c731a80ac78164b3b3b5cf72e1b1575709997da708b69af1b5f7c40894623ba1",
+ "storage/app/private/scan-incidents-pint-protocol-format-20261103.log": "b9d11d50d5ec90e196367ec40e98749837f8763bd3fff517495adf79981081b4",
+ "storage/app/private/scan-incidents-pint-tests-final-20261103.log": "14e5bc399d571d3893e7ef275720e66801e1e274b3f3a316ed265ca9a9e662a9"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/scan-incidents-prior-receipt-20261103.json",
+ "sha256": "938917cd33308c7ad652d28327d69fbe8294a449440e12cd3cbf819df4aca143"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22",
+ "storage/logs/resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "storage/logs/resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "storage/logs/resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "storage/logs/resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "storage/logs/resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "storage/logs/resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "storage/logs/resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "storage/logs/resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "storage/logs/resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Services/OpportunityTechnicalIncidents.php": "3222e4165b60733d57b89b501e8c92cd602d492c66657b4ac3d3241a1a78c4c0",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "bc22cb190b300752597775fc49d23142da813d0e8d22736ab07abe5b155ec26d",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "b4bc4cbb8ced0d1804a568de537c463785c04ab3ac85d35c97848c90aa10d187",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "3d328fa77955028b2fb6d2f374f9d6cdb20a130f78f6598e93d4878a73174d9e",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/lib/technical-incident-labels.ts": "cfccbe565cc58353c76d219018aeedc05a13995eab41037b60a7b6f21fe12172",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "7cc1cf48c053f90804dd062c8dd498988306bb54f3dae0fc254e0f496f08b2ac",
+ "tests/frontend/technical-incident-handling.test.mjs": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "6fc4dbd981692964f82616c47214ab57f3c8e9b46fad1fc136c05092cac62cb1",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityResources.php": "b02b838c78b9d925a43899e617d65ce96c87a09f75df226f158fcf093da422a5",
+ "app/Services/OpportunityImageProcessor.php": "a7a553de933b239e2eadec3fa46e93b98f3d9bb587a39b588fa907d0cdb68986",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a"
+ },
+ "prior_code_deltas": {
+ "app/Services/OpportunityTechnicalIncidents.php": {
+ "previous": "3222e4165b60733d57b89b501e8c92cd602d492c66657b4ac3d3241a1a78c4c0",
+ "current": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b"
+ },
+ "resources/js/components/opportunity-technical-incidents.tsx": {
+ "previous": "bc22cb190b300752597775fc49d23142da813d0e8d22736ab07abe5b155ec26d",
+ "current": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e"
+ },
+ "resources/js/pages/profiles/technical-support.tsx": {
+ "previous": "b4bc4cbb8ced0d1804a568de537c463785c04ab3ac85d35c97848c90aa10d187",
+ "current": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff"
+ },
+ "tests/frontend/opportunity-technical-incidents.test.mjs": {
+ "previous": "3d328fa77955028b2fb6d2f374f9d6cdb20a130f78f6598e93d4878a73174d9e",
+ "current": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60"
+ },
+ "resources/js/lib/technical-incident-labels.ts": {
+ "previous": "cfccbe565cc58353c76d219018aeedc05a13995eab41037b60a7b6f21fe12172",
+ "current": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c"
+ },
+ "resources/js/pages/profiles/technical-incident.tsx": {
+ "previous": "7cc1cf48c053f90804dd062c8dd498988306bb54f3dae0fc254e0f496f08b2ac",
+ "current": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a"
+ },
+ "tests/frontend/technical-incident-handling.test.mjs": {
+ "previous": "0a54f2551fae48ffc312133eeaab8fb0188611a7e56ebdfac43740aa4ea3c67a",
+ "current": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e"
+ },
+ "app/Services/PortalProfileInstallation.php": {
+ "previous": "6fc4dbd981692964f82616c47214ab57f3c8e9b46fad1fc136c05092cac62cb1",
+ "current": "7daee388dfa39acce3a70bd114d93467870929a1c7f2810bc39ca3873980dfc4"
+ },
+ "app/Services/OpportunityResources.php": {
+ "previous": "b02b838c78b9d925a43899e617d65ce96c87a09f75df226f158fcf093da422a5",
+ "current": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6"
+ },
+ "app/Services/OpportunityImageProcessor.php": {
+ "previous": "a7a553de933b239e2eadec3fa46e93b98f3d9bb587a39b588fa907d0cdb68986",
+ "current": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "3b226388b8a80add73a248773d02ce9bb2c71cc38c3a494a964caeba5c5d2188",
+ "public/build/assets/app-BHesLmie.js": "ea37da10f078ff76f3f39985b7b54a9d9a2efca6567106a25b7f1e601e567da3",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-BDZ2qE2U.js": "c2853f965a40dadb5675a6ec65a5a31d6ab659bbd949c796047488a0e2dc29ce",
+ "public/build/assets/investment-territory-7JavasTr.js": "3f575a64b630d9e8e6d0b1123eac07e79515df2af6fd92e48d1c952edfbe66df",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-C-46-nOe.js": "8a8a5090de7eae4268ecfc4cfdcb6a7fabf40a6429a5a8e0ff89653b5b9fa7e0",
+ "public/build/assets/territory-geometry-preview-DywGUSlA.js": "174fc6ced9ae4a9aebfcb6bf79f0223555827011fda19b214a4f8c18b0191926",
+ "public/build/assets/interactive-investment-map-DQ19jbfY.js": "9ab8d9557d1dd1ef4a16d6af8e2063163972182efc7bafbc9af8dc118b800109",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B8ohIVwy.js": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "public/build/assets/opportunity-draft-CmXokNPV.js": "d23acd637577389cf78eaee94ca5b4bf5ed89d9897ca01be2a67979fdbb1aee5",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-hpwqS0Fy.js": "0f1e33a81ea1a501f9fa95a0c92e3a096b58661442f1451915b2a150294694a8",
+ "public/build/assets/opportunity-search-filters-CncAi5Js.js": "a5531c237672eea00e238126ddf1520770ee735e2995f4add2addc434b50369d",
+ "public/build/assets/proactive-investment-PRv8PwaN.js": "82a8a5997981585b5829eb2db7145b238ba452b645c475a364b294e254b45131",
+ "public/build/assets/installation-DODMrWIz.js": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/support-installation-LpR5Rkrn.js": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/technical-support-DEq0kuSc.js": "3bef9282aaec70d8b771aa6d151773c554f784d435e641288528e29869d3a0be",
+ "public/build/assets/technical-incident-notice-CwVG4hrN.js": "8917cfcd5abaa159be5e6f1c19f37226ec40a880875b75514c8f70d42d60bdd0",
+ "public/build/assets/technical-incident-C2M6yu59.js": "2a616744b3215c6570c5ed962246c1b2e41fe1c36df6a238744a0c938ab6f622"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "b63511e2a153e2b6d3819b99e12e962fe6445de7277650e201cd3816ee36d563",
+ "current": "3b226388b8a80add73a248773d02ce9bb2c71cc38c3a494a964caeba5c5d2188",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-4F_6daqD.js": {
+ "previous": "8e644c5b7ae9ac0a65ed92da0b931f49442566ebd1c7d53b0652434397bb959e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-resources-Bu4jlmPt.js": {
+ "previous": "6de9ca07ef09bb8ab5770922c3cb3aff7e6d30b8e4dab28b1098a0fd096aba93",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-DsbO1KyR.js": {
+ "previous": "0bb069c4aa3c58fd8fa3dcdf8d581b7ab64358cb3e6def89ea209f3f52059199",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-BAm5W4N2.js": {
+ "previous": "17b069d447c53c6832a0b3576d4febcd0f922d596dca4b8c7185af25847afa4a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-Cqt6mz47.js": {
+ "previous": "9ce71dda422f944216bd97a4c7b4e19c5a2da8fd3e094fff35feaea1d29ce726",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-B5fE2qFe.js": {
+ "previous": "abb6748144113240ae80ac204883954dca05955a27eb68f9b4a5042e635209f9",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B8ohIVwy.js": {
+ "previous": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "current": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-technical-incidents-BxBfkMrN.js": {
+ "previous": "4eabe851cfad6de81bad03370f8acae79d82d74ac9ec25782cbe23931847c6b3",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-D5ZcAmdo.js": {
+ "previous": "cc8154f8c7eb00c17c48b14cabc0682e0a8b1c797213a56f1f58c7c394fb2ab9",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-Vro-OJNh.js": {
+ "previous": "7c044fef2db4e9d991804096e77ed2542632068817c5868df99fbf7061875eaa",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-hpwqS0Fy.js": {
+ "previous": "0f1e33a81ea1a501f9fa95a0c92e3a096b58661442f1451915b2a150294694a8",
+ "current": "0f1e33a81ea1a501f9fa95a0c92e3a096b58661442f1451915b2a150294694a8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-Dw1eeMXn.js": {
+ "previous": "2fc7cb97f544c2727b39489c5c73c420184003a6bc37f95db36a8a7e877708cb",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-PRv8PwaN.js": {
+ "previous": "82a8a5997981585b5829eb2db7145b238ba452b645c475a364b294e254b45131",
+ "current": "82a8a5997981585b5829eb2db7145b238ba452b645c475a364b294e254b45131",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-DODMrWIz.js": {
+ "previous": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "current": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-LpR5Rkrn.js": {
+ "previous": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "current": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-BiqOlwLy.js": {
+ "previous": "562a3949c274029c3eeeffe4e9247dc6c2a86ff8111747d2ff6bf6aa45f2c5a7",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-CwVG4hrN.js": {
+ "previous": "8917cfcd5abaa159be5e6f1c19f37226ec40a880875b75514c8f70d42d60bdd0",
+ "current": "8917cfcd5abaa159be5e6f1c19f37226ec40a880875b75514c8f70d42d60bdd0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-19UMhdgf.js": {
+ "previous": "f63e7be1bc0ce10b3c9eed4294ca826c9d71657316375b9869772ed498744e89",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "No transactional outbox or exactly-once delivery; commit/push crash gap and existing unique lease under uncertain transport remain",
+ "Actual one-message database queue worker used real ClamD deliberately unavailable; healthy engine, load and physical two-worker race are not demonstrated",
+ "Existing in-memory workers require drain/restart during deployment; old serialized payload compatibility is tested against the installed Laravel handler",
+ "Legacy contextless jobs do not invent opportunity recipients; support has no new rescan or document authority",
+ "Existing resource preparation is page memory; durable recovery, retained-byte reconciliation and other failure boundaries remain",
+ "GD/WebP was process-only QA; active installation, current-candidate backup/restore and browser acceptance remain pending"
+ ]
+ },
+ "scan_retry_increment_20261103": {
+ "recorded_at": "2026-11-03T20:27:09.076Z",
+ "requirements": [
+ "AUD-PROFILE-20"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 36,
+ "passed": 36,
+ "assertions": 378,
+ "duration_ms": 88123
+ },
+ "initial_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 24,
+ "passed": 24,
+ "assertions": 228,
+ "duration_ms": 29925
+ },
+ "new_feature_cases": 11,
+ "frontend_focused_tests": 47,
+ "new_frontend_cases": 4,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 43
+ },
+ "qa": {
+ "result": "passed",
+ "database": "scan_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "document_malware_scans": 0,
+ "jobs": 0,
+ "failed_jobs": 0,
+ "cache": 0,
+ "cache_locks": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "worker": {
+ "result": "passed",
+ "identity": {
+ "database": "scan_retry_operational_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "queue": "scan-retry-20261103-test",
+ "separate_process": {
+ "result": "worker_finished",
+ "worker_pid": 25960,
+ "producer_pid": 25340,
+ "same_process": false,
+ "remaining_jobs": 0,
+ "failed_jobs": 0,
+ "remaining_shared_leases": 0,
+ "output_sha256": "e57b808eaff78af7dcbb9b1a8d9f3bcc5d8e82a9f69413bc04d6327c3a37caca",
+ "active_writes": 0
+ },
+ "table_count": 190,
+ "changed_tables": [
+ "audit_events",
+ "cache_locks",
+ "document_malware_scans",
+ "documents",
+ "jobs"
+ ],
+ "baseline": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "e679e9345622182025c588674ea588fe0e452ada22074202a23cb6d3fae145bf"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 1,
+ "sha256": "69680740a1fbaaaae011c35c8587e732cb62be74b216e4441e70a2eaf54a63c0"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 1,
+ "sha256": "fe72c4e13de2427c77a1522e9e78b13be7ff446b412e07a35b29690b5a936fff"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 1,
+ "sha256": "46bc3002edbcbd4c9a906bd68e01d147f1f3d44de3c7c474c6dd051a4ae3a48d"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 1,
+ "sha256": "2d0e677164eb8a67069ea9777c3ddc140d0cbeb2da07960e0e540cd132d59e46"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5c99278f2fe65078f73602e123501daba5ee1522f6b31865ce2e5ce77dd612cd"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "e760bd35474a20b1d4b205747c2c07fc31bd2cf37a4f942e6b0855a6bf9d8fbf"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "e679e9345622182025c588674ea588fe0e452ada22074202a23cb6d3fae145bf"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 3,
+ "sha256": "4807086301c51bcdc6cd1633f4b2eb6b0fd20250250b9547146bd08c58c63de5"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 1,
+ "sha256": "6f6ffe77ffaaca4d26bfe4ab0218ad58427a82fb1b28ed011ce7c91f300318e0"
+ },
+ "documents": {
+ "count": 1,
+ "sha256": "327a859e263f8f1d22bf0ae8f8e6a4ed2bf9cdde66b59b77c41f4b5bcb29578b"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5c99278f2fe65078f73602e123501daba5ee1522f6b31865ce2e5ce77dd612cd"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "e760bd35474a20b1d4b205747c2c07fc31bd2cf37a4f942e6b0855a6bf9d8fbf"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "snapshot_role": {
+ "rolsuper": true,
+ "rolbypassrls": true
+ },
+ "reference": "423c68fc-1f5e-4c31-85a8-b70e95b7380e",
+ "duplicate_preserved_all_tables": true,
+ "shared_lease_owner_verified": true,
+ "shared_lease_released_by_worker": true,
+ "scan_results": 1,
+ "scan_status": "inconclusive",
+ "scan_reason": "scanner_unavailable",
+ "malware_engine": "ClamAV",
+ "scanner_host": "127.0.0.1",
+ "scanner_port": 1,
+ "original_cipher_preserved": true,
+ "private_temporary_files": 0,
+ "code_hash": "4a8835aaa62c85224092faa7109f88ea67f9f860ba6d857fa13f838bb6b5e6f5",
+ "active_writes": 0,
+ "active_migrations": 0,
+ "external_messages": 0,
+ "scope": "Actual document retry, shared database-cache lease, duplicate suppression and separate database queue worker with ClamD deliberately unavailable. No healthy-engine, physical race, active installation or real user acceptance claim."
+ },
+ "checks": {
+ "phpstan": "passed_five_application_sources_level_7_without_suppression",
+ "pint": "passed_six_php_sources_test",
+ "types": "passed",
+ "check": "three_sources_format_and_lint_passed",
+ "build": "passed_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/Malware/DocumentScanDelivery.php": "d34bef072621d88d49588e7498a9b5f4a881f438d259d868fa97dd91eef9e061",
+ "app/Services/Malware/DocumentScanRetry.php": "ddac00577280355c51c8345ec53e0805e75aacb7df0b183b9ef7a2507d5b5216",
+ "app/Services/OpportunityScanDispatch.php": "cb0e80cd69d0052a4a350d1d19283e2f6a7a19511b753920dc3f0a5894d9969a",
+ "app/Http/Controllers/DocumentMalwareController.php": "0a6f88460a214185ed53b5e2edc1fd955d2360e3c5888a37c4831abab84d2fce",
+ "app/Services/PortalProfileInstallation.php": "d6f7e54712e4d15a3b1f9783c154ad8a7ca5a58372d7d703e2fa9a5a755ec751",
+ "resources/js/pages/management/shared.tsx": "fd61a937262dc62dfb08b1122a1ed2f442109728ce1738eebc92ad0f57906e77",
+ "resources/js/pages/investment/zone-attachments.tsx": "e1e64cdea70aa668ce39056f0b1a08c349b583418c303ae205da33f5bee9662b",
+ "tests/Feature/DocumentScanRetryTest.php": "574c86d9a4a93c6226a0dcd37baa7da8cec1989f72fa72db90f8b1fa6d564d13",
+ "tests/frontend/document-scan-retry.test.mjs": "27e4df0b31622d8d0c28e37511e98579c44bf47b48d88ac6a62055f521fc7937"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-scan-incidents-20261103.php": "a5febcdfc89e57e8eb45d14d3416e2eae308d9e2684e9fa8877d222c4dce204e",
+ "storage/app/private/check-scan-retry-qa-20261103.php": "0043749dd2f66d5b82a208ee710a7c6ab3d70a26d1bcef18127d3943a0b52f54",
+ "storage/app/private/verify-scan-retry-operational-20261103.php": "3322e4aedb07439663237feb4214ceda575264d06a813349961209b527b54458",
+ "storage/app/private/record-scan-retry-20261103.cjs": "6a3cbcf9abe1801d2f71468ae379d6fa9b5bb115d21a8ac5ce84f11a4e85fe74"
+ },
+ "logs_sha256": {
+ "scan-retry-feature-initial-20261103.log": "b6c344f4ba2ed260f1f7414c4d1ab2275a0fbcaecb84670c25f5b9c92bd1c1dd",
+ "scan-retry-feature-final-20261103.log": "0a2926297128a0ed3939e13e2fdc8be1ac947191b53f47ac72c01be1ec25f5e6",
+ "scan-retry-frontend-final-20261103.log": "895f1693f9743bfbce28dc5b33525f619cfc07cff66f0ec3213040f9cf075285",
+ "scan-retry-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "scan-retry-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "scan-retry-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "scan-retry-check-final-20261103.log": "1604d9c53237daed95be6db605b7d83b1b0f71fe48c6d44fe71e75048481aa0f",
+ "scan-retry-build-final-20261103.log": "3954997bdbeda8e30ed8d637596df4ce6c6fe8902597748f378f27ece29ebddd",
+ "scan-retry-worker-init-20261103.log": "c8753f2d7dd3a327848143e808c1e23496d02822b388f692eab4f925801e51c8",
+ "scan-retry-worker-process-20261103.log": "a6f31ed2ba97fa0c8fe1e06ee004e035d54faa40de98cb3612df7b75f5a9108a",
+ "scan-retry-worker-verified-20261103.log": "9e0b0a91d22b2fef8e903884218f3f8516888677a0b29b6de1f7876aa1bc7172",
+ "scan-retry-worker-existing-guard-20261103.log": "90f2209ef3e9880d3fc461e17a5b83ee5a1d67556c349af367fb5b7be158def6",
+ "scan-retry-qa-accepted-20261103.json": "dfaedfd21f8de622b4bf2ea8ee172831b631a795e178eb4c3d2e8a8ecf07772a",
+ "scan-retry-worker-proof-20261103.json": "b0f74cdabf0564cf8dca33370ab72b8d4085cc00a11bcab290a72fb9dbcebbdb"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/scan-retry-check-format-20261103.log": "0db54f3e4cdd1a9eba6a4bb606583647a9f5c839cbb76f305744adf9ca14a8ce",
+ "storage/app/private/scan-retry-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/scan-retry-pint-format-20261103.log": "cf19dfaa805bc3a9800290134d302fc4de940d97b5c15b08071ed761b9406bdf"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/scan-retry-prior-receipt-20261103.json",
+ "sha256": "69db45d353c31ce1835c8c91ca12c1f37f6c85205b24c9e89c55e86ffaaa2236"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22",
+ "storage/logs/resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "storage/logs/resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "storage/logs/resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "storage/logs/resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "storage/logs/resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "storage/logs/resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "storage/logs/resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "storage/logs/resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "storage/logs/resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043",
+ "storage/logs/scan-incidents-feature-initial-20261103.log": "34c0d09fb3cef0583c005a5a21e9cf198e1d4e1b2629208184c100d56b3ef159",
+ "storage/logs/scan-incidents-feature-final-20261103.log": "de586fd101f083af0976b37c8bf80ebf29a22cf7b92e274fbbe67c308e710d35",
+ "storage/logs/scan-incidents-frontend-initial-20261103.log": "6250c3ed8c6ab9fac2dc5f3cb3f757022ac7b2971d5d359a628aabc1209c78b3",
+ "storage/logs/scan-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-incidents-check-final-20261103.log": "b605db485894f33b655ec2682f241160d4b03ff0389c8aeebbf27af6eb056df2",
+ "storage/logs/scan-incidents-build-final-20261103.log": "66c51148e850059b6404940f3189399230caa994993d63defb72ad2bd61ec921",
+ "storage/logs/scan-incidents-worker-init-20261103.log": "d1d0ba14bc20a77a8dc85236f9401ce85c9b0f9b93fa65ce875deb95b464380d",
+ "storage/logs/scan-incidents-worker-process-20261103.log": "ba3e512c805f7bb0852c62dd871dae76858919d822587c32208f6118f0e00d12",
+ "storage/logs/scan-incidents-worker-verified-20261103.log": "115c2047c614e5d8faf2ae5d1363d2661f4b092519c3a65501923f2f1fec9f59",
+ "storage/logs/scan-incidents-worker-existing-guard-20261103.log": "580207ff6534089bfa4bbde910e584aa8c55d390689f1095b8e5bf0c6d5ee363",
+ "storage/logs/scan-incidents-qa-accepted-20261103.json": "b23a6f89d98a2c43c32fae97c6b99ce9beadcfaeca610461a467d79895c825e2",
+ "storage/logs/scan-incidents-worker-proof-20261103.json": "8fa6fa596c5c51d20ea42eb8160788479b35e122f29e29ce167d802dcff893d4"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Services/OpportunityTechnicalIncidents.php": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/lib/technical-incident-labels.ts": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a",
+ "tests/frontend/technical-incident-handling.test.mjs": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "7daee388dfa39acce3a70bd114d93467870929a1c7f2810bc39ca3873980dfc4",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityResources.php": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6",
+ "app/Services/OpportunityImageProcessor.php": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a",
+ "app/Jobs/ScanDocumentForMalware.php": "7c9e3e8b55a3b635b39c1834953184dd413aacdebf5a5d7a29cd3b35a8b6055f",
+ "app/Services/Malware/DocumentScanAttempts.php": "55ea55ad4def90e6244fd64d49b3492c2afaad60788af8c7faa542cd4bfede65",
+ "app/Services/OpportunityScanDispatch.php": "650a9849c613e26658227c52dbbfdd1ef08ce9e6cfcb3d2e08a24ad3c504581c",
+ "tests/Feature/ScanTechnicalIncidentsTest.php": "6eb53d7f0a0c6f02968229e10473f9a2f3f5e9b3a11ea4a6aa4d7a1f7775d153"
+ },
+ "prior_code_deltas": {
+ "app/Services/PortalProfileInstallation.php": {
+ "previous": "7daee388dfa39acce3a70bd114d93467870929a1c7f2810bc39ca3873980dfc4",
+ "current": "d6f7e54712e4d15a3b1f9783c154ad8a7ca5a58372d7d703e2fa9a5a755ec751"
+ },
+ "app/Services/OpportunityScanDispatch.php": {
+ "previous": "650a9849c613e26658227c52dbbfdd1ef08ce9e6cfcb3d2e08a24ad3c504581c",
+ "current": "cb0e80cd69d0052a4a350d1d19283e2f6a7a19511b753920dc3f0a5894d9969a"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "ea94a8052baa43a8ea41788ee40afed5b554f406c40a5b933c29e553a0a5f71a",
+ "public/build/assets/app-c9qwUYpW.js": "6dbe5cda461f9ffa61b661b7f6e1651dd72c470c845683c29f69513b0fe1b8a2",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-D0ibHdlf.js": "38250abfdd215ca9574a6eda28fc4cabfd2f58148396ffe768207734b0005158",
+ "public/build/assets/investment-territory-De5bxhXD.js": "afaeec765c2d36d7301ce84a836af09a2d18b39467d15ff9806dbd5da6802b70",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-CTJaZ-rn.js": "0099151d043996b76409a10c646b041070215cd2bcc14a66957302a10eb609f2",
+ "public/build/assets/territory-geometry-preview-DkSGSMbH.js": "306bb0a33bedfd0dff5c9f5b8e4f2eb3b316ecdc4b2c88c60227aabcc492d1f9",
+ "public/build/assets/interactive-investment-map-Dlx3OC8g.js": "1ee54120a04c3eb5e530311af35ffd94181ebc80006ddce6dab6ae16c06ff6dc",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B-FE4xRF.js": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "public/build/assets/opportunity-draft-SL5bu0Qa.js": "beaaa80b870c6df67269906a44e3c8f9a79c25a842b1aa4bbeb75528db884523",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "public/build/assets/opportunity-search-filters-CvtDlhpL.js": "d58997e8057b431d6dd059a73de38be1dba99a5ea4d5ec13a0ccdb98c2ef0437",
+ "public/build/assets/proactive-investment-CYz0tbgM.js": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "public/build/assets/manage-BzsCf6FW.js": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "public/build/assets/zone-D5aMMwzr.js": "85a40b631b9e3baddf33833bc96fa1148b923147d5996bd472a8b65d92ddbbb1",
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "public/build/assets/investment-map-panel-CWYtMCsv.js": "f648684b21c9ba881885f062c6e33f5301bf58586ac69c808a806abcf3f9fedf",
+ "public/build/assets/catalogue-investment-map-BPtXPxxZ.js": "539080ab1c0576bdcdaccac82f188fa63b3dcc596a33f0b0b736b66df4b4c93e",
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "public/build/assets/zone-attachments-Dv822FPo.js": "4de09cbe382c691a93736872d9c05a9f37ce41301c855f381aec5356afae03ad",
+ "public/build/assets/zone-map-BeeN-Pp_.js": "a4023045fca9ea32e6b8001287f5fbd3dd1940ec565f60b4697a8f88dd4476b0",
+ "public/build/assets/zone-relations-OmoP2RN3.js": "ef4c1fc9605fc1f8e5bd5cdee932544a25fb31c049fd6b32645df9b7392e98f5",
+ "public/build/assets/catalogue-context-BI0WEkaG.js": "00dd37c73d504153873879f4d8018792597a078c2099313fc82aa49acd1f4a70",
+ "public/build/assets/installation-B0nI9WAi.js": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/support-installation-3F6rIOG2.js": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/technical-support-CpP0Ki7O.js": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "public/build/assets/technical-incident-CYL9UpWe.js": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "3b226388b8a80add73a248773d02ce9bb2c71cc38c3a494a964caeba5c5d2188",
+ "current": "ea94a8052baa43a8ea41788ee40afed5b554f406c40a5b933c29e553a0a5f71a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-BHesLmie.js": {
+ "previous": "ea37da10f078ff76f3f39985b7b54a9d9a2efca6567106a25b7f1e601e567da3",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-resources-BDZ2qE2U.js": {
+ "previous": "c2853f965a40dadb5675a6ec65a5a31d6ab659bbd949c796047488a0e2dc29ce",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-7JavasTr.js": {
+ "previous": "3f575a64b630d9e8e6d0b1123eac07e79515df2af6fd92e48d1c952edfbe66df",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-C-46-nOe.js": {
+ "previous": "8a8a5090de7eae4268ecfc4cfdcb6a7fabf40a6429a5a8e0ff89653b5b9fa7e0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-DywGUSlA.js": {
+ "previous": "174fc6ced9ae4a9aebfcb6bf79f0223555827011fda19b214a4f8c18b0191926",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-DQ19jbfY.js": {
+ "previous": "9ab8d9557d1dd1ef4a16d6af8e2063163972182efc7bafbc9af8dc118b800109",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B8ohIVwy.js": {
+ "previous": "bfc293167f9eb4eacd6dc50433308a786e5cf3178c9b100deb615286258e860c",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": {
+ "previous": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "current": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": {
+ "previous": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "current": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-CmXokNPV.js": {
+ "previous": "d23acd637577389cf78eaee94ca5b4bf5ed89d9897ca01be2a67979fdbb1aee5",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-hpwqS0Fy.js": {
+ "previous": "0f1e33a81ea1a501f9fa95a0c92e3a096b58661442f1451915b2a150294694a8",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-CncAi5Js.js": {
+ "previous": "a5531c237672eea00e238126ddf1520770ee735e2995f4add2addc434b50369d",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-PRv8PwaN.js": {
+ "previous": "82a8a5997981585b5829eb2db7145b238ba452b645c475a364b294e254b45131",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-DODMrWIz.js": {
+ "previous": "3dbffabf59f890d229bd1405507085c19b9e855a36593f812044077c4aa006dd",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-LpR5Rkrn.js": {
+ "previous": "101bad39a5c01ed9f4f0d2b9516cee1b0ef1361477c5feb656e014aa5e5a456a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-DEq0kuSc.js": {
+ "previous": "3bef9282aaec70d8b771aa6d151773c554f784d435e641288528e29869d3a0be",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-CwVG4hrN.js": {
+ "previous": "8917cfcd5abaa159be5e6f1c19f37226ec40a880875b75514c8f70d42d60bdd0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-C2M6yu59.js": {
+ "previous": "2a616744b3215c6570c5ed962246c1b2e41fe1c36df6a238744a0c938ab6f622",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "No transactional outbox or exactly-once delivery; commit/push crash gap and existing unique lease under uncertain transport remain",
+ "A duplicate means an existing cache lease, not proof of a live or healthy job; ambiguous push keeps that lease until worker release or expiry",
+ "Generic manual retry keeps the existing document-management authority and does not invent opportunity context or technical-support document rights",
+ "One actual queue worker and shared database-cache lease with ClamD deliberately unavailable; healthy engine, load and physical race are not proven",
+ "Operational rehearsal belongs to this fingerprint; current destination backup/restore, active installation and browser acceptance remain pending"
+ ]
+ },
+ "investment_profile_commands_increment_20261103": {
+ "recorded_at": "2026-11-03T20:40:31.687Z",
+ "requirements": [
+ "AUD-COUNTRY-01",
+ "AUD-COUNTRY-02",
+ "AUD-PROFILE-25"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 17,
+ "passed": 17,
+ "assertions": 248,
+ "duration_ms": 68042
+ },
+ "initial_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 17,
+ "passed": 17,
+ "assertions": 248,
+ "duration_ms": 51377
+ },
+ "new_feature_cases": 6,
+ "frontend_focused_tests": 60,
+ "new_frontend_cases": 13,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 47
+ },
+ "qa": {
+ "result": "passed",
+ "database": "scan_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "investment_accounts": 0,
+ "investment_submissions": 0,
+ "investment_submission_zones": 0,
+ "investment_submission_revisions": 0,
+ "investment_submission_attachments": 0,
+ "investment_specific_needs": 0,
+ "investment_messages": 0,
+ "investment_notifications": 0,
+ "investment_reference_options": 0,
+ "investment_submission_events": 0,
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "document_malware_scans": 0,
+ "jobs": 0,
+ "failed_jobs": 0,
+ "cache": 0,
+ "cache_locks": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "identity": {
+ "database": "workspace_profile_concurrency_20261103b_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "holder": {
+ "result": "applied",
+ "mode": "holder",
+ "pid": 21992,
+ "response": {
+ "id": "27ec073d-0bb3-4d51-a440-f020145f5424",
+ "version": 1
+ },
+ "database_lock_wait_observed": true,
+ "active_writes": 0
+ },
+ "waiter": {
+ "result": "applied",
+ "mode": "waiter",
+ "pid": 1848,
+ "response": {
+ "id": "27ec073d-0bb3-4d51-a440-f020145f5424",
+ "version": 1
+ },
+ "database_lock_wait_observed": false,
+ "active_writes": 0
+ },
+ "table_count": 190,
+ "changed_tables": [
+ "audit_events",
+ "investment_company_declarations"
+ ],
+ "declarations": 1,
+ "business_audits": 1,
+ "command_receipts": 1,
+ "payload_encrypted": true,
+ "code_sha256": {
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "b4a5ffd723fb00d6a3a7b376f7c99e334ff4d1c8a1a3cba5aed1e299e757dac6",
+ "resources/js/lib/investment-profile-editor.ts": "fd624ad1101e08500313a0d2eacf565ac5567f789fdc1008c1c482833763f453",
+ "resources/js/components/investment-profile-editor.tsx": "d53714731f456d10ff65b8886edaada3f79361267389c6d7ac7bcbc3fce88885",
+ "resources/js/pages/investment/profile.tsx": "15a1b90295471471f11623c4eee30d50ad0a645285ac7a1c39448ba3cade92a6"
+ },
+ "baseline": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "344456e64008d2b7cb494767fcd06b4cf8b3f389fde322e1b4267972accd7a2a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "a3b5d10659d3ffb631023fb572922d8f54dd688f75e4039c428ab580fcb8fb98"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "c4c3755741275a1cc3509b79d14e34807cf1bded8e04ca485e966408640a9b4c"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "344456e64008d2b7cb494767fcd06b4cf8b3f389fde322e1b4267972accd7a2a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 2,
+ "sha256": "e79fe972a24037a8eb2127313ee4f85168cc293644438a5cf397e4c67fd7e173"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 1,
+ "sha256": "fc6da71613d44108ed3bd6644e490049626f863e499244d5de2a01cd8c659356"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "a3b5d10659d3ffb631023fb572922d8f54dd688f75e4039c428ab580fcb8fb98"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "c4c3755741275a1cc3509b79d14e34807cf1bded8e04ca485e966408640a9b4c"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "snapshot_role": {
+ "rolsuper": true,
+ "rolbypassrls": true
+ },
+ "active_writes": 0,
+ "active_migrations": 0,
+ "external_messages": 0,
+ "scope": "Two separate PHP controller-command processes, real PostgreSQL user-row lock wait and replay; HTTP middleware is covered by Feature tests, not this direct-controller rehearsal. No active installation or real-user acceptance."
+ },
+ "checks": {
+ "phpstan": "passed_two_application_sources_level_7_without_suppression",
+ "pint": "passed_three_php_sources_test",
+ "types": "passed",
+ "check": "five_sources_format_and_lint_passed",
+ "build": "passed_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "b4a5ffd723fb00d6a3a7b376f7c99e334ff4d1c8a1a3cba5aed1e299e757dac6",
+ "resources/js/lib/investment-profile-editor.ts": "fd624ad1101e08500313a0d2eacf565ac5567f789fdc1008c1c482833763f453",
+ "resources/js/components/investment-profile-editor.tsx": "d53714731f456d10ff65b8886edaada3f79361267389c6d7ac7bcbc3fce88885",
+ "resources/js/pages/investment/profile.tsx": "15a1b90295471471f11623c4eee30d50ad0a645285ac7a1c39448ba3cade92a6",
+ "tests/Feature/InvestmentProfileCommandsTest.php": "515564e26321c449427b114ad7b009519f774f0a8443f2aa1997b6fd636971b5",
+ "tests/frontend/investment-profile-editor.test.mjs": "3fe4f8c527f15ab10c96328a16049ee7ad42c539adeb5c16b973de282d480b8d",
+ "tests/frontend/helpers/investment-profile-editor.mjs": "3f2c4ea81e3d10b5ff86079d72d5728411f25634ce8f635200517ed07eed8d2d"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-scan-incidents-20261103.php": "a5febcdfc89e57e8eb45d14d3416e2eae308d9e2684e9fa8877d222c4dce204e",
+ "storage/app/private/check-workspace-profile-qa-20261103.php": "13f0a9b09549acf5639c298cafd5141170b77c5770ea93329c0aa49a328f0690",
+ "storage/app/private/verify-workspace-profile-concurrency-20261103.php": "c22cac819c61da5b44230e9234dcdc4cc9a722dc99a54ee9581bac8c1ad0c7e1",
+ "storage/app/private/verify-workspace-profile-concurrency-final-20261103.php": "1512e4c31576ec2fd655cb9c03198e33d96373216a6f53e203e236aa849d484e",
+ "storage/app/private/record-workspace-profile-20261103.cjs": "ee99bf2154477e1c45251d8ce593bf31661e5d245b3ac3a15577ed3263895e38"
+ },
+ "logs_sha256": {
+ "workspace-profile-feature-initial-20261103.log": "710dbcb04c49c91bfbafdff9ffb15bfb13a4656481241b9c7d52928adf38c171",
+ "workspace-profile-feature-final-20261103.log": "d256c45808794f1e5209ac4946e28374509600cb99801b296ae57153f63f1b96",
+ "workspace-profile-frontend-initial-20261103.log": "00b58f85e3f43e12e2fbf92bc6021121b4929a0dfcee382c0b228733e887af20",
+ "workspace-profile-frontend-final-20261103.log": "0d3779784a8c5babcce77869b52fe57539188801836392b605e029d32525cc14",
+ "workspace-profile-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "workspace-profile-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "workspace-profile-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "workspace-profile-check-final-20261103.log": "d752c22d4c752c723185f92bb2e22f54cb297f211fe845fc452c5087ef168b3b",
+ "workspace-profile-build-final-20261103.log": "48ec8ccc289dfd2c463cfa99d461fa047f2bcd7c089553af8076c5eb7f807949",
+ "workspace-profile-concurrency-final-init-20261103.log": "b7abc147e484337609ca6d3d0852b83db63281e92634f037afb5a9abc111a935",
+ "workspace-profile-concurrency-final-holder-20261103.log": "ebc5891a64bdef23eba411f3f7865fdb5026bbfb85bb9e5620cf3ae8a553e5aa",
+ "workspace-profile-concurrency-final-waiter-20261103.log": "25c1f2d94f7e0132025975b71d2836d8a98169aa8b53aa0185a20ade3a1caab8",
+ "workspace-profile-concurrency-final-verified-20261103.log": "a52acb13a8ab1fdc6ffd8ca859775ea7c1357c44d7cb03887e862d335c8c7289",
+ "workspace-profile-concurrency-final-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "workspace-profile-qa-accepted-20261103.json": "dedd179d9dc34aeb55b72cb5bc99d3dae7df8cc0201b70322c2fdbadfb4c48db",
+ "workspace-profile-concurrency-proof-20261103.json": "2fc4b3865f08230be5d5739869fc547c22a7dfbcfd1702ab2109a4202a03d800"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/workspace-profile-build-first-candidate-20261103.log": "1637dba78ace77e309ff0aa6754f5eb54361d85462dadd1f783e30f4e75d0487",
+ "storage/app/private/workspace-profile-check-format-20261103.log": "0cd03166ad0f1e5e0664136334cb0d99ab5b88aaaf4de11e6927d5d021ca79ca",
+ "storage/app/private/workspace-profile-check-helper-format-20261103.log": "77c3d64b44346805d1bd227e58cd0fe7c54f9e3d45e4785fff0a2d0f95062a85",
+ "storage/app/private/workspace-profile-check-last-format-20261103.log": "0c1a234ec32501f0daa6fd810e5ac4290b6566d5ca021a85fcd521adc9fd4be4",
+ "storage/app/private/workspace-profile-concurrency-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "storage/app/private/workspace-profile-concurrency-holder-20261103.log": "d8f1c255f22c5a44a8807060441db4ba687a86cc8dc813ab999497d05cc4d19f",
+ "storage/app/private/workspace-profile-concurrency-init-20261103.log": "9d75fefc58504245f09e3dabb6c26779c166fab4267b51901e5b696715c49e1b",
+ "storage/app/private/workspace-profile-concurrency-verified-20261103.log": "f99632e0979ae121fc6b63378b0ec069a9b43f5002e2097a5760640717cd2e34",
+ "storage/app/private/workspace-profile-concurrency-waiter-20261103.log": "206c2bc80722287d21794bf95970b4d3d3178562062f7c2490eec308cde87e38",
+ "storage/app/private/workspace-profile-frontend-window-diagnostic-20261103.log": "245bdf494e7b676d1c03c1d5c751d05c0657ff8be24b1d3191f42aa19a57599e",
+ "storage/app/private/workspace-profile-phpstan-initial-20261103.log": "3a9d1fc2a2e4e01d937394926fed7d5625899d5b13b49cef8515762865dfdf1f",
+ "storage/app/private/workspace-profile-pint-format-20261103.log": "23e040b7e143567ca48ced7ebf670c9a2a5a28f62a51b3707d73d5e4510f13ca",
+ "storage/app/private/workspace-profile-types-initial-20261103.log": "91e2ce52f624629e4476a72a3144ce49b1e98067ed85cc0535add9c79dff43d2"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/workspace-profile-prior-receipt-20261103.json",
+ "sha256": "1d75ebc3fafd575636c200c0907364ced83f10faa4b244f0984bd7ed518b473b"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22",
+ "storage/logs/resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "storage/logs/resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "storage/logs/resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "storage/logs/resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "storage/logs/resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "storage/logs/resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "storage/logs/resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "storage/logs/resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "storage/logs/resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043",
+ "storage/logs/scan-incidents-feature-initial-20261103.log": "34c0d09fb3cef0583c005a5a21e9cf198e1d4e1b2629208184c100d56b3ef159",
+ "storage/logs/scan-incidents-feature-final-20261103.log": "de586fd101f083af0976b37c8bf80ebf29a22cf7b92e274fbbe67c308e710d35",
+ "storage/logs/scan-incidents-frontend-initial-20261103.log": "6250c3ed8c6ab9fac2dc5f3cb3f757022ac7b2971d5d359a628aabc1209c78b3",
+ "storage/logs/scan-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-incidents-check-final-20261103.log": "b605db485894f33b655ec2682f241160d4b03ff0389c8aeebbf27af6eb056df2",
+ "storage/logs/scan-incidents-build-final-20261103.log": "66c51148e850059b6404940f3189399230caa994993d63defb72ad2bd61ec921",
+ "storage/logs/scan-incidents-worker-init-20261103.log": "d1d0ba14bc20a77a8dc85236f9401ce85c9b0f9b93fa65ce875deb95b464380d",
+ "storage/logs/scan-incidents-worker-process-20261103.log": "ba3e512c805f7bb0852c62dd871dae76858919d822587c32208f6118f0e00d12",
+ "storage/logs/scan-incidents-worker-verified-20261103.log": "115c2047c614e5d8faf2ae5d1363d2661f4b092519c3a65501923f2f1fec9f59",
+ "storage/logs/scan-incidents-worker-existing-guard-20261103.log": "580207ff6534089bfa4bbde910e584aa8c55d390689f1095b8e5bf0c6d5ee363",
+ "storage/logs/scan-incidents-qa-accepted-20261103.json": "b23a6f89d98a2c43c32fae97c6b99ce9beadcfaeca610461a467d79895c825e2",
+ "storage/logs/scan-incidents-worker-proof-20261103.json": "8fa6fa596c5c51d20ea42eb8160788479b35e122f29e29ce167d802dcff893d4",
+ "storage/logs/scan-retry-feature-initial-20261103.log": "b6c344f4ba2ed260f1f7414c4d1ab2275a0fbcaecb84670c25f5b9c92bd1c1dd",
+ "storage/logs/scan-retry-feature-final-20261103.log": "0a2926297128a0ed3939e13e2fdc8be1ac947191b53f47ac72c01be1ec25f5e6",
+ "storage/logs/scan-retry-frontend-final-20261103.log": "895f1693f9743bfbce28dc5b33525f619cfc07cff66f0ec3213040f9cf075285",
+ "storage/logs/scan-retry-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-retry-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-retry-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-retry-check-final-20261103.log": "1604d9c53237daed95be6db605b7d83b1b0f71fe48c6d44fe71e75048481aa0f",
+ "storage/logs/scan-retry-build-final-20261103.log": "3954997bdbeda8e30ed8d637596df4ce6c6fe8902597748f378f27ece29ebddd",
+ "storage/logs/scan-retry-worker-init-20261103.log": "c8753f2d7dd3a327848143e808c1e23496d02822b388f692eab4f925801e51c8",
+ "storage/logs/scan-retry-worker-process-20261103.log": "a6f31ed2ba97fa0c8fe1e06ee004e035d54faa40de98cb3612df7b75f5a9108a",
+ "storage/logs/scan-retry-worker-verified-20261103.log": "9e0b0a91d22b2fef8e903884218f3f8516888677a0b29b6de1f7876aa1bc7172",
+ "storage/logs/scan-retry-worker-existing-guard-20261103.log": "90f2209ef3e9880d3fc461e17a5b83ee5a1d67556c349af367fb5b7be158def6",
+ "storage/logs/scan-retry-qa-accepted-20261103.json": "dfaedfd21f8de622b4bf2ea8ee172831b631a795e178eb4c3d2e8a8ecf07772a",
+ "storage/logs/scan-retry-worker-proof-20261103.json": "b0f74cdabf0564cf8dca33370ab72b8d4085cc00a11bcab290a72fb9dbcebbdb"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Services/OpportunityTechnicalIncidents.php": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/lib/technical-incident-labels.ts": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a",
+ "tests/frontend/technical-incident-handling.test.mjs": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "d6f7e54712e4d15a3b1f9783c154ad8a7ca5a58372d7d703e2fa9a5a755ec751",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityResources.php": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6",
+ "app/Services/OpportunityImageProcessor.php": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a",
+ "app/Jobs/ScanDocumentForMalware.php": "7c9e3e8b55a3b635b39c1834953184dd413aacdebf5a5d7a29cd3b35a8b6055f",
+ "app/Services/Malware/DocumentScanAttempts.php": "55ea55ad4def90e6244fd64d49b3492c2afaad60788af8c7faa542cd4bfede65",
+ "app/Services/OpportunityScanDispatch.php": "cb0e80cd69d0052a4a350d1d19283e2f6a7a19511b753920dc3f0a5894d9969a",
+ "tests/Feature/ScanTechnicalIncidentsTest.php": "6eb53d7f0a0c6f02968229e10473f9a2f3f5e9b3a11ea4a6aa4d7a1f7775d153",
+ "app/Services/Malware/DocumentScanDelivery.php": "d34bef072621d88d49588e7498a9b5f4a881f438d259d868fa97dd91eef9e061",
+ "app/Services/Malware/DocumentScanRetry.php": "ddac00577280355c51c8345ec53e0805e75aacb7df0b183b9ef7a2507d5b5216",
+ "app/Http/Controllers/DocumentMalwareController.php": "0a6f88460a214185ed53b5e2edc1fd955d2360e3c5888a37c4831abab84d2fce",
+ "resources/js/pages/management/shared.tsx": "fd61a937262dc62dfb08b1122a1ed2f442109728ce1738eebc92ad0f57906e77",
+ "resources/js/pages/investment/zone-attachments.tsx": "e1e64cdea70aa668ce39056f0b1a08c349b583418c303ae205da33f5bee9662b",
+ "tests/Feature/DocumentScanRetryTest.php": "574c86d9a4a93c6226a0dcd37baa7da8cec1989f72fa72db90f8b1fa6d564d13",
+ "tests/frontend/document-scan-retry.test.mjs": "27e4df0b31622d8d0c28e37511e98579c44bf47b48d88ac6a62055f521fc7937"
+ },
+ "prior_code_deltas": {},
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "14235236b4f12eb567159541029429a88905fb6a89b0cdafa15a4e468592af6e",
+ "public/build/assets/app-DJr5rmsF.js": "2bca9a6d9f9fc63a779df337477f80d35027ed9e15eec6d4bc07af8791a6bbf9",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-hsjfuv9C.js": "1679ca19adb73c1a56957f0f5752f40339499ab968029cfee344a1414ac69298",
+ "public/build/assets/investment-territory-YaiLxYkU.js": "824a8d85bde24ae122e9fa8910ab87c64d4085161dba07ae495ab961dd3b7c7e",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-BvN_k0_p.js": "928ea114db19750db2f2c6c729ebb1b11e8394c5b882729b5f3e0886df45cd70",
+ "public/build/assets/territory-geometry-preview-CGVx8_We.js": "4f8fdfacd1372ca4c8320f78e14f1da45a94d892a02d658d49dd23a4b50fe2e3",
+ "public/build/assets/interactive-investment-map-CTkcRNba.js": "9ceff8e2fa71f2f9cb04692444964a8bb26dc96469539b66d93caef664ccf4f7",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B-FE4xRF.js": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "public/build/assets/opportunity-draft-CvlU8e5g.js": "a956ced4621a307a392b75e6269d4d4e05f5233ad07be08251ce7545389f30b0",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "public/build/assets/opportunity-search-filters-6s36qI7n.js": "f66b188ef9b4d000f1f1ec8275902028fc21100f68c3ca74836a5a6908215b78",
+ "public/build/assets/proactive-investment-CYz0tbgM.js": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "public/build/assets/manage-BzsCf6FW.js": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "public/build/assets/zone-BscN3JR0.js": "61f05a2a43646442b20d58e8fecfe1a1cd2cc2d3928e6fe156074b5dec3dc91b",
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "public/build/assets/investment-map-panel-BIMfpRze.js": "0b77d7bba43f5455b883d8e7dd228f757ebda10a3af08fcfb7fdbf87e2aba2b2",
+ "public/build/assets/catalogue-investment-map-BA-fR0Wn.js": "d7e1a924435c779f7025caeb909588b4c9cb6161adda24bb9d5c85cfe6777e7e",
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "public/build/assets/zone-attachments-CqGuadTd.js": "3b586d3e31441147aa4fc7faee8336a8edbb5f75f051929da7e0e89dd56e0480",
+ "public/build/assets/zone-map-CDhWr74x.js": "2dd9c7ac7c1931d5957c872fc8d54c81f063848f8a0500ae5e4c1905184a26ca",
+ "public/build/assets/zone-relations-BSGH6FF3.js": "1a5a9d9d077c3ec804817b7b010195f9a8653b68dd3ca4340535c117509af481",
+ "public/build/assets/catalogue-context-CJVNp__h.js": "5b69fda73199a8d432782c5224cef152082d45c30d277f93a1ca2de5e145061e",
+ "public/build/assets/profile-B981DCv9.js": "1fea63cc90ae2729b41583bfcc39f9da0e9d20ac180de6763ebe67cba198a785",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/country-select-4uP5BvMf.js": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/installation-B0nI9WAi.js": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "public/build/assets/support-installation-3F6rIOG2.js": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "public/build/assets/technical-support-CpP0Ki7O.js": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "public/build/assets/technical-incident-CYL9UpWe.js": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "ea94a8052baa43a8ea41788ee40afed5b554f406c40a5b933c29e553a0a5f71a",
+ "current": "14235236b4f12eb567159541029429a88905fb6a89b0cdafa15a4e468592af6e",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-c9qwUYpW.js": {
+ "previous": "6dbe5cda461f9ffa61b661b7f6e1651dd72c470c845683c29f69513b0fe1b8a2",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-resources-D0ibHdlf.js": {
+ "previous": "38250abfdd215ca9574a6eda28fc4cabfd2f58148396ffe768207734b0005158",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-De5bxhXD.js": {
+ "previous": "afaeec765c2d36d7301ce84a836af09a2d18b39467d15ff9806dbd5da6802b70",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-CTJaZ-rn.js": {
+ "previous": "0099151d043996b76409a10c646b041070215cd2bcc14a66957302a10eb609f2",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-DkSGSMbH.js": {
+ "previous": "306bb0a33bedfd0dff5c9f5b8e4f2eb3b316ecdc4b2c88c60227aabcc492d1f9",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-Dlx3OC8g.js": {
+ "previous": "1ee54120a04c3eb5e530311af35ffd94181ebc80006ddce6dab6ae16c06ff6dc",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B-FE4xRF.js": {
+ "previous": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "current": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": {
+ "previous": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "current": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": {
+ "previous": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "current": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-SL5bu0Qa.js": {
+ "previous": "beaaa80b870c6df67269906a44e3c8f9a79c25a842b1aa4bbeb75528db884523",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": {
+ "previous": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "current": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-CvtDlhpL.js": {
+ "previous": "d58997e8057b431d6dd059a73de38be1dba99a5ea4d5ec13a0ccdb98c2ef0437",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-CYz0tbgM.js": {
+ "previous": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "current": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/manage-BzsCf6FW.js": {
+ "previous": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "current": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-D5aMMwzr.js": {
+ "previous": "85a40b631b9e3baddf33833bc96fa1148b923147d5996bd472a8b65d92ddbbb1",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": {
+ "previous": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "current": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-map-panel-CWYtMCsv.js": {
+ "previous": "f648684b21c9ba881885f062c6e33f5301bf58586ac69c808a806abcf3f9fedf",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-investment-map-BPtXPxxZ.js": {
+ "previous": "539080ab1c0576bdcdaccac82f188fa63b3dcc596a33f0b0b736b66df4b4c93e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": {
+ "previous": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "current": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-attachments-Dv822FPo.js": {
+ "previous": "4de09cbe382c691a93736872d9c05a9f37ce41301c855f381aec5356afae03ad",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-map-BeeN-Pp_.js": {
+ "previous": "a4023045fca9ea32e6b8001287f5fbd3dd1940ec565f60b4697a8f88dd4476b0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-relations-OmoP2RN3.js": {
+ "previous": "ef4c1fc9605fc1f8e5bd5cdee932544a25fb31c049fd6b32645df9b7392e98f5",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-context-BI0WEkaG.js": {
+ "previous": "00dd37c73d504153873879f4d8018792597a078c2099313fc82aa49acd1f4a70",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-B0nI9WAi.js": {
+ "previous": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "current": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-3F6rIOG2.js": {
+ "previous": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "current": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-CpP0Ki7O.js": {
+ "previous": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "current": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": {
+ "previous": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "current": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-CYL9UpWe.js": {
+ "previous": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "current": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Optional operation keys preserve legacy clients; clients omitting the key keep their previous semantics",
+ "Account/company preparations remain page memory with one leave guard; durable navigation/reload/expiry recovery is not claimed",
+ "Organisation master-country editor keeps its separate existing path; full recovery/idempotency for that form and other consumers remains pending",
+ "Concurrent controller commands use real PostgreSQL lock waiting; HTTP middleware is separately covered by Feature tests, not the direct-controller rehearsal",
+ "Browser/real-user acceptance, active deployment and destination backup/restore remain pending"
+ ]
+ },
+ "organization_country_editor_increment_20261103": {
+ "recorded_at": "2026-11-03T21:01:56.187Z",
+ "requirements": [
+ "AUD-COUNTRY-02",
+ "AUD-PROFILE-25"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 23,
+ "passed": 23,
+ "assertions": 295,
+ "duration_ms": 190345
+ },
+ "initial_feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 22,
+ "passed": 22,
+ "assertions": 288,
+ "duration_ms": 201084
+ },
+ "new_feature_cases": 6,
+ "frontend_focused_tests": 69,
+ "new_frontend_cases": 9,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 60
+ },
+ "qa": {
+ "result": "passed",
+ "database": "scan_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "investment_accounts": 0,
+ "investment_submissions": 0,
+ "investment_submission_zones": 0,
+ "investment_submission_revisions": 0,
+ "investment_submission_attachments": 0,
+ "investment_specific_needs": 0,
+ "investment_messages": 0,
+ "investment_notifications": 0,
+ "investment_reference_options": 0,
+ "investment_submission_events": 0,
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "document_malware_scans": 0,
+ "jobs": 0,
+ "failed_jobs": 0,
+ "cache": 0,
+ "cache_locks": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "identity": {
+ "database": "organization_country_editor_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "holder": {
+ "result": "applied",
+ "mode": "holder",
+ "pid": 22568,
+ "response": {
+ "version": 2,
+ "country": "FR"
+ },
+ "database_lock_wait_observed": true,
+ "active_writes": 0
+ },
+ "waiter": {
+ "result": "applied",
+ "mode": "waiter",
+ "pid": 28816,
+ "response": {
+ "status": 409
+ },
+ "database_lock_wait_observed": false,
+ "active_writes": 0
+ },
+ "table_count": 190,
+ "changed_tables": [
+ "audit_events",
+ "organizations"
+ ],
+ "organizations": 1,
+ "country": "FR",
+ "version": 2,
+ "business_audits": 1,
+ "command_receipts": 1,
+ "command_encrypted": true,
+ "code_sha256": {
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "app/Services/OrganizationCountry.php": "7c41807102d9cf8dac11f6a438b2c3fae079543d6b1d3bc245996ced5bb517c3",
+ "resources/js/lib/investment-profile-editor.ts": "54f2f450130c09533e85615a3f1a4959cb079c087ea7a306333e9097456e5f2f",
+ "resources/js/components/organization-country-editor.tsx": "6e280f7a08a9d1632cefac977005be1d5e8e48fe6a5ff6b09b880e5ff0dfa15c",
+ "resources/js/pages/investment/profile.tsx": "8bfb74247596fb0767869a8bd007e8453e959417ce218ba4d7fafbe68aa913d4"
+ },
+ "baseline": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "7bde62a85bdeda47eeb493840b1f3fd146e739c1842fcb8f56a6ee63d6c2137a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 2,
+ "sha256": "7f4626f965d180bcef8d881877ce42b574874754c0fb1f8e9cc0b0f2257c4fe1"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "2ce2c76a73d6ba104a22513948228ab01d7900c33ce2fa81f8a8acc7403085ab"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5ac7f027343a16b36a957b2a59701dbbf39e2955e81d14391832868c1d5a4668"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 2,
+ "sha256": "e80fa60f52331ab8439f641ac461848ff2935ba33b264124f34a99a1eb39f7b7"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "7bde62a85bdeda47eeb493840b1f3fd146e739c1842fcb8f56a6ee63d6c2137a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 2,
+ "sha256": "2b316dafc335f01658cf7bb1e1b26fb4c47424e9e92af5ddf9fe7f3c6b2d2557"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 2,
+ "sha256": "7f4626f965d180bcef8d881877ce42b574874754c0fb1f8e9cc0b0f2257c4fe1"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "dfb379a98e8efb418bca8f8a78e748a3b94f2de330e8614f48ddabb9bb73300f"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5ac7f027343a16b36a957b2a59701dbbf39e2955e81d14391832868c1d5a4668"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 2,
+ "sha256": "e80fa60f52331ab8439f641ac461848ff2935ba33b264124f34a99a1eb39f7b7"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "snapshot_role": {
+ "rolsuper": true,
+ "rolbypassrls": true
+ },
+ "active_writes": 0,
+ "active_migrations": 0,
+ "external_messages": 0,
+ "scope": "Two different synthetic representatives in separate PHP controller processes, real PostgreSQL organization-row lock wait; one country revision, one stale 409, original source preserved. HTTP middleware and replay are covered separately by Feature tests; no active install or real-user acceptance."
+ },
+ "checks": {
+ "phpstan": "passed_two_application_sources_level_7_without_suppression",
+ "pint": "passed_two_php_sources_test",
+ "types": "passed",
+ "check": "five_sources_format_and_lint_passed",
+ "build": "passed_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/OrganizationCountry.php": "7c41807102d9cf8dac11f6a438b2c3fae079543d6b1d3bc245996ced5bb517c3",
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "resources/js/lib/investment-profile-editor.ts": "54f2f450130c09533e85615a3f1a4959cb079c087ea7a306333e9097456e5f2f",
+ "resources/js/components/organization-country-editor.tsx": "6e280f7a08a9d1632cefac977005be1d5e8e48fe6a5ff6b09b880e5ff0dfa15c",
+ "resources/js/pages/investment/profile.tsx": "8bfb74247596fb0767869a8bd007e8453e959417ce218ba4d7fafbe68aa913d4",
+ "tests/Feature/OrganizationCountryCommandsTest.php": "4aa127bbed6b735ffd0df11f0237411dee59793ed219f48ae66ec757bcd6709f",
+ "tests/frontend/organization-country-editor.test.mjs": "2c626f14ee55c8c43f91d2505eb8fcfc1722d5e54cc0b1788574ec936eb66c63",
+ "tests/frontend/helpers/investment-profile-editor.mjs": "be40b797348c0488d158cade713599e1db31c0a7deaa3f8e063eea02ced3e084"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-scan-incidents-20261103.php": "a5febcdfc89e57e8eb45d14d3416e2eae308d9e2684e9fa8877d222c4dce204e",
+ "storage/app/private/check-workspace-profile-qa-20261103.php": "13f0a9b09549acf5639c298cafd5141170b77c5770ea93329c0aa49a328f0690",
+ "storage/app/private/verify-workspace-profile-concurrency-20261103.php": "c22cac819c61da5b44230e9234dcdc4cc9a722dc99a54ee9581bac8c1ad0c7e1",
+ "storage/app/private/record-workspace-profile-20261103.cjs": "ee99bf2154477e1c45251d8ce593bf31661e5d245b3ac3a15577ed3263895e38"
+ },
+ "logs_sha256": {
+ "organization-country-editor-feature-initial-20261103.log": "2878de5d5a95e797abaef832933cf5dc5cdceb3c3120491ce213269ff993b497",
+ "organization-country-editor-feature-final-20261103.log": "e1503875a2f703324ef7d0fb47b89c37927d1767686ed871cbf37e6ea14cc457",
+ "organization-country-editor-frontend-initial-20261103.log": "af099ad22efb3e365e5303c5c6c24377db22f4a70fc6531b2c6270c6d569ad46",
+ "organization-country-editor-frontend-final-20261103.log": "8e2b1cc65e4d113b8d0202c5e4071eb0f9235a9e575b164c0f76a2d9c7e5725f",
+ "organization-country-editor-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "organization-country-editor-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "organization-country-editor-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "organization-country-editor-check-final-20261103.log": "9e9d51c6c9f621426d985f3d7bd521fa051f2348e9f51afeb25d6a78e5bff006",
+ "organization-country-editor-build-final-20261103.log": "9a52ae9a4d95d8a81720832be33735a9e88988976945727c606b1dc167f28c53",
+ "organization-country-editor-concurrency-init-20261103.log": "63d93f82c36bed7a46558a707f66d3ad81000487a576751621f346356ff4ad1e",
+ "organization-country-editor-concurrency-holder-20261103.log": "4d5a929380ac4afd88f6a96003c0f1ae86034c405b244f8d44c4f06038781729",
+ "organization-country-editor-concurrency-waiter-20261103.log": "e33c978249d5b5ec3dd5f83a05a1d5ac1d3f50413cd0112e58d7a813635303eb",
+ "organization-country-editor-concurrency-verified-20261103.log": "9f93a21016a4a48e9143e39f01589b5a33f425a84ca49db1a3294e532eddc337",
+ "organization-country-editor-concurrency-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "organization-country-editor-qa-accepted-20261103.json": "dedd179d9dc34aeb55b72cb5bc99d3dae7df8cc0201b70322c2fdbadfb4c48db",
+ "organization-country-editor-concurrency-proof-20261103.json": "04a8e8f9ecf86f986f8d6b42feeea405306386c5bc3bfa5b741967979a2441e8"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/organization-country-editor-build-first-candidate-20261103.log": "19dacfdf6c97518127727525c24eb253ddd7878fc68b934a8590fcfd67b4401f",
+ "storage/app/private/organization-country-editor-check-format-20261103.log": "dfdc6a8f6e52833f23a19f7ec5291e3f02865f538d8abd6c9642925cdedcceab",
+ "storage/app/private/organization-country-editor-check-recovery-format-20261103.log": "178a414e10b7cc2085d1b44786923d4aa68dbf27985e807b669b1f716a9c8b8c",
+ "storage/app/private/organization-country-editor-check-test-format-20261103.log": "b89e06f2e7fdaf872b7ebf508cb371f344370a8cbb01cff6e0356f9346088238",
+ "storage/app/private/organization-country-editor-membership-fixture-diagnostic-20261103.log": "6417f55f6b842eb8f9d7289562c8cd44f109c01e5789725519041297ef427974",
+ "storage/app/private/organization-country-editor-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/organization-country-editor-pint-format-20261103.log": "e81c46998d51e4b0e2645222312007b659d7f67a58209d428c1e3b837b518a66",
+ "storage/app/private/organization-country-editor-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/organization-country-editor-prior-receipt-20261103.json",
+ "sha256": "09ba149096ac120cbcfa3e3b7a074917671ef6e94ebc7f7a5209fe2c21f807f1"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22",
+ "storage/logs/resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "storage/logs/resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "storage/logs/resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "storage/logs/resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "storage/logs/resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "storage/logs/resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "storage/logs/resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "storage/logs/resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "storage/logs/resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043",
+ "storage/logs/scan-incidents-feature-initial-20261103.log": "34c0d09fb3cef0583c005a5a21e9cf198e1d4e1b2629208184c100d56b3ef159",
+ "storage/logs/scan-incidents-feature-final-20261103.log": "de586fd101f083af0976b37c8bf80ebf29a22cf7b92e274fbbe67c308e710d35",
+ "storage/logs/scan-incidents-frontend-initial-20261103.log": "6250c3ed8c6ab9fac2dc5f3cb3f757022ac7b2971d5d359a628aabc1209c78b3",
+ "storage/logs/scan-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-incidents-check-final-20261103.log": "b605db485894f33b655ec2682f241160d4b03ff0389c8aeebbf27af6eb056df2",
+ "storage/logs/scan-incidents-build-final-20261103.log": "66c51148e850059b6404940f3189399230caa994993d63defb72ad2bd61ec921",
+ "storage/logs/scan-incidents-worker-init-20261103.log": "d1d0ba14bc20a77a8dc85236f9401ce85c9b0f9b93fa65ce875deb95b464380d",
+ "storage/logs/scan-incidents-worker-process-20261103.log": "ba3e512c805f7bb0852c62dd871dae76858919d822587c32208f6118f0e00d12",
+ "storage/logs/scan-incidents-worker-verified-20261103.log": "115c2047c614e5d8faf2ae5d1363d2661f4b092519c3a65501923f2f1fec9f59",
+ "storage/logs/scan-incidents-worker-existing-guard-20261103.log": "580207ff6534089bfa4bbde910e584aa8c55d390689f1095b8e5bf0c6d5ee363",
+ "storage/logs/scan-incidents-qa-accepted-20261103.json": "b23a6f89d98a2c43c32fae97c6b99ce9beadcfaeca610461a467d79895c825e2",
+ "storage/logs/scan-incidents-worker-proof-20261103.json": "8fa6fa596c5c51d20ea42eb8160788479b35e122f29e29ce167d802dcff893d4",
+ "storage/logs/scan-retry-feature-initial-20261103.log": "b6c344f4ba2ed260f1f7414c4d1ab2275a0fbcaecb84670c25f5b9c92bd1c1dd",
+ "storage/logs/scan-retry-feature-final-20261103.log": "0a2926297128a0ed3939e13e2fdc8be1ac947191b53f47ac72c01be1ec25f5e6",
+ "storage/logs/scan-retry-frontend-final-20261103.log": "895f1693f9743bfbce28dc5b33525f619cfc07cff66f0ec3213040f9cf075285",
+ "storage/logs/scan-retry-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-retry-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-retry-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-retry-check-final-20261103.log": "1604d9c53237daed95be6db605b7d83b1b0f71fe48c6d44fe71e75048481aa0f",
+ "storage/logs/scan-retry-build-final-20261103.log": "3954997bdbeda8e30ed8d637596df4ce6c6fe8902597748f378f27ece29ebddd",
+ "storage/logs/scan-retry-worker-init-20261103.log": "c8753f2d7dd3a327848143e808c1e23496d02822b388f692eab4f925801e51c8",
+ "storage/logs/scan-retry-worker-process-20261103.log": "a6f31ed2ba97fa0c8fe1e06ee004e035d54faa40de98cb3612df7b75f5a9108a",
+ "storage/logs/scan-retry-worker-verified-20261103.log": "9e0b0a91d22b2fef8e903884218f3f8516888677a0b29b6de1f7876aa1bc7172",
+ "storage/logs/scan-retry-worker-existing-guard-20261103.log": "90f2209ef3e9880d3fc461e17a5b83ee5a1d67556c349af367fb5b7be158def6",
+ "storage/logs/scan-retry-qa-accepted-20261103.json": "dfaedfd21f8de622b4bf2ea8ee172831b631a795e178eb4c3d2e8a8ecf07772a",
+ "storage/logs/scan-retry-worker-proof-20261103.json": "b0f74cdabf0564cf8dca33370ab72b8d4085cc00a11bcab290a72fb9dbcebbdb",
+ "storage/logs/workspace-profile-feature-initial-20261103.log": "710dbcb04c49c91bfbafdff9ffb15bfb13a4656481241b9c7d52928adf38c171",
+ "storage/logs/workspace-profile-feature-final-20261103.log": "d256c45808794f1e5209ac4946e28374509600cb99801b296ae57153f63f1b96",
+ "storage/logs/workspace-profile-frontend-initial-20261103.log": "00b58f85e3f43e12e2fbf92bc6021121b4929a0dfcee382c0b228733e887af20",
+ "storage/logs/workspace-profile-frontend-final-20261103.log": "0d3779784a8c5babcce77869b52fe57539188801836392b605e029d32525cc14",
+ "storage/logs/workspace-profile-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/workspace-profile-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/workspace-profile-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/workspace-profile-check-final-20261103.log": "d752c22d4c752c723185f92bb2e22f54cb297f211fe845fc452c5087ef168b3b",
+ "storage/logs/workspace-profile-build-final-20261103.log": "48ec8ccc289dfd2c463cfa99d461fa047f2bcd7c089553af8076c5eb7f807949",
+ "storage/logs/workspace-profile-concurrency-final-init-20261103.log": "b7abc147e484337609ca6d3d0852b83db63281e92634f037afb5a9abc111a935",
+ "storage/logs/workspace-profile-concurrency-final-holder-20261103.log": "ebc5891a64bdef23eba411f3f7865fdb5026bbfb85bb9e5620cf3ae8a553e5aa",
+ "storage/logs/workspace-profile-concurrency-final-waiter-20261103.log": "25c1f2d94f7e0132025975b71d2836d8a98169aa8b53aa0185a20ade3a1caab8",
+ "storage/logs/workspace-profile-concurrency-final-verified-20261103.log": "a52acb13a8ab1fdc6ffd8ca859775ea7c1357c44d7cb03887e862d335c8c7289",
+ "storage/logs/workspace-profile-concurrency-final-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "storage/logs/workspace-profile-qa-accepted-20261103.json": "dedd179d9dc34aeb55b72cb5bc99d3dae7df8cc0201b70322c2fdbadfb4c48db",
+ "storage/logs/workspace-profile-concurrency-proof-20261103.json": "2fc4b3865f08230be5d5739869fc547c22a7dfbcfd1702ab2109a4202a03d800"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Services/OpportunityTechnicalIncidents.php": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/lib/technical-incident-labels.ts": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a",
+ "tests/frontend/technical-incident-handling.test.mjs": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "d6f7e54712e4d15a3b1f9783c154ad8a7ca5a58372d7d703e2fa9a5a755ec751",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityResources.php": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6",
+ "app/Services/OpportunityImageProcessor.php": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a",
+ "app/Jobs/ScanDocumentForMalware.php": "7c9e3e8b55a3b635b39c1834953184dd413aacdebf5a5d7a29cd3b35a8b6055f",
+ "app/Services/Malware/DocumentScanAttempts.php": "55ea55ad4def90e6244fd64d49b3492c2afaad60788af8c7faa542cd4bfede65",
+ "app/Services/OpportunityScanDispatch.php": "cb0e80cd69d0052a4a350d1d19283e2f6a7a19511b753920dc3f0a5894d9969a",
+ "tests/Feature/ScanTechnicalIncidentsTest.php": "6eb53d7f0a0c6f02968229e10473f9a2f3f5e9b3a11ea4a6aa4d7a1f7775d153",
+ "app/Services/Malware/DocumentScanDelivery.php": "d34bef072621d88d49588e7498a9b5f4a881f438d259d868fa97dd91eef9e061",
+ "app/Services/Malware/DocumentScanRetry.php": "ddac00577280355c51c8345ec53e0805e75aacb7df0b183b9ef7a2507d5b5216",
+ "app/Http/Controllers/DocumentMalwareController.php": "0a6f88460a214185ed53b5e2edc1fd955d2360e3c5888a37c4831abab84d2fce",
+ "resources/js/pages/management/shared.tsx": "fd61a937262dc62dfb08b1122a1ed2f442109728ce1738eebc92ad0f57906e77",
+ "resources/js/pages/investment/zone-attachments.tsx": "e1e64cdea70aa668ce39056f0b1a08c349b583418c303ae205da33f5bee9662b",
+ "tests/Feature/DocumentScanRetryTest.php": "574c86d9a4a93c6226a0dcd37baa7da8cec1989f72fa72db90f8b1fa6d564d13",
+ "tests/frontend/document-scan-retry.test.mjs": "27e4df0b31622d8d0c28e37511e98579c44bf47b48d88ac6a62055f521fc7937",
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "b4a5ffd723fb00d6a3a7b376f7c99e334ff4d1c8a1a3cba5aed1e299e757dac6",
+ "resources/js/lib/investment-profile-editor.ts": "fd624ad1101e08500313a0d2eacf565ac5567f789fdc1008c1c482833763f453",
+ "resources/js/components/investment-profile-editor.tsx": "d53714731f456d10ff65b8886edaada3f79361267389c6d7ac7bcbc3fce88885",
+ "resources/js/pages/investment/profile.tsx": "15a1b90295471471f11623c4eee30d50ad0a645285ac7a1c39448ba3cade92a6",
+ "tests/Feature/InvestmentProfileCommandsTest.php": "515564e26321c449427b114ad7b009519f774f0a8443f2aa1997b6fd636971b5",
+ "tests/frontend/investment-profile-editor.test.mjs": "3fe4f8c527f15ab10c96328a16049ee7ad42c539adeb5c16b973de282d480b8d",
+ "tests/frontend/helpers/investment-profile-editor.mjs": "3f2c4ea81e3d10b5ff86079d72d5728411f25634ce8f635200517ed07eed8d2d"
+ },
+ "prior_code_deltas": {
+ "resources/js/lib/investment-profile-editor.ts": {
+ "previous": "fd624ad1101e08500313a0d2eacf565ac5567f789fdc1008c1c482833763f453",
+ "current": "54f2f450130c09533e85615a3f1a4959cb079c087ea7a306333e9097456e5f2f"
+ },
+ "resources/js/pages/investment/profile.tsx": {
+ "previous": "15a1b90295471471f11623c4eee30d50ad0a645285ac7a1c39448ba3cade92a6",
+ "current": "8bfb74247596fb0767869a8bd007e8453e959417ce218ba4d7fafbe68aa913d4"
+ },
+ "tests/frontend/helpers/investment-profile-editor.mjs": {
+ "previous": "3f2c4ea81e3d10b5ff86079d72d5728411f25634ce8f635200517ed07eed8d2d",
+ "current": "be40b797348c0488d158cade713599e1db31c0a7deaa3f8e063eea02ced3e084"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "153438bc5dd39813a55cdfae33ecb3789802e467a83404868467ba1a4a8ecf23",
+ "public/build/assets/app-BwqXO-kt.js": "e7a76d89a3d143c4533669406e40473e393460484c7245d3af0804bf2087997a",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-CSDk-OYk.js": "0e263792b1aa23267e7e3599b316dabb23db99cc132b1e0fd639f6d80065bfe1",
+ "public/build/assets/investment-territory-BTAmsxbu.js": "c34d74d9b88a3956537e3dccebbb1e72e55b1bb5253d05587e8403d00c922e10",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-CpMjXVgs.js": "cae8a225d7edeaed9857919ab35ddc5d4024fb0dbd2a37fe6a4aeb8085be83d8",
+ "public/build/assets/territory-geometry-preview-B20FuvJI.js": "70b84fbe19bfc78c37c28152c7954186414fd5db5eaede18dc85469fdbf7ebbb",
+ "public/build/assets/interactive-investment-map-Ctkdk-9k.js": "eb205a42a51016cd1e7fd8a57dd8782534f5c670dbb9673ebaf12e1073e63505",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B-FE4xRF.js": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "public/build/assets/opportunity-draft-B4uAe0VJ.js": "d594e165589268701f769d83aa266791baf7547bb12ca43361f24af114d3f3d2",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "public/build/assets/opportunity-search-filters-DJOMnDUd.js": "d873371c2a689b00c5725133f04ea652f2fd9be1e96faf0d970679d90e75405e",
+ "public/build/assets/proactive-investment-CYz0tbgM.js": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "public/build/assets/manage-BzsCf6FW.js": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "public/build/assets/zone-l3FoBiQ3.js": "7b7331f93d5824394ea13f1d95c47adf82093415db2fc3125920306febd6c9f0",
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "public/build/assets/investment-map-panel-BChaE46z.js": "22efeed920548942682fcac210f8db0d6c3917b6e01b6a6787402f67877da79a",
+ "public/build/assets/catalogue-investment-map-Lxdld7TL.js": "d655638ce24be7e624b6beb2e88397e02562eb52504136d90def2ffc4089c5ce",
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "public/build/assets/zone-attachments-yo9XOR91.js": "1476aa61eaad06532f70aef89a16d0ee49195168e4f46d1725a22e7e10e7e00f",
+ "public/build/assets/zone-map-DEudEadc.js": "e391b0963bd928f47c1ea27cb64c4c9b26a7c568ace6f4864878a1506cd1813d",
+ "public/build/assets/zone-relations-ttYEfvQE.js": "7723ce1efff48a5a812172ccf999aff407fab4fcc6677580a922636116437ec5",
+ "public/build/assets/catalogue-context-B1GeKTzL.js": "987fa08c273148f4f19985663215d1ac11142fc2cc043baf7cf06ea3d57ded9c",
+ "public/build/assets/profile-CI6GR1H6.js": "643d17a1d3a9c0c6abe166d6d757962edfa35f6951c15522ab9baca020419f6a",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/country-select-4uP5BvMf.js": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/installation-B0nI9WAi.js": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "public/build/assets/support-installation-3F6rIOG2.js": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "public/build/assets/technical-support-CpP0Ki7O.js": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "public/build/assets/technical-incident-CYL9UpWe.js": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "14235236b4f12eb567159541029429a88905fb6a89b0cdafa15a4e468592af6e",
+ "current": "153438bc5dd39813a55cdfae33ecb3789802e467a83404868467ba1a4a8ecf23",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-DJr5rmsF.js": {
+ "previous": "2bca9a6d9f9fc63a779df337477f80d35027ed9e15eec6d4bc07af8791a6bbf9",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-resources-hsjfuv9C.js": {
+ "previous": "1679ca19adb73c1a56957f0f5752f40339499ab968029cfee344a1414ac69298",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-YaiLxYkU.js": {
+ "previous": "824a8d85bde24ae122e9fa8910ab87c64d4085161dba07ae495ab961dd3b7c7e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-BvN_k0_p.js": {
+ "previous": "928ea114db19750db2f2c6c729ebb1b11e8394c5b882729b5f3e0886df45cd70",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-CGVx8_We.js": {
+ "previous": "4f8fdfacd1372ca4c8320f78e14f1da45a94d892a02d658d49dd23a4b50fe2e3",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-CTkcRNba.js": {
+ "previous": "9ceff8e2fa71f2f9cb04692444964a8bb26dc96469539b66d93caef664ccf4f7",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B-FE4xRF.js": {
+ "previous": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "current": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": {
+ "previous": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "current": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": {
+ "previous": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "current": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-CvlU8e5g.js": {
+ "previous": "a956ced4621a307a392b75e6269d4d4e05f5233ad07be08251ce7545389f30b0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": {
+ "previous": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "current": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-6s36qI7n.js": {
+ "previous": "f66b188ef9b4d000f1f1ec8275902028fc21100f68c3ca74836a5a6908215b78",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-CYz0tbgM.js": {
+ "previous": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "current": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/manage-BzsCf6FW.js": {
+ "previous": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "current": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-BscN3JR0.js": {
+ "previous": "61f05a2a43646442b20d58e8fecfe1a1cd2cc2d3928e6fe156074b5dec3dc91b",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": {
+ "previous": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "current": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-map-panel-BIMfpRze.js": {
+ "previous": "0b77d7bba43f5455b883d8e7dd228f757ebda10a3af08fcfb7fdbf87e2aba2b2",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-investment-map-BA-fR0Wn.js": {
+ "previous": "d7e1a924435c779f7025caeb909588b4c9cb6161adda24bb9d5c85cfe6777e7e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": {
+ "previous": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "current": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-attachments-CqGuadTd.js": {
+ "previous": "3b586d3e31441147aa4fc7faee8336a8edbb5f75f051929da7e0e89dd56e0480",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-map-CDhWr74x.js": {
+ "previous": "2dd9c7ac7c1931d5957c872fc8d54c81f063848f8a0500ae5e4c1905184a26ca",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-relations-BSGH6FF3.js": {
+ "previous": "1a5a9d9d077c3ec804817b7b010195f9a8653b68dd3ca4340535c117509af481",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-context-CJVNp__h.js": {
+ "previous": "5b69fda73199a8d432782c5224cef152082d45c30d277f93a1ca2de5e145061e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-B981DCv9.js": {
+ "previous": "1fea63cc90ae2729b41583bfcc39f9da0e9d20ac180de6763ebe67cba198a785",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/country-select-4uP5BvMf.js": {
+ "previous": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "current": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-B0nI9WAi.js": {
+ "previous": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "current": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-3F6rIOG2.js": {
+ "previous": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "current": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-CpP0Ki7O.js": {
+ "previous": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "current": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": {
+ "previous": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "current": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-CYL9UpWe.js": {
+ "previous": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "current": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Optional operation keys preserve legacy client semantics; unkeyed legacy writes are not claimed idempotent",
+ "Preparations remain page memory with a shared leave guard; durable navigation/reload/authentication recovery and expiry remain pending",
+ "Country reuse into private company declarations keeps its existing separate path and still needs recovery/idempotency review",
+ "Two different representatives and actual organization-row lock wait demonstrate a bounded conflicting update; exhaustive interleavings and load are not claimed",
+ "Browser/real-user acceptance, active deployment, real authorized country completion and destination backup/restore remain pending"
+ ]
+ },
+ "organization_country_reuse_increment_20261103": {
+ "recorded_at": "2026-11-03T21:19:22.338Z",
+ "requirements": [
+ "AUD-COUNTRY-02",
+ "AUD-PROFILE-25"
+ ],
+ "status": "partial_local_qa_not_installed",
+ "feature": {
+ "tool": "phpunit",
+ "result": "passed",
+ "tests": 29,
+ "passed": 29,
+ "assertions": 364,
+ "duration_ms": 142017
+ },
+ "initial_server_diagnostic": {
+ "tool": "phpunit",
+ "result": "failed",
+ "tests": 29,
+ "passed": 27,
+ "assertions": 349,
+ "duration_ms": 137883,
+ "failed": 2,
+ "failures": [
+ {
+ "test": "Tests\\Feature\\OrganizationCountryReuseCommandsTest::test_read_authority_can_reuse_once_and_replay_keeps_the_original_snapshot_and_encrypted_receipt",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php",
+ "line": 51,
+ "message": "Failed asserting that two strings are equal.\n--- Expected\n+++ Actual\n@@ @@\n '{\\n\n- \"country\": \"FR\",\\n\n- \"version\": 2\\n\n+ \"exception\": \"Symfony\\\\Component\\\\HttpKernel\\\\Exception\\\\HttpException\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Application.php\",\\n\n+ \"line\": 1447,\\n\n+ \"message\": \"Este pedido j\\u00e1 foi utilizado com outros dados. Consulte o registo guardado antes de preparar outro pedido.\",\\n\n+ \"trace\": {\\n\n+ \"0\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Application\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\helpers.php\",\\n\n+ \"function\": \"abort\",\\n\n+ \"line\": 67,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"1\": {\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\helpers.php\",\\n\n+ \"function\": \"abort\",\\n\n+ \"line\": 104\\n\n+ },\\n\n+ \"10\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Route\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Route.php\",\\n\n+ \"function\": \"runController\",\\n\n+ \"line\": 216,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"11\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Route\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Router.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 822,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"12\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Router\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"{closure:Illuminate\\\\Routing\\\\Router::runRouteWithinStack():821}\",\\n\n+ \"line\": 180,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"13\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\PrivateInvestmentResponse.php\",\\n\n+ \"function\": \"{closure:Illuminate\\\\Pipeline\\\\Pipeline::prepareDestination():178}\",\\n\n+ \"line\": 16,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"14\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\PrivateInvestmentResponse\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"15\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Auth\\\\Middleware\\\\EnsureEmailIsVerified.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 41,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"16\": {\\n\n+ \"class\": \"Illuminate\\\\Auth\\\\Middleware\\\\EnsureEmailIsVerified\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"17\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Http\\\\Middleware\\\\AddLinkHeadersForPreloadedAssets.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 32,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"18\": {\\n\n+ \"class\": \"Illuminate\\\\Http\\\\Middleware\\\\AddLinkHeadersForPreloadedAssets\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"19\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\PreserveFormFeedback.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 18,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"2\": {\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Services\\\\InvestmentProfileCommands.php\",\\n\n+ \"function\": \"abort_unless\",\\n\n+ \"line\": 29\\n\n+ },\\n\n+ \"20\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\PreserveFormFeedback\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"21\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\inertiajs\\\\inertia-laravel\\\\src\\\\Middleware.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 147,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"22\": {\\n\n+ \"class\": \"Inertia\\\\Middleware\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"23\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\HandleAppearance.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 21,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"24\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\HandleAppearance\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"25\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\ProtectProfileOpportunity.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 40,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"26\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\ProtectProfileOpportunity\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"27\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\AuditProfileDecision.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 18,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"28\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\AuditProfileDecision\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"29\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\ProtectPrivilegedIdentity.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 39,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"3\": {\\n\n+ \"class\": \"App\\\\Services\\\\InvestmentProfileCommands\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Controllers\\\\InvestmentWorkspaceController.php\",\\n\n+ \"function\": \"replay\",\\n\n+ \"line\": 133,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"30\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\ProtectPrivilegedIdentity\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"31\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\PortalProfileSession.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 42,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"32\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\PortalProfileSession\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"33\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\EnsureHomologationAccess.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 15,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"34\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\EnsureHomologationAccess\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"35\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Middleware\\\\SubstituteBindings.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 52,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"36\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Middleware\\\\SubstituteBindings\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"37\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Middleware\\\\ThrottleRequests.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 168,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"38\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Middleware\\\\ThrottleRequests\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Middleware\\\\ThrottleRequests.php\",\\n\n+ \"function\": \"handleRequest\",\\n\n+ \"line\": 93,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"39\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Middleware\\\\ThrottleRequests\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"4\": {\\n\n+ \"class\": \"App\\\\Http\\\\Controllers\\\\InvestmentWorkspaceController\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Database\\\\Concerns\\\\ManagesTransactions.php\",\\n\n+ \"function\": \"{closure:App\\\\Http\\\\Controllers\\\\InvestmentWorkspaceController::reuseOrganizationCountry():126}\",\\n\n+ \"line\": 35,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"40\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Auth\\\\Middleware\\\\Authenticate.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 63,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"41\": {\\n\n+ \"class\": \"Illuminate\\\\Auth\\\\Middleware\\\\Authenticate\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"42\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\PreventRequestForgery.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 104,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"43\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\PreventRequestForgery\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"44\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\View\\\\Middleware\\\\ShareErrorsFromSession.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 48,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"45\": {\\n\n+ \"class\": \"Illuminate\\\\View\\\\Middleware\\\\ShareErrorsFromSession\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"46\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Session\\\\Middleware\\\\StartSession.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 120,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"47\": {\\n\n+ \"class\": \"Illuminate\\\\Session\\\\Middleware\\\\StartSession\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Session\\\\Middleware\\\\StartSession.php\",\\n\n+ \"function\": \"handleStatefulRequest\",\\n\n+ \"line\": 63,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"48\": {\\n\n+ \"class\": \"Illuminate\\\\Session\\\\Middleware\\\\StartSession\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"49\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Cookie\\\\Middleware\\\\AddQueuedCookiesToResponse.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 36,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"5\": {\\n\n+ \"class\": \"Illuminate\\\\Database\\\\Connection\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Database\\\\DatabaseManager.php\",\\n\n+ \"function\": \"transaction\",\\n\n+ \"line\": 502,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"50\": {\\n\n+ \"class\": \"Illuminate\\\\Cookie\\\\Middleware\\\\AddQueuedCookiesToResponse\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"51\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Cookie\\\\Middleware\\\\EncryptCookies.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 74,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"52\": {\\n\n+ \"class\": \"Illuminate\\\\Cookie\\\\Middleware\\\\EncryptCookies\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"53\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 137,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"54\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Router.php\",\\n\n+ \"function\": \"then\",\\n\n+ \"line\": 821,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"55\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Router\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Router.php\",\\n\n+ \"function\": \"runRouteWithinStack\",\\n\n+ \"line\": 800,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"56\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Router\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Router.php\",\\n\n+ \"function\": \"runRoute\",\\n\n+ \"line\": 764,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"57\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Router\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Router.php\",\\n\n+ \"function\": \"dispatchToRoute\",\\n\n+ \"line\": 753,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"58\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\Router\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Kernel.php\",\\n\n+ \"function\": \"dispatch\",\\n\n+ \"line\": 200,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"59\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Kernel\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"{closure:Illuminate\\\\Foundation\\\\Http\\\\Kernel::dispatchToRouter():197}\",\\n\n+ \"line\": 180,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"6\": {\\n\n+ \"class\": \"Illuminate\\\\Database\\\\DatabaseManager\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Support\\\\Facades\\\\Facade.php\",\\n\n+ \"function\": \"__call\",\\n\n+ \"line\": 364,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"60\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\inertiajs\\\\inertia-laravel\\\\src\\\\Middleware\\\\EnsureGetOnRedirect.php\",\\n\n+ \"function\": \"{closure:Illuminate\\\\Pipeline\\\\Pipeline::prepareDestination():178}\",\\n\n+ \"line\": 19,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"61\": {\\n\n+ \"class\": \"Inertia\\\\Middleware\\\\EnsureGetOnRedirect\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"62\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Middleware\\\\CollectPublicSearchMetrics.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 14,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"63\": {\\n\n+ \"class\": \"App\\\\Http\\\\Middleware\\\\CollectPublicSearchMetrics\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"64\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TransformsRequest.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 21,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"65\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TransformsRequest\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\ConvertEmptyStringsToNull.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 31,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"66\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\ConvertEmptyStringsToNull\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"67\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TransformsRequest.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 21,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"68\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TransformsRequest\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TrimStrings.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 51,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"69\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\TrimStrings\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"7\": {\\n\n+ \"class\": \"Illuminate\\\\Support\\\\Facades\\\\Facade\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\app\\\\Http\\\\Controllers\\\\InvestmentWorkspaceController.php\",\\n\n+ \"function\": \"__callStatic\",\\n\n+ \"line\": 126,\\n\n+ \"type\": \"::\"\\n\n+ },\\n\n+ \"70\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Http\\\\Middleware\\\\ValidatePostSize.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 27,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"71\": {\\n\n+ \"class\": \"Illuminate\\\\Http\\\\Middleware\\\\ValidatePostSize\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"72\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\PreventRequestsDuringMaintenance.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 110,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"73\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\PreventRequestsDuringMaintenance\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"74\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Http\\\\Middleware\\\\HandleCors.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 74,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"75\": {\\n\n+ \"class\": \"Illuminate\\\\Http\\\\Middleware\\\\HandleCors\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"76\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Http\\\\Middleware\\\\TrustProxies.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 58,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"77\": {\\n\n+ \"class\": \"Illuminate\\\\Http\\\\Middleware\\\\TrustProxies\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"78\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\InvokeDeferredCallbacks.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 22,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"79\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Middleware\\\\InvokeDeferredCallbacks\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"8\": {\\n\n+ \"class\": \"App\\\\Http\\\\Controllers\\\\InvestmentWorkspaceController\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\ControllerDispatcher.php\",\\n\n+ \"function\": \"reuseOrganizationCountry\",\\n\n+ \"line\": 46,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"80\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Http\\\\Middleware\\\\ValidatePathEncoding.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 28,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"81\": {\\n\n+ \"class\": \"Illuminate\\\\Http\\\\Middleware\\\\ValidatePathEncoding\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 219,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"82\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Pipeline\\\\Pipeline.php\",\\n\n+ \"function\": \"{closure:{closure:Illuminate\\\\Pipeline\\\\Pipeline::carry():194}:195}\",\\n\n+ \"line\": 137,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"83\": {\\n\n+ \"class\": \"Illuminate\\\\Pipeline\\\\Pipeline\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Kernel.php\",\\n\n+ \"function\": \"then\",\\n\n+ \"line\": 175,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"84\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Kernel\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Http\\\\Kernel.php\",\\n\n+ \"function\": \"sendRequestThroughRouter\",\\n\n+ \"line\": 144,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"85\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Http\\\\Kernel\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Testing\\\\Concerns\\\\MakesHttpRequests.php\",\\n\n+ \"function\": \"handle\",\\n\n+ \"line\": 638,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"86\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Testing\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Testing\\\\Concerns\\\\MakesHttpRequests.php\",\\n\n+ \"function\": \"call\",\\n\n+ \"line\": 604,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"87\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Testing\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Foundation\\\\Testing\\\\Concerns\\\\MakesHttpRequests.php\",\\n\n+ \"function\": \"json\",\\n\n+ \"line\": 411,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"88\": {\\n\n+ \"class\": \"Illuminate\\\\Foundation\\\\Testing\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\tests\\\\Feature\\\\OrganizationCountryReuseCommandsTest.php\",\\n\n+ \"function\": \"postJson\",\\n\n+ \"line\": 51,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"89\": {\\n\n+ \"class\": \"Tests\\\\Feature\\\\OrganizationCountryReuseCommandsTest\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestCase.php\",\\n\n+ \"function\": \"test_read_authority_can_reuse_once_and_replay_keeps_the_original_snapshot_and_encrypted_receipt\",\\n\n+ \"line\": 1318,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"9\": {\\n\n+ \"class\": \"Illuminate\\\\Routing\\\\ControllerDispatcher\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\laravel\\\\framework\\\\src\\\\Illuminate\\\\Routing\\\\Route.php\",\\n\n+ \"function\": \"dispatch\",\\n\n+ \"line\": 276,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"90\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestCase.php\",\\n\n+ \"function\": \"invokeTestMethod\",\\n\n+ \"line\": 1355,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"91\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestCase.php\",\\n\n+ \"function\": \"runTest\",\\n\n+ \"line\": 521,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"92\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestRunner\\\\TestRunner.php\",\\n\n+ \"function\": \"runBare\",\\n\n+ \"line\": 99,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"93\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestRunner\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestCase.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 361,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"94\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestCase\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestSuite.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 374,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"95\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestSuite\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\Framework\\\\TestSuite.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 374,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"96\": {\\n\n+ \"class\": \"PHPUnit\\\\Framework\\\\TestSuite\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\TextUI\\\\TestRunner.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 64,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"97\": {\\n\n+ \"class\": \"PHPUnit\\\\TextUI\\\\TestRunner\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\src\\\\TextUI\\\\Application.php\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 229,\\n\n+ \"type\": \"->\"\\n\n+ },\\n\n+ \"98\": {\\n\n+ \"class\": \"PHPUnit\\\\TextUI\\\\Application\",\\n\n+ \"file\": \"C:\\\\laragon\\\\www\\\\portal-investidor\\\\vendor\\\\phpunit\\\\phpunit\\\\phpunit\",\\n\n+ \"function\": \"run\",\\n\n+ \"line\": 104,\\n\n+ \"type\": \"->\"\\n\n+ }\\n\n+ }\\n\n }'",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\AssertableJsonString.php:102",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php:51"
+ ]
+ },
+ {
+ "test": "Tests\\Feature\\OrganizationCountryReuseCommandsTest::test_a_receipt_failure_rolls_back_the_company_and_business_audit_together",
+ "file": "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php",
+ "line": 112,
+ "message": "Expected response status code [500] but received 503.\nFailed asserting that 503 is identical to 500.\r\n\r\nThe following exception occurred during the last request:\n\nPDOException: SQLSTATE[23514]: Check violation: 7 ERROR: new row for relation \"audit_events\" violates check constraint \"qa_reject_country_reuse_receipt\"\nDETAIL: Failing row contains (537ee9d2-8640-4992-99c6-96ebdde741d7, investment-workspace-command, null, restricted, 264f11cb-3877-405b-be87-3d3c96fc6553, 2026-11-03 21:11:15.036243+00, 7, investment-profile-command, null, command_applied, 2026-11-03 21:11:15.036243+00, null, {\"result_encrypted\": \"eyJpdiI6IjB3aTl6QXJSTGNHclNlMldRNVV5NEE9PS...). in C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:601\nStack trace:\n#0 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(601): PDOStatement->execute()\n#1 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(846): Illuminate\\Database\\Connection->{closure:Illuminate\\Database\\Connection::statement():590}('insert into \"au...', Array)\n#2 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(813): Illuminate\\Database\\Connection->runQueryCallback('insert into \"au...', Array, Object(Closure))\n#3 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(590): Illuminate\\Database\\Connection->run('insert into \"au...', Array, Object(Closure))\n#4 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(554): Illuminate\\Database\\Connection->statement('insert into \"au...', Array)\n#5 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Builder.php(4220): Illuminate\\Database\\Connection->insert('insert into \"au...', Array)\n#6 C:\\laragon\\www\\portal-investidor\\app\\Services\\InvestmentProfileCommands.php(53): Illuminate\\Database\\Query\\Builder->insert(Array)\n#7 C:\\laragon\\www\\portal-investidor\\app\\Http\\Controllers\\InvestmentWorkspaceController.php(151): App\\Services\\InvestmentProfileCommands->record(Object(App\\Models\\User), '264f11cb-3877-4...', Array, Array)\n#8 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Concerns\\ManagesTransactions.php(35): App\\Http\\Controllers\\InvestmentWorkspaceController->{closure:App\\Http\\Controllers\\InvestmentWorkspaceController::reuseOrganizationCountry():126}(Object(Illuminate\\Database\\PostgresConnection))\n#9 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\DatabaseManager.php(502): Illuminate\\Database\\Connection->transaction(Object(Closure))\n#10 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Facades\\Facade.php(364): Illuminate\\Database\\DatabaseManager->__call('transaction', Array)\n#11 C:\\laragon\\www\\portal-investidor\\app\\Http\\Controllers\\InvestmentWorkspaceController.php(126): Illuminate\\Support\\Facades\\Facade::__callStatic('transaction', Array)\n#12 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php(46): App\\Http\\Controllers\\InvestmentWorkspaceController->reuseOrganizationCountry(Object(Illuminate\\Http\\Request), '55b45cfd-9a6d-4...', Object(App\\Services\\OrganizationCountry))\n#13 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(276): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(App\\Http\\Controllers\\InvestmentWorkspaceController), 'reuseOrganizati...')\n#14 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(216): Illuminate\\Routing\\Route->runController()\n#15 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(822): Illuminate\\Routing\\Route->run()\n#16 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Routing\\Router->{closure:Illuminate\\Routing\\Router::runRouteWithinStack():821}(Object(Illuminate\\Http\\Request))\n#17 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PrivateInvestmentResponse.php(16): Illuminate\\Pipeline\\Pipeline->{closure:Illuminate\\Pipeline\\Pipeline::prepareDestination():178}(Object(Illuminate\\Http\\Request))\n#18 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PrivateInvestmentResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified.php(41): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#20 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#21 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\AddLinkHeadersForPreloadedAssets.php(32): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#22 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\AddLinkHeadersForPreloadedAssets->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#23 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PreserveFormFeedback.php(18): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#24 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PreserveFormFeedback->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#25 C:\\laragon\\www\\portal-investidor\\vendor\\inertiajs\\inertia-laravel\\src\\Middleware.php(147): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#26 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Inertia\\Middleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#27 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\HandleAppearance.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#28 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\HandleAppearance->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#29 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\ProtectProfileOpportunity.php(40): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#30 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\ProtectProfileOpportunity->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#31 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\AuditProfileDecision.php(18): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#32 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\AuditProfileDecision->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#33 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\ProtectPrivilegedIdentity.php(39): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#34 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\ProtectPrivilegedIdentity->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#35 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PortalProfileSession.php(42): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#36 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PortalProfileSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\EnsureHomologationAccess.php(15): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#38 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\EnsureHomologationAccess->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(52): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#40 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#41 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\ThrottleRequests.php(168): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#42 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\ThrottleRequests.php(93): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest(Object(Illuminate\\Http\\Request), Object(Closure), Array)\n#43 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle(Object(Illuminate\\Http\\Request), Object(Closure), '20', '1')\n#44 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\Authenticate.php(63): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#45 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Auth\\Middleware\\Authenticate->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#46 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestForgery.php(104): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#47 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestForgery->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#48 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\View\\Middleware\\ShareErrorsFromSession.php(48): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#49 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#50 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(120): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#51 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(63): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))\n#52 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#53 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse.php(36): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#54 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#55 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\EncryptCookies.php(74): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#56 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#57 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#58 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(821): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#59 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(800): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#60 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(764): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#61 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(753): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#62 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(200): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))\n#63 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Kernel->{closure:Illuminate\\Foundation\\Http\\Kernel::dispatchToRouter():197}(Object(Illuminate\\Http\\Request))\n#64 C:\\laragon\\www\\portal-investidor\\vendor\\inertiajs\\inertia-laravel\\src\\Middleware\\EnsureGetOnRedirect.php(19): Illuminate\\Pipeline\\Pipeline->{closure:Illuminate\\Pipeline\\Pipeline::prepareDestination():178}(Object(Illuminate\\Http\\Request))\n#65 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Inertia\\Middleware\\EnsureGetOnRedirect->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#66 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\CollectPublicSearchMetrics.php(14): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#67 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\CollectPublicSearchMetrics->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#68 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#69 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#70 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#71 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#72 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php(51): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#73 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#74 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#75 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#76 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php(110): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#77 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#78 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php(74): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#79 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#80 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php(58): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#81 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#82 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks.php(22): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#83 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#84 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\ValidatePathEncoding.php(28): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#85 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePathEncoding->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#86 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#87 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#88 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#89 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(638): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#90 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(604): Illuminate\\Foundation\\Testing\\TestCase->call('POST', '/api/v1/investm...', Array, Array, Array, Array, '{\"version\":1,\"o...')\n#91 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(411): Illuminate\\Foundation\\Testing\\TestCase->json('POST', '/api/v1/investm...', Array, Array, 0)\n#92 C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php(112): Illuminate\\Foundation\\Testing\\TestCase->postJson('/api/v1/investm...', Array)\n#93 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(1318): Tests\\Feature\\OrganizationCountryReuseCommandsTest->test_a_receipt_failure_rolls_back_the_company_and_business_audit_together()\n#94 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(1355): PHPUnit\\Framework\\TestCase->invokeTestMethod('test_a_receipt_...', Array)\n#95 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(521): PHPUnit\\Framework\\TestCase->runTest()\n#96 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestRunner\\TestRunner.php(99): PHPUnit\\Framework\\TestCase->runBare()\n#97 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(361): PHPUnit\\Framework\\TestRunner->run(Object(Tests\\Feature\\OrganizationCountryReuseCommandsTest))\n#98 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestSuite.php(374): PHPUnit\\Framework\\TestCase->run()\n#99 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestSuite.php(374): PHPUnit\\Framework\\TestSuite->run()\n#100 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\TextUI\\TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run()\n#101 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\TextUI\\Application.php(229): PHPUnit\\TextUI\\TestRunner->run(Object(PHPUnit\\TextUI\\Configuration\\Configuration), Object(PHPUnit\\Runner\\ResultCache\\DefaultResultCache), Object(PHPUnit\\Framework\\TestSuite))\n#102 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\phpunit(104): PHPUnit\\TextUI\\Application->run(Array)\n#103 {main}\n\nNext Illuminate\\Database\\QueryException: SQLSTATE[23514]: Check violation: 7 ERROR: new row for relation \"audit_events\" violates check constraint \"qa_reject_country_reuse_receipt\"\nDETAIL: Failing row contains (537ee9d2-8640-4992-99c6-96ebdde741d7, investment-workspace-command, null, restricted, 264f11cb-3877-405b-be87-3d3c96fc6553, 2026-11-03 21:11:15.036243+00, 7, investment-profile-command, null, command_applied, 2026-11-03 21:11:15.036243+00, null, {\"result_encrypted\": \"eyJpdiI6IjB3aTl6QXJSTGNHclNlMldRNVV5NEE9PS...). (Connection: pgsql, Host: 127.0.0.1, Port: 55441, Database: scan_incidents_20261103_test, SQL: insert into \"audit_events\" (\"id\", \"source_system\", \"actor_user_id\", \"entity_type\", \"entity_id\", \"action\", \"correlation_id\", \"data_classification\", \"after_data\") values (537ee9d2-8640-4992-99c6-96ebdde741d7, investment-workspace-command, 7, investment-profile-command, ?, command_applied, 264f11cb-3877-405b-be87-3d3c96fc6553, restricted, {\"command_encrypted\":\"eyJpdiI6IkZrelVOYjArRjcyL1B4UFBCbHIzUUE9PSIsInZhbHVlIjoiTTVJcjc1QXhmR3JCUk1XVE44OUkzRG4zTkhudWNsQlJXNFlJbEU4WXBod0xmTkJKUHVMSTZUYU01TFVLOGVKU2g5dzBYejBRS2pUWXBsd1dXWFFDS01OcnpTTnoyQVJPYS82VEk1QXo4eXgwblJTMWFDUnhPTHZCdURPbTA0dmtKNjNYUTNiTnlYQ2swMlJtaVlqSlAxRnk3SHZVaFhibjNiTlhyeXRHWUk2WVBsNGYzMkFXTmNLU0JsVWJHZHZ3ODc2NmVVc0Z1Vml4T2FVSkRqRFZIdC8vK1k2QWRIREpSV2ZLb1FCSGh2YkozVzYxUy9hL29nOXNEM3l2azlZWlBETlJmdGkyRUttWU54ZnJHNStVOVE9PSIsIm1hYyI6IjY4ZjFiNjAyY2NkNWI2NjQyNzA1OWNhNDNkMmZjNzE5YjgzMWYyZDQyNzU4MmQ4ZjFkZDFmMDFjYWQ3NWNlOWUiLCJ0YWciOiIifQ==\",\"result_encrypted\":\"eyJpdiI6IjB3aTl6QXJSTGNHclNlMldRNVV5NEE9PSIsInZhbHVlIjoiTFREMG1TL3l0S1dFS0ZYeDJPSHpybmRIbG1kNkQ5eGdDSG1FTmJZQmxkQT0iLCJtYWMiOiIyODA1MTE3NmQ3ZjM1ZDExODNkMmI3MDhiYzVmYmNiNTkzNDc1NDhlZDI2ZDFlZTllNDU5OGI5NmJkZjJmZjRlIiwidGFnIjoiIn0=\"})) in C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:857\nStack trace:\n#0 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(813): Illuminate\\Database\\Connection->runQueryCallback('insert into \"au...', Array, Object(Closure))\n#1 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(590): Illuminate\\Database\\Connection->run('insert into \"au...', Array, Object(Closure))\n#2 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php(554): Illuminate\\Database\\Connection->statement('insert into \"au...', Array)\n#3 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Builder.php(4220): Illuminate\\Database\\Connection->insert('insert into \"au...', Array)\n#4 C:\\laragon\\www\\portal-investidor\\app\\Services\\InvestmentProfileCommands.php(53): Illuminate\\Database\\Query\\Builder->insert(Array)\n#5 C:\\laragon\\www\\portal-investidor\\app\\Http\\Controllers\\InvestmentWorkspaceController.php(151): App\\Services\\InvestmentProfileCommands->record(Object(App\\Models\\User), '264f11cb-3877-4...', Array, Array)\n#6 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Concerns\\ManagesTransactions.php(35): App\\Http\\Controllers\\InvestmentWorkspaceController->{closure:App\\Http\\Controllers\\InvestmentWorkspaceController::reuseOrganizationCountry():126}(Object(Illuminate\\Database\\PostgresConnection))\n#7 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\DatabaseManager.php(502): Illuminate\\Database\\Connection->transaction(Object(Closure))\n#8 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Facades\\Facade.php(364): Illuminate\\Database\\DatabaseManager->__call('transaction', Array)\n#9 C:\\laragon\\www\\portal-investidor\\app\\Http\\Controllers\\InvestmentWorkspaceController.php(126): Illuminate\\Support\\Facades\\Facade::__callStatic('transaction', Array)\n#10 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php(46): App\\Http\\Controllers\\InvestmentWorkspaceController->reuseOrganizationCountry(Object(Illuminate\\Http\\Request), '55b45cfd-9a6d-4...', Object(App\\Services\\OrganizationCountry))\n#11 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(276): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(App\\Http\\Controllers\\InvestmentWorkspaceController), 'reuseOrganizati...')\n#12 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(216): Illuminate\\Routing\\Route->runController()\n#13 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(822): Illuminate\\Routing\\Route->run()\n#14 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Routing\\Router->{closure:Illuminate\\Routing\\Router::runRouteWithinStack():821}(Object(Illuminate\\Http\\Request))\n#15 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PrivateInvestmentResponse.php(16): Illuminate\\Pipeline\\Pipeline->{closure:Illuminate\\Pipeline\\Pipeline::prepareDestination():178}(Object(Illuminate\\Http\\Request))\n#16 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PrivateInvestmentResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#17 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified.php(41): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#18 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#19 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\AddLinkHeadersForPreloadedAssets.php(32): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#20 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\AddLinkHeadersForPreloadedAssets->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#21 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PreserveFormFeedback.php(18): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#22 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PreserveFormFeedback->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#23 C:\\laragon\\www\\portal-investidor\\vendor\\inertiajs\\inertia-laravel\\src\\Middleware.php(147): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#24 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Inertia\\Middleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#25 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\HandleAppearance.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#26 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\HandleAppearance->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#27 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\ProtectProfileOpportunity.php(40): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#28 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\ProtectProfileOpportunity->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#29 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\AuditProfileDecision.php(18): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#30 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\AuditProfileDecision->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#31 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\ProtectPrivilegedIdentity.php(39): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#32 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\ProtectPrivilegedIdentity->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#33 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\PortalProfileSession.php(42): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#34 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\PortalProfileSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#35 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\EnsureHomologationAccess.php(15): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#36 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\EnsureHomologationAccess->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#37 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(52): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#38 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#39 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\ThrottleRequests.php(168): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#40 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\ThrottleRequests.php(93): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest(Object(Illuminate\\Http\\Request), Object(Closure), Array)\n#41 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle(Object(Illuminate\\Http\\Request), Object(Closure), '20', '1')\n#42 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\Authenticate.php(63): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#43 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Auth\\Middleware\\Authenticate->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#44 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestForgery.php(104): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#45 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestForgery->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#46 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\View\\Middleware\\ShareErrorsFromSession.php(48): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#47 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#48 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(120): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#49 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(63): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))\n#50 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#51 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse.php(36): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#52 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#53 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\EncryptCookies.php(74): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#54 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#55 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#56 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(821): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#57 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(800): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))\n#58 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(764): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))\n#59 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(753): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))\n#60 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(200): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))\n#61 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Kernel->{closure:Illuminate\\Foundation\\Http\\Kernel::dispatchToRouter():197}(Object(Illuminate\\Http\\Request))\n#62 C:\\laragon\\www\\portal-investidor\\vendor\\inertiajs\\inertia-laravel\\src\\Middleware\\EnsureGetOnRedirect.php(19): Illuminate\\Pipeline\\Pipeline->{closure:Illuminate\\Pipeline\\Pipeline::prepareDestination():178}(Object(Illuminate\\Http\\Request))\n#63 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Inertia\\Middleware\\EnsureGetOnRedirect->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#64 C:\\laragon\\www\\portal-investidor\\app\\Http\\Middleware\\CollectPublicSearchMetrics.php(14): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#65 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): App\\Http\\Middleware\\CollectPublicSearchMetrics->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#66 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#67 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#68 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#69 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#70 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php(51): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#71 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#72 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#73 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#74 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php(110): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#75 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#76 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php(74): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#77 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#78 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php(58): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#79 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#80 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks.php(22): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#81 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#82 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\ValidatePathEncoding.php(28): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#83 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePathEncoding->handle(Object(Illuminate\\Http\\Request), Object(Closure))\n#84 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->{closure:{closure:Illuminate\\Pipeline\\Pipeline::carry():194}:195}(Object(Illuminate\\Http\\Request))\n#85 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))\n#86 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))\n#87 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(638): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))\n#88 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(604): Illuminate\\Foundation\\Testing\\TestCase->call('POST', '/api/v1/investm...', Array, Array, Array, Array, '{\"version\":1,\"o...')\n#89 C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(411): Illuminate\\Foundation\\Testing\\TestCase->json('POST', '/api/v1/investm...', Array, Array, 0)\n#90 C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php(112): Illuminate\\Foundation\\Testing\\TestCase->postJson('/api/v1/investm...', Array)\n#91 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(1318): Tests\\Feature\\OrganizationCountryReuseCommandsTest->test_a_receipt_failure_rolls_back_the_company_and_business_audit_together()\n#92 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(1355): PHPUnit\\Framework\\TestCase->invokeTestMethod('test_a_receipt_...', Array)\n#93 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(521): PHPUnit\\Framework\\TestCase->runTest()\n#94 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestRunner\\TestRunner.php(99): PHPUnit\\Framework\\TestCase->runBare()\n#95 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestCase.php(361): PHPUnit\\Framework\\TestRunner->run(Object(Tests\\Feature\\OrganizationCountryReuseCommandsTest))\n#96 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestSuite.php(374): PHPUnit\\Framework\\TestCase->run()\n#97 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\Framework\\TestSuite.php(374): PHPUnit\\Framework\\TestSuite->run()\n#98 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\TextUI\\TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run()\n#99 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\src\\TextUI\\Application.php(229): PHPUnit\\TextUI\\TestRunner->run(Object(PHPUnit\\TextUI\\Configuration\\Configuration), Object(PHPUnit\\Runner\\ResultCache\\DefaultResultCache), Object(PHPUnit\\Framework\\TestSuite))\n#100 C:\\laragon\\www\\portal-investidor\\vendor\\phpunit\\phpunit\\phpunit(104): PHPUnit\\TextUI\\Application->run(Array)\n#101 {main}\n\n----------------------------------------------------------------------------------\n\nSQLSTATE[23514]: Check violation: 7 ERROR: new row for relation \"audit_events\" violates check constraint \"qa_reject_country_reuse_receipt\"\nDETAIL: Failing row contains (537ee9d2-8640-4992-99c6-96ebdde741d7, investment-workspace-command, null, restricted, 264f11cb-3877-405b-be87-3d3c96fc6553, 2026-11-03 21:11:15.036243+00, 7, investment-profile-command, null, command_applied, 2026-11-03 21:11:15.036243+00, null, {\"result_encrypted\": \"eyJpdiI6IjB3aTl6QXJSTGNHclNlMldRNVV5NEE9PS...). (Connection: pgsql, Host: 127.0.0.1, Port: 55441, Database: scan_incidents_20261103_test, SQL: insert into \"audit_events\" (\"id\", \"source_system\", \"actor_user_id\", \"entity_type\", \"entity_id\", \"action\", \"correlation_id\", \"data_classification\", \"after_data\") values (537ee9d2-8640-4992-99c6-96ebdde741d7, investment-workspace-command, 7, investment-profile-command, ?, command_applied, 264f11cb-3877-405b-be87-3d3c96fc6553, restricted, {\"command_encrypted\":\"eyJpdiI6IkZrelVOYjArRjcyL1B4UFBCbHIzUUE9PSIsInZhbHVlIjoiTTVJcjc1QXhmR3JCUk1XVE44OUkzRG4zTkhudWNsQlJXNFlJbEU4WXBod0xmTkJKUHVMSTZUYU01TFVLOGVKU2g5dzBYejBRS2pUWXBsd1dXWFFDS01OcnpTTnoyQVJPYS82VEk1QXo4eXgwblJTMWFDUnhPTHZCdURPbTA0dmtKNjNYUTNiTnlYQ2swMlJtaVlqSlAxRnk3SHZVaFhibjNiTlhyeXRHWUk2WVBsNGYzMkFXTmNLU0JsVWJHZHZ3ODc2NmVVc0Z1Vml4T2FVSkRqRFZIdC8vK1k2QWRIREpSV2ZLb1FCSGh2YkozVzYxUy9hL29nOXNEM3l2azlZWlBETlJmdGkyRUttWU54ZnJHNStVOVE9PSIsIm1hYyI6IjY4ZjFiNjAyY2NkNWI2NjQyNzA1OWNhNDNkMmZjNzE5YjgzMWYyZDQyNzU4MmQ4ZjFkZDFmMDFjYWQ3NWNlOWUiLCJ0YWciOiIifQ==\",\"result_encrypted\":\"eyJpdiI6IjB3aTl6QXJSTGNHclNlMldRNVV5NEE9PSIsInZhbHVlIjoiTFREMG1TL3l0S1dFS0ZYeDJPSHpybmRIbG1kNkQ5eGdDSG1FTmJZQmxkQT0iLCJtYWMiOiIyODA1MTE3NmQ3ZjM1ZDExODNkMmI3MDhiYzVmYmNiNTkzNDc1NDhlZDI2ZDFlZTllNDU5OGI5NmJkZjJmZjRlIiwidGFnIjoiIn0=\"}))",
+ "trace": [
+ "C:\\laragon\\www\\portal-investidor\\vendor\\laravel\\framework\\src\\Illuminate\\Testing\\TestResponseAssert.php:46",
+ "C:\\laragon\\www\\portal-investidor\\tests\\Feature\\OrganizationCountryReuseCommandsTest.php:112"
+ ]
+ }
+ ]
+ },
+ "new_feature_cases": 6,
+ "frontend_focused_tests": 79,
+ "new_frontend_cases": 10,
+ "frontend_baseline": {
+ "tests": 1545,
+ "current_full_suite_executed": false,
+ "overlapping_incident_cases": 69
+ },
+ "qa": {
+ "result": "passed",
+ "temporary_receipt_constraint_present": false,
+ "membership_unique_index_present": true,
+ "database": "scan_incidents_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test",
+ "counts": {
+ "investment_accounts": 0,
+ "investment_submissions": 0,
+ "investment_submission_zones": 0,
+ "investment_submission_revisions": 0,
+ "investment_submission_attachments": 0,
+ "investment_specific_needs": 0,
+ "investment_messages": 0,
+ "investment_notifications": 0,
+ "investment_reference_options": 0,
+ "investment_submission_events": 0,
+ "users": 0,
+ "organizations": 0,
+ "investment_company_declarations": 0,
+ "desk_service_versions": 0,
+ "desk_cases": 0,
+ "desk_requests": 0,
+ "desk_revisions": 0,
+ "desk_events": 0,
+ "audit_events": 0,
+ "desk_request_checkpoints": 0,
+ "documents": 0,
+ "document_malware_scans": 0,
+ "jobs": 0,
+ "failed_jobs": 0,
+ "cache": 0,
+ "cache_locks": 0,
+ "desk_documents": 0,
+ "desk_notifications": 0,
+ "product_search_counts": 0,
+ "product_experiments": 0,
+ "product_experiment_revisions": 0,
+ "desk_payments": 0,
+ "desk_messages": 0,
+ "tasks": 0,
+ "leads": 0,
+ "investors": 0,
+ "contacts": 0,
+ "investor_contacts": 0,
+ "interest_requests": 0,
+ "portal_role_assignments": 0,
+ "portal_superuser_pair": 0,
+ "portal_profile_requests": 0,
+ "portal_security_approvals": 0,
+ "opportunities": 0,
+ "ai_runs": 0,
+ "ai_sources": 0,
+ "ai_feedback": 0,
+ "portal_partnerships": 0,
+ "partnership_documents": 0,
+ "partnership_events": 0,
+ "partnership_interests": 0,
+ "partnership_locations": 0,
+ "partnership_messages": 0,
+ "partnership_milestones": 0,
+ "partnership_notifications": 0,
+ "partnership_origins": 0,
+ "partnership_rooms": 0,
+ "sectors": 0,
+ "memberships": 0,
+ "projects": 0,
+ "investment_dossiers": 0,
+ "geo_locations": 0,
+ "project_locations": 0,
+ "crm_task_preparations": 0,
+ "skills": 0,
+ "occupations": 0,
+ "training_providers": 0,
+ "courses": 0,
+ "labour_demands": 0,
+ "training_capacities": 0,
+ "education_declaration_drafts": 0,
+ "education_investment_proposals": 0,
+ "opportunity_location_drafts": 0,
+ "opportunity_documents": 0,
+ "opportunity_images": 0,
+ "opportunity_locations": 0,
+ "reference_catalog_versions": 0,
+ "economic_activities": 0,
+ "authorities": 0
+ },
+ "row_visibility": [
+ {
+ "table": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "table": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "test_process_lock_acquired": true,
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0
+ },
+ "concurrency": {
+ "result": "passed",
+ "identity": {
+ "database": "organization_country_reuse_20261103_test",
+ "port": 55441,
+ "role": "investmoz_test"
+ },
+ "synthetic_only": true,
+ "holder": {
+ "result": "applied",
+ "mode": "holder",
+ "pid": 12544,
+ "response": {
+ "version": 2,
+ "country": "FR"
+ },
+ "database_lock_wait_observed": true,
+ "response_no_store": true,
+ "active_writes": 0
+ },
+ "waiter": {
+ "result": "applied",
+ "mode": "waiter",
+ "pid": 1808,
+ "response": {
+ "version": 2,
+ "country": "FR"
+ },
+ "database_lock_wait_observed": false,
+ "response_no_store": true,
+ "active_writes": 0
+ },
+ "table_count": 190,
+ "changed_tables": [
+ "audit_events",
+ "investment_company_declarations"
+ ],
+ "declarations": 1,
+ "version": 2,
+ "country": "FR",
+ "business_audits": 1,
+ "command_receipts": 1,
+ "payload_encrypted": true,
+ "result_encrypted": true,
+ "snapshot_preserved": true,
+ "code_sha256": {
+ "app/Services/InvestmentProfileCommands.php": "618575ebbd92a091b5b698879524909b997bf2dc036209733593fc96a2139bcd",
+ "app/Services/OrganizationCountry.php": "a703b8b5db5229ee1d2dacd3355c5a8613d0a37f15175d11b4104c9a6652b250",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "5467100057507b1eacb0480c5e415371f6d921229e2974fcab1d8d3270e8124f",
+ "resources/js/lib/investment-profile-editor.ts": "eec551780b8ac4a75253c6144fe206d3dcc776381209b4b412562e0d16317143",
+ "resources/js/lib/organization-country-reuse.ts": "98079db249205140f46a8907e9a37c446702ac576a09aace675812306dd68f53",
+ "resources/js/components/investment-profile-editor.tsx": "33289a039394cf238880225acd4f0d3dedec966eef535bb96987f3296b238495",
+ "resources/js/components/organization-country-reuse.tsx": "29be110a930696eb76e580629964a102ca1f4f7b5f3ad5962fb30ae137d251ea",
+ "resources/js/pages/investment/profile.tsx": "fc10d0c4f73c3eb9a0a144f4b5e078eb43324b9b49e96401314c2c3378496d09"
+ },
+ "baseline": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "6d0b189aec078007346fcca2f8bf7a9a386acbed9cfc701019c27c87d6c0e08a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 1,
+ "sha256": "f48b823c5d9022ed88e92182869f7709ef0d63e33a1ca6b9212f1971b3ab4a50"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 1,
+ "sha256": "4c409aaf18d6a812133a967c71a0740b2587f791d5687554bf1f7479a971e91c"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "e24dc98505bea731908874c30919822ac3d255cad10408dc5ee6d541d4eaef81"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5cba8ec83adcc9661e65308aaeb52a4bf9bc67573e76c5b3ec429f20deca3e97"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "5147996a185cd2c1d14ee4926daa50b8ac878040777a0f6edaacb85b073cdf16"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "after": {
+ "activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "aftercare_plans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_chunks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_controls": {
+ "count": 7,
+ "sha256": "6d0b189aec078007346fcca2f8bf7a9a386acbed9cfc701019c27c87d6c0e08a"
+ },
+ "ai_feedback": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "ai_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "anchor_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "audit_events": {
+ "count": 2,
+ "sha256": "b8399e5c3300e4b720cb22aea8aaf155f636c97dc2af27ce08d1c93f0fa2cc1d"
+ },
+ "authorities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "business_workflow_transitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cache_locks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "cluster_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "complementary_project_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "consents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "constraints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "corridor_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "courses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "crm_task_preparations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_institutional_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_payments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_request_checkpoints": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "desk_service_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "development_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "document_malware_scans": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_activities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "economic_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_declaration_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_investment_proposals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "education_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "escalations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_document_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_mandates": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_objects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_reviews": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_business_rights": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "existing_businesses": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "external_record_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "failed_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programme_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "funding_programmes": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_names": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_territory_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "geo_write_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "inbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "interest_submission_receipts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_company_declarations": {
+ "count": 1,
+ "sha256": "a8b99eb7371368b85bfb83410b50c163d8f4b309149a603d2c61da575f53587d"
+ },
+ "investment_dossiers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_funding_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_gaps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_item_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_items": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_legal_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_reference_options": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_specific_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submission_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_tender_alert_seen": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachment_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_attachments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_geometries": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_relations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zone_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investment_zones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_accounts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_contacts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_journeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investor_navigation_preferences": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "investors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "job_batches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "journey_steps": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "labour_demands": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_cases": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "land_assistance_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "leads": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "memberships": {
+ "count": 1,
+ "sha256": "4c409aaf18d6a812133a967c71a0740b2587f791d5687554bf1f7479a971e91c"
+ },
+ "migrations": {
+ "count": 105,
+ "sha256": "596e369486bfdedd74078e30db66a171baa739a43770f6ae8e1642717ba945f3"
+ },
+ "occupations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_clusters": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_corridors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_facets": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_favourites": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_images": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_location_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_profiles": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "opportunity_projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "organizations": {
+ "count": 1,
+ "sha256": "e24dc98505bea731908874c30919822ac3d255cad10408dc5ee6d541d4eaef81"
+ },
+ "outbox_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_interests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_messages": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_milestones": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_notifications": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_origins": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "partnership_rooms": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "passkeys": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "password_reset_tokens": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_partnerships": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_profile_requests": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resource_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_resources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_role_assignments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_security_approvals": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_superuser_pair": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tender_watches": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "portal_tenders": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_observations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "proactive_supply_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiment_revisions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_experiments": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_counts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "product_search_definitions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_documents": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "project_locations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "projects": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "questionnaire_versions": {
+ "count": 2,
+ "sha256": "5cba8ec83adcc9661e65308aaeb52a4bf9bc67573e76c5b3ec429f20deca3e97"
+ },
+ "reconciliation_issues": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "reference_catalog_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sectors": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sessions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_audit_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_draft_business_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_form_drafts": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_idempotency": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_jobs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_obligations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_reports": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_result_sources": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_results": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_scenarios": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_events": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulation_tax_rule_versions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "simulations": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "skills": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "spatial_ref_sys": {
+ "count": 8500,
+ "sha256": "2bb4adb27d115545b9293dfee0e259ddb19e8d93762511ee018a06a3c4850824"
+ },
+ "submissions": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "sync_runs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "tasks": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_capacities": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_needs": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "training_providers": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "users": {
+ "count": 1,
+ "sha256": "5147996a185cd2c1d14ee4926daa50b8ac878040777a0f6edaacb85b073cdf16"
+ },
+ "value_chain_links": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ },
+ "value_chains": {
+ "count": 0,
+ "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }
+ },
+ "row_visibility": [
+ {
+ "name": "activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "aftercare_plans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_chunks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_controls",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_feedback",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "ai_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "anchor_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "audit_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "authorities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "business_workflow_transitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cache_locks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "cluster_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "complementary_project_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "consents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "constraints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "corridor_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "courses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "crm_task_preparations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_institutional_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_payments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_request_checkpoints",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "desk_service_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "development_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "document_malware_scans",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_activities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "economic_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_declaration_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_investment_proposals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "education_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "escalations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_document_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_mandates",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_objects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_reviews",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_business_rights",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "existing_businesses",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "external_record_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "failed_jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programme_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "funding_programmes",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_names",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_territory_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "geo_write_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "inbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "interest_submission_receipts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_company_declarations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_dossiers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_funding_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_gaps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_item_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_items",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_legal_sources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_reference_options",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_specific_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submission_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_tender_alert_seen",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachment_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_attachments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_geometries",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_relations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zone_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investment_zones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_accounts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_contacts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_journeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investor_navigation_preferences",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "investors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "job_batches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "jobs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "journey_steps",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "labour_demands",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_cases",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "land_assistance_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "leads",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "memberships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "migrations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "occupations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_clusters",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_corridors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_facets",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_favourites",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_images",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_location_drafts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_profiles",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "opportunity_projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "organizations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "outbox_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_events",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_interests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_messages",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_milestones",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_notifications",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_origins",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "partnership_rooms",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "passkeys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "password_reset_tokens",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_partnerships",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_profile_requests",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resource_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_resources",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_role_assignments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_security_approvals",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_superuser_pair",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tender_watches",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "portal_tenders",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_observations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "proactive_supply_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiment_revisions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_experiments",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_counts",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "product_search_definitions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_documents",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "project_locations",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "projects",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "questionnaire_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reconciliation_issues",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "reference_catalog_versions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sectors",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sessions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_audit_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_draft_business_links",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_form_drafts",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_idempotency",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_jobs",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_obligations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_reports",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_result_sources",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_results",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_scenarios",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_events",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulation_tax_rule_versions",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "simulations",
+ "rls": true,
+ "force_rls": true,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "skills",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "spatial_ref_sys",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "submissions",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "sync_runs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "tasks",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_capacities",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_needs",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "training_providers",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "users",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chain_links",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ },
+ {
+ "name": "value_chains",
+ "rls": false,
+ "force_rls": false,
+ "owner": "investmoz_test"
+ }
+ ],
+ "snapshot_role": {
+ "rolsuper": true,
+ "rolbypassrls": true
+ },
+ "active_writes": 0,
+ "active_migrations": 0,
+ "external_messages": 0,
+ "scope": "Two separate PHP controller commands, real PostgreSQL user-row lock wait and replay of the same authorized viewer country-reuse command; one target revision, first ciphertext and snapshot preserved. HTTP middleware is separately covered by Feature tests; no active installation or real-user acceptance."
+ },
+ "checks": {
+ "phpstan": "passed_three_application_sources_level_7_without_suppression",
+ "pint": "passed_four_php_sources_test",
+ "types": "passed",
+ "check": "seven_sources_format_and_lint_passed",
+ "build": "passed_with_existing_advisories"
+ },
+ "source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/Relatorios/novos/segmentar processos v1.docx",
+ "sha256": "bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5",
+ "paragraphs": [
+ 481,
+ 161,
+ 565
+ ]
+ },
+ "profile_source": {
+ "path": "C:/Mac/Home/Documents/TEMPO/Portal Tempo/Servicos Tempo/prompt/novos/Gestao de perfis investeMOZ v1.docx",
+ "sha256": "f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38"
+ },
+ "instructions_sha256": "eff8379b9a1e7ac0d2162af0d6d94010a24740d65b430ade479ae0b1cda6f8a2",
+ "code_sha256": {
+ "app/Services/OrganizationCountry.php": "a703b8b5db5229ee1d2dacd3355c5a8613d0a37f15175d11b4104c9a6652b250",
+ "app/Services/InvestmentProfileCommands.php": "618575ebbd92a091b5b698879524909b997bf2dc036209733593fc96a2139bcd",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "5467100057507b1eacb0480c5e415371f6d921229e2974fcab1d8d3270e8124f",
+ "resources/js/lib/investment-profile-editor.ts": "eec551780b8ac4a75253c6144fe206d3dcc776381209b4b412562e0d16317143",
+ "resources/js/lib/organization-country-reuse.ts": "98079db249205140f46a8907e9a37c446702ac576a09aace675812306dd68f53",
+ "resources/js/components/investment-profile-editor.tsx": "33289a039394cf238880225acd4f0d3dedec966eef535bb96987f3296b238495",
+ "resources/js/components/organization-country-reuse.tsx": "29be110a930696eb76e580629964a102ca1f4f7b5f3ad5962fb30ae137d251ea",
+ "resources/js/pages/investment/profile.tsx": "fc10d0c4f73c3eb9a0a144f4b5e078eb43324b9b49e96401314c2c3378496d09",
+ "tests/Feature/OrganizationCountryReuseCommandsTest.php": "984d9145a6813e7020766a00a605d1901c36e3cb0d609a8592fd67dddfa0652b",
+ "tests/frontend/organization-country-reuse.test.mjs": "cc0906f3440ff1a4dc747bb91143f4bc526b19349823f780f74cf1fb50209f9f",
+ "tests/frontend/helpers/investment-profile-editor.mjs": "5fbb8132c85aeb6b880a4dcaa58d12c815b38b0037ef137def92f428fd646bab"
+ },
+ "tooling_sha256": {
+ "storage/app/private/run-scan-incidents-20261103.php": "a5febcdfc89e57e8eb45d14d3416e2eae308d9e2684e9fa8877d222c4dce204e",
+ "storage/app/private/check-organization-country-reuse-qa-20261103.php": "b76e08f2c6bff7347c5251eda0319bc772e1f637682202f757d377d533efda69",
+ "storage/app/private/verify-organization-country-reuse-concurrency-20261103.php": "fd3a3b7b4cadde9d7b17df7afb2dccf9a2e173ce58697e4452a34622fdda813b",
+ "storage/app/private/record-organization-country-reuse-20261103.cjs": "ca601cdc81b985dbc6103bb38c354e86065827a860c6861d3f1d88c919e6c758"
+ },
+ "prior_tooling_supplement": {
+ "receipt": "organization_country_editor_increment_20261103",
+ "reason": "The prior tooling path array retained older workspace-helper names. Preserve the prior receipt exactly and supplement hashes of the retained executors actually used; original code hashes, logs and concurrency observations remain unchanged."
+ },
+ "prior_tooling_supplement_sha256": {
+ "storage/app/private/check-organization-country-editor-qa-20261103.php": "13f0a9b09549acf5639c298cafd5141170b77c5770ea93329c0aa49a328f0690",
+ "storage/app/private/verify-organization-country-editor-concurrency-20261103.php": "27618c9617af399e7867308c2cba397b3756970887fcae10e2b714f7a2800efd",
+ "storage/app/private/record-organization-country-editor-20261103.cjs": "4cbafcc69bcd266a266d9f83167670573d92ae3e1c8aaaeaa33319e62f095685"
+ },
+ "logs_sha256": {
+ "organization-country-reuse-feature-initial-20261103.log": "973c71beaef106a5fd828fa52399367b8a01ad60cd45438bf5dfab553e65c827",
+ "organization-country-reuse-feature-final-20261103.log": "11bacedbe3bd688cdf2967885becc8d9ccb8817c170ffa75850e4c876cde06bc",
+ "organization-country-reuse-frontend-initial-20261103.log": "8927436bd72d1ee79fb07b75cd2df6c7ab959025874ea813060a2645ca1ecbf0",
+ "organization-country-reuse-frontend-final-20261103.log": "7ef1a32a8d3040b0a87fb7a18f19b2ec4929c64c180e5228764cfa12798dea35",
+ "organization-country-reuse-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "organization-country-reuse-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "organization-country-reuse-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "organization-country-reuse-check-final-20261103.log": "ec0e5360d6db3629f25fd1757257e9a51b0dd832dec881e05ad9fa4ef3e5a688",
+ "organization-country-reuse-build-final-20261103.log": "0d6841963755b018a4d4fe24ae4673141c09350aafc23c1e00e31e51be0d49e5",
+ "organization-country-reuse-concurrency-init-20261103.log": "858509f30fbc492f00bd7773e1dd10d5d1a68b7c9286217c944107183665d7c9",
+ "organization-country-reuse-concurrency-holder-20261103.log": "143d86cf976f58d886c6c4e3051905d3f66ea51c53ad700ecfab722e649bcc64",
+ "organization-country-reuse-concurrency-waiter-20261103.log": "14201037c1456dd1c1e7921e8cf6cdf2a71d98dc6864b98f842cc27240fbc3e6",
+ "organization-country-reuse-concurrency-verified-20261103.log": "b76118de1d3295acb8a0ebad63d4b46c07dcb0e49d4d96f701a62b14cfd24a05",
+ "organization-country-reuse-concurrency-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "organization-country-reuse-qa-accepted-20261103.json": "f0ac6ebb902c735414feea76ec8813f9b5ba337e44f15de834bd8f2205b90522",
+ "organization-country-reuse-concurrency-proof-20261103.json": "3a223a47c14a667c57f19da6c3f05da898e2a576df974d97210ca481e4116fff"
+ },
+ "diagnostic_logs_sha256": {
+ "storage/app/private/organization-country-reuse-check-format-20261103.log": "a6e7af65e32d5b40716e41bd0187c984206d8b1d4bc8009925281a6b75b5cadd",
+ "storage/app/private/organization-country-reuse-frontend-regression-initial-20261103.log": "7259a7adfad71920a942543ceb8894e906714035b09380a94d9e8b3e7aff962f",
+ "storage/app/private/organization-country-reuse-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/app/private/organization-country-reuse-pint-final-format-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/app/private/organization-country-reuse-pint-format-20261103.log": "5f719a68a36dd9245ae9d3f6b226946a9b9652ae3f9358da0b3c598efd2e5ac6",
+ "storage/app/private/organization-country-reuse-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c"
+ },
+ "prior_receipt_snapshot": {
+ "path": "storage/app/private/organization-country-reuse-prior-receipt-20261103.json",
+ "sha256": "a109b3cd0b5fd23dadac85e4de0bb434765d5b7903809dbb2ae0a3f1614f695e"
+ },
+ "prior_logs_sha256": {
+ "storage/logs/desk-effective-dates-ready-feature-20261102.log": "5077145e97ebfaf2131447393639e12cb85e8be384f719b98c6e714bafb03062",
+ "storage/logs/desk-effective-dates-complete-frontend-20261102.log": "514739de6970fca851bccd9d29e73c7d35a8f044f29c455b995d17d173dc7c3d",
+ "storage/logs/desk-effective-dates-ready-phpstan-20261102.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-effective-dates-complete-types-20261102.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-effective-dates-complete-check-20261102.log": "b4ebe6eac7037882a6303bb842ed82a6b88fd42f5ff0162f57fd5035d2b7c62e",
+ "storage/logs/desk-effective-dates-complete-pint-20261102.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-effective-dates-complete-build-20261102.log": "4f9672e2227a702e22b57fc4618ce9d3b85e1194d35e3f474d0bd331b2ac2200",
+ "storage/logs/product-usage-final-feature-20261103.log": "8ee1386f774078bf8f5dd438f76d3dc1b5131493d73e3853b5ddc36eb6515234",
+ "storage/logs/product-usage-frontend-20261103.log": "ce2a160fcfb5388e55ac79056cb9481e083b0454d1f919bb306af49b67d7b80d",
+ "storage/logs/product-usage-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-usage-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-usage-final-build-20261103.log": "65d67a1a6a8a5006d3a1b9d310fcb5d247317156d93aea8bf2fda943bf95de4f",
+ "storage/logs/product-usage-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-usage-final-format-20261103.log": "818e1e698ec7cc44b2f6c831b94d1900e6b5b9a9f7ac99143bf5f08ac0cd807e",
+ "storage/logs/product-usage-qa-snapshot-20261103.json": "536689f397de0d17b9628600957c59151580fbe84440cc1b8d3fc65966aa8c78",
+ "storage/logs/product-experiments-scope-final-feature-20261103.log": "0237ab62ddbef2ca33176e2aa84cdd7d0b6a12ea440ec6c6eef59f6c766d3fc1",
+ "storage/logs/product-experiments-intent-final-frontend-20261103.log": "54a717ba4bba4d993ba2a9619ad57e3900321caa561ca1c10937c63f52fbef8c",
+ "storage/logs/product-experiments-scope-final-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/product-experiments-scope-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/product-experiments-format-final-js-20261103.log": "ad18c4e4db2f6dada00dec719cf85ea48dfad3f84e935a149a3f5b565899a760",
+ "storage/logs/product-experiments-historical-format-js-20261103.log": "a88c733b3266376bd9a3dc92aed5f9a05a40c4ebca06221aee658c2e8065b3dd",
+ "storage/logs/product-experiments-intent-format-js-20261103.log": "56b074e7bdcf389d243240636a9ddeb512495826ac93fe7b77dc633ce1d96039",
+ "storage/logs/product-experiments-intent-final-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/product-experiments-intent-final-build-20261103.log": "6e696e29f45a37b70dc380a02daad3519e871b710adc94e42f9d354fe7f022c2",
+ "storage/logs/product-experiments-qa-preservation-20261103.json": "3da441d91f45ee2a2c49879552433a19c338a156e0e60abba969ceb5d0c63c35",
+ "storage/logs/search-metrics-final-feature-20261103.log": "1a54fbb26d00c4ee4d0a621a244487d9b39f97c56f4aae88b9401ece7ed529bd",
+ "storage/logs/search-metrics-frontend-20261103.log": "067d9a089bc526d2fa2aa1bafcf587079bc581ba745c1cb19275f9a8e8068e69",
+ "storage/logs/search-metrics-final-phpstan-alias-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/search-metrics-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/search-metrics-format-js-20261103.log": "cd885f4cd5910af6335f176cc8259262eb2df439b7a52322e70986c58e75f3a2",
+ "storage/logs/search-metrics-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/search-metrics-build-20261103.log": "a7f3d256576324e3915dc3ecb7b77fa34bd3641355ea27f387acf65f43821ebf",
+ "storage/logs/search-metrics-qa-preservation-20261103.json": "6a07edf31765716612a51f96fbc981506a4deab0b45364aefe616fc78149e321",
+ "storage/logs/search-metrics-race-init-20261103.json": "dacd57ebd2e632f087c585199f84a42f0c756d1ec213d34ee1361de9d807ec84",
+ "storage/logs/search-metrics-race-a-20261103.json": "3c6e81c313acd79a5a0b4809ca002251002c6ab5ce1de017ce125ca1860af20b",
+ "storage/logs/search-metrics-race-b-20261103.json": "47081f8116e39d6f1661b6ae56d071c310438ff81d91c33a0308ea7980f4fbe1",
+ "storage/logs/search-metrics-race-proof-20261103.json": "709c4732f0e24e91c9bd5f79bae3ff3612655e41a68dfc72787848bc81e8436e",
+ "storage/logs/desk-typed-fields-verified-feature-20261103.log": "fcbb8cfd3941cbdfc5b6cb7baa2d3e4070812b83853448026c0cd0290f8d489a",
+ "storage/logs/desk-typed-fields-verified-frontend-20261103.log": "bcaff002c1e01632de3f8ce23afd7ecdb5191ed5ebd8011cf2f1f1399dbe7077",
+ "storage/logs/desk-typed-fields-final-phpstan-20261103.json": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-typed-fields-final-pint-20261103.json": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-typed-fields-final-format-js-20261103.log": "d95d64faf1928ca27a4bf0531f7639e059602b84a19bddf673fef810a70f9c0e",
+ "storage/logs/desk-typed-fields-final-editor-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-typed-fields-final-build-20261103.log": "062a57ec0cd42d17fc17cc7a676e456fbec15ed8e6f69414a9c3d70955dafd92",
+ "storage/logs/desk-typed-fields-qa-preservation-20261103.json": "5862d8d1093cd5904c9608735135c1f95af6013a28d4ebb900052e43588f700b",
+ "storage/logs/desk-checkpoint-verified-feature-20261103.log": "3665cb688d8bd437f1bfd9ea31752c2fcc069265c487ff19c68f3797c504ca03",
+ "storage/logs/desk-checkpoint-ready-frontend-20261103.log": "a707d8c7da5bbed2b51280d3e2a0c32b9270a62f734fc16661186fdbe67ed984",
+ "storage/logs/desk-checkpoint-verified-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-checkpoint-ready-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-checkpoint-complete-format-js-20261103.log": "c49a865d7f3a70afe7571b3a36f67e30eec078eccd37d0f92a2d786b6dd4abd4",
+ "storage/logs/desk-checkpoint-complete-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-checkpoint-build-20261103.log": "ec7e57137e010d6eb55dd8cfc50b3e752b456443265a3462fbcb5aa3f093be28",
+ "storage/logs/desk-checkpoint-qa-preservation-20261103.json": "1b83239dab2af62a7ba4d697ce909ad4f36a19d8422c22233aca17faccf9b189",
+ "storage/logs/desk-checkpoint-race-init-20261103.json": "3ba00522d712a406670504dc1b789a57c0749ed896db21e187a860f8a501f69e",
+ "storage/logs/desk-checkpoint-race-a-20261103.json": "35ae4b0611ba2c94f72bdab4e1fcfa1e2aa63f5ec2f6b0e15fe9c38055a95740",
+ "storage/logs/desk-checkpoint-race-b-20261103.json": "15f2f003b1e957cd8298ec871d7efc83f15e92aa010f24c78c0f9f5a55384c59",
+ "storage/logs/desk-checkpoint-race-proof-20261103.json": "79aaed7371c0a8357874d4e908cbba5c4f4d4368063ef161c11d9e0cbfee7f04",
+ "storage/logs/desk-attachments-verified-feature-20261103.log": "c4f12eb4103a22e5987d8a250dafeca05c1e2d8b9c2e92f2a86d3364ef27539d",
+ "storage/logs/desk-attachments-review-feature-20261103.log": "93cdc8587f88a719e03b82dcc0af3676db31f7ac9601cdc76bcc656d1fe3c3e1",
+ "storage/logs/desk-attachments-reuse-frontend-20261103.log": "a381ad02a523e8b3249c3f5492fdc70015d401f8da9dbc22e85684603cbee029",
+ "storage/logs/desk-attachments-review-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-attachments-ready-final-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-attachments-reuse-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-attachments-reuse-format-js-20261103.log": "321a939bfd3f3b528c1d5e05f12e0f801171bfcec9397498545817922f5d558b",
+ "storage/logs/desk-attachments-reuse-build-20261103.log": "51fee437a80712308e30fd2dc5cf297b2a22341f2874d105b8fa8991768d65db",
+ "storage/logs/desk-attachments-qa-preservation-20261103.json": "3d7f118fc2ebb39553e8e7f503107f4c582871c4f40d152843dd0d2ea83fa75f",
+ "storage/logs/desk-attachment-race-init-20261103.json": "a1482c169cb3fb61d8d54e8ad44cb58610592119d4ac05bd834a15894ea3e51b",
+ "storage/logs/desk-attachment-race-a-v2-20261103.json": "b1a46f24f579fb72232d366b86ad7a70563174b46982d5da33038c6061f57e24",
+ "storage/logs/desk-attachment-race-b-v2-20261103.json": "6127d4cc998f98c8c94e13a3dcb96ed8ee8efa675c4d3e5d06e7e92fc5d76923",
+ "storage/logs/desk-attachment-race-v2-proof-20261103.json": "51dfd1a2304e542eec243f326e76248e0a5412ac29c9476700e03ea4f4152fd5",
+ "storage/logs/desk-document-reuse-feature-20261103.log": "9721b1952afe69b593bee2c17841682b07bae8f53f999ec73247fb0ba1be7757",
+ "storage/logs/desk-document-reuse-frontend-final-20261103.log": "6d80f97d70def0925296297a2640ed1d3b6755f706e3d3688fdda29815bcac59",
+ "storage/logs/desk-document-reuse-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-document-reuse-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-document-reuse-types-final-20261103.log": "82962651e47f564de653ad2883f8fd34e7dae4b4468e4ac459cb3331962a3879",
+ "storage/logs/desk-document-reuse-format-js-20261103.log": "aee1caa5df197cbc9c8db6fa4df9dd47586958d64bd57e74c0a4f2b7e3e654a3",
+ "storage/logs/desk-document-reuse-format-tests-20261103.log": "e37ea2489da7c224183d1eb9e339a00ef735b87228b4e5f034f13460506ccde9",
+ "storage/logs/desk-document-reuse-build-20261103.log": "7c08a2fe8bd7fcf194ebdab6fc89e8a611668dc9d1208cbc64a43353cb7f5e0c",
+ "storage/logs/desk-document-reuse-qa-20261103.json": "117fe4561a9470afbf0e6d9eed97840c1980d8d42e5873a3a88c6afc2a8fc575",
+ "storage/logs/desk-payment-evidence-feature-20261103.log": "05cb826170a895ce8b4ca6163a4cf6bc23b46f0aaf4495ec1f420efb005ed82b",
+ "storage/logs/desk-payment-evidence-frontend-final-20261103.log": "e13d90ebc1d379de32de70dec8957a3c010073749f02eeb0fdd3684303cf2ff8",
+ "storage/logs/desk-payment-evidence-phpstan-initial-20261103.log": "5faa3c257232df43db4a06f3338df42d311cd963077ac3ebc3b64eeac17f2d04",
+ "storage/logs/desk-payment-evidence-pint-20261103.log": "e9d6f79de157b815c74d2ca1a40c52bd72e82a3e9f84c4562b4a1ca835c84a8f",
+ "storage/logs/desk-payment-evidence-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-payment-evidence-format-js-final-20261103.log": "478b0df2329ad25a5f0883fb020f881067c3d5e67951a89fee5f7edbcfd79d1f",
+ "storage/logs/desk-payment-evidence-build-final-20261103.log": "d7bb0e7f0044013e5d1daafc1824405eac09bf351dfa55fddaab01e548a5c88e",
+ "storage/logs/desk-payment-evidence-qa-20261103.json": "483b7fda38ef5e45103b5cf86781bab8239bc7cccfe69755d29d3cdfd2ec4e4c",
+ "storage/logs/desk-payment-race-init-20261103.json": "89247fe9fd857fc4e1bab8bf8e5d7268bb8d42ef6220603a5edb57fd01949874",
+ "storage/logs/desk-payment-race-a-20261103.json": "abb4c6cbc4f2b84743cbab2ee7a3b8e94386138894c20b59bfb0adce710af259",
+ "storage/logs/desk-payment-race-b-20261103.json": "c060458107cdc3c67940fbdf66321e6b04646fc3db28db90390de11f1380ab00",
+ "storage/logs/desk-payment-race-proof-20261103.json": "4f3eae24811cea6ede00871a34c6a4084322ff31c2c5e4485da122455956c124",
+ "storage/logs/desk-payment-race-migrate-20261103.log": "ef67db8533c14dd21ee37c12dc4197195eb3f6f7d5f1eedbf1871a21105eb8c5",
+ "storage/logs/desk-closed-lifecycle-feature-20261103.log": "b6177a328567f8d774eea21b62887bfec4fb81e1740c4ddce7587b2c540bad24",
+ "storage/logs/desk-closed-lifecycle-focus-20261103.log": "de000347879078ff5831e38437acfc678f34391c76d7f3195df04d6321e15f6b",
+ "storage/logs/desk-owner-state-frontend-verified-20261103.log": "95ab9360217c283a5f8ec13647b416018b8d7bb88ec3a14f515a32ea64ea0181",
+ "storage/logs/desk-owner-state-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/desk-owner-state-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/desk-owner-state-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/desk-closed-lifecycle-format-final-20261103.log": "886db9b6f2c4c3c7215be4c43ba36d7de6c6e4ab4a70b0bd226577b976486909",
+ "storage/logs/desk-owner-state-format-20261103.log": "52ee775a2281677fe18a32094f9767f1c3e23af460d7c384be2af2278ef991fe",
+ "storage/logs/desk-owner-state-test-format-final-20261103.log": "283f457dff0fddb160d7aae07de877b6796c3a8ca430dbf24f3525992e209619",
+ "storage/logs/desk-owner-state-build-20261103.log": "14cf70c4b92ad6d7e1bf7942c9a01abf04b02a2180a4c557226162df90e4d264",
+ "storage/logs/desk-closed-lifecycle-qa-20261103.json": "92eb9ef983ba733fb8c789ff7a8f607c38a197e24d2c14a37984a9f36c02969a",
+ "storage/logs/desk-closed-lifecycle-reproduction-20261103.log": "aad323531c3ee212fe45fadb3e8a837cb43b076a49debbda42bf4511ebd4b0f5",
+ "storage/logs/desk-closed-lifecycle-assignment-reproduction-20261103.log": "e338b3c728b8bce57131f48e56bfbfd505d04d92bff36b1a4fe633c5ee65792e",
+ "storage/logs/crm-record-versions-feature-20261103.log": "eb8572b42ce2dd47ec7adeaa6648d6109cbd18c16b8892c77c1283b1565885b9",
+ "storage/logs/crm-record-versions-frontend-20261103.log": "d512811038cb1720ff2c238abf6ba0f65deac09e1ea482f566e536e5cb77d88b",
+ "storage/logs/crm-record-versions-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-record-versions-pint-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-record-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-record-versions-format-20261103.log": "d37a2496c9117c9c20abb670c2cb3de259f98ff6baed7809bacfd98d1cba973e",
+ "storage/logs/crm-record-versions-build-20261103.log": "32e709e73a2696401ae96253d3822061b41d0e3c443d1a11be24dd098b7bbc77",
+ "storage/logs/crm-record-versions-qa-20261103.json": "86ac445a3429384bb1f5ee524e94cdc8fe22250a8407bed863fa4ae464f6ced5",
+ "storage/logs/crm-record-race-proof-20261103.json": "7bb425c29db7edbc66434a2664eafdf5333de8dba0292ac4e26beb33efd162c6",
+ "storage/logs/dashboard-work-queue-feature-final-20261103.log": "07c63eec407d44d3ce3e9cde3927fb87a49783bef4b1a7e17a0e356a5e8b9859",
+ "storage/logs/dashboard-work-queue-frontend-20261103.log": "a3f86222f38e0833efb68ea6ceaa052cbbcd1f907c74caef02f27418a1c88862",
+ "storage/logs/dashboard-work-queue-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/dashboard-work-queue-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/dashboard-work-queue-types-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/dashboard-work-queue-format-20261103.log": "dde473e47ef4cee0c138ec5b68024ea969b08b89f5f20113918f01b4465bf10d",
+ "storage/logs/dashboard-work-queue-build-20261103.log": "dd22d29a8cb8961cbca482e3a2e6ac4b0570fe66ed91366c47f02dc8410ac46f",
+ "storage/logs/dashboard-work-queue-qa-20261103.json": "bd0f8b38441bc709e8b80b1cacbcf26c342ca9db57e3e93b62a45d9885521124",
+ "storage/logs/crm-next-action-reproduction-20261103.log": "bb8a02611a931add10b6115bc77c38c8ba2842a8379024ceb34ee280b0fde2ce",
+ "storage/logs/crm-next-action-feature-20261103.log": "11ae82af99b9419ffcc9488a9fc9f5564256b773cfc7bc53390928dfbf666271",
+ "storage/logs/crm-next-action-final-focus-20261103.log": "2c0812c8ae937568d35339beba1a5483bcebd77c938754226b1350d4037acf4d",
+ "storage/logs/crm-next-action-frontend-final-20261103.log": "65c39c169731c5ddc92fa38fd7d344d72a1eb263938f8f1504e74d001a89644d",
+ "storage/logs/crm-next-action-phpstan-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-next-action-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-next-action-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-next-action-format-final-20261103.log": "1618b11d1fa5796eb41666d10b9075f0f632fddf5d6838ed86d3d08d505f6d1d",
+ "storage/logs/crm-next-action-build-final-20261103.log": "9f715dd1143c5246ffbcbb7fb7eafb269e7fe31c46c3b0496871d1c24d2cdaa2",
+ "storage/logs/crm-next-action-qa-20261103.json": "fda0cd95d6109cb863461a5601e29b2a2b65528684c618d54b5f2d7c7f34b087",
+ "storage/logs/crm-next-action-race-proof-20261103.json": "5e54b8e9f8a100bb2ddf78a647ea23a275ccd88bbbfb583f5f32d5221570f803",
+ "storage/logs/partnership-editing-reproduction-20261103.log": "a9197d5c240620a389e738e96699bc840ef3322331aff940419b61861d9fe58e",
+ "storage/logs/partnership-editing-feature-final3-20261103.log": "18990ca0f19f2d5e9c611109f0e6eda20ff23fd64201e3a2f80636f380d8bd66",
+ "storage/logs/partnership-editing-frontend-final2-20261103.log": "7d776cbd8c37449bd7bf27731dceb7c5ee724897f997fd5146943f473c18c14c",
+ "storage/logs/partnership-editing-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-editing-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-editing-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-editing-format-final2-20261103.log": "a20eb5e663931fa3791c13200a37622cd44abd2c07162e35477278cd8285e2c3",
+ "storage/logs/partnership-editing-build-final2-20261103.log": "61478359b6e2fa0af226d67e990c08690815ef608d95e17ad0706739ec515979",
+ "storage/logs/partnership-editing-qa-final-20261103.json": "da192aa349566d79da4ddc7098bf54bb79f4e46d11a18e1ef97f955f7bb9d0ed",
+ "storage/logs/partnership-editing-race-v2-proof-20261103.json": "71e6288ee25f687f82632608cd0a8710f7ffef8d53f37d05790cb5cb7cb2faf0",
+ "storage/logs/partnership-participants-reproduction-valid-20261103.log": "973989c4c2cbf690567866a0e5f1a8afdb6a0e65b8b41adba5fa007ec8df00ee",
+ "storage/logs/partnership-participants-feature-final-20261103.log": "b6df1e332b4ec1e43d02c78bbe47aefb4a395e06f67556bcd4bcf74df3e91a83",
+ "storage/logs/partnership-participants-frontend-final-20261103.log": "42cc5ed5a4d77220cd4a5da589936f693fe97d8c61e58c22ec7f4a4503956518",
+ "storage/logs/partnership-participants-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-participants-pint-checked-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-participants-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-participants-format-20261103.log": "35ba768faac6089de976ec23b3af273e99b63f8c3a3fffee08d00c3d7d0f4380",
+ "storage/logs/partnership-participants-build-final-20261103.log": "ab30adc1f9fc1056c5f04bdbd3cba9b955247ce3771172358b01de0b705005a2",
+ "storage/logs/partnership-participants-qa-final-20261103.json": "1b3f8ccb4253a55f9fd4f2647b430779d4f908a5e05e8f2ed6ef527a7578c288",
+ "storage/logs/partnership-room-recovery-feature-final-20261103.log": "a1826cc9afeb51f53ecb29716a8b7bc6cc847d2e282ec37db970a8ac84f04914",
+ "storage/logs/partnership-room-recovery-feature-key-case-final-20261103.log": "6c9f71d97f1c981e87525d62c61cde67de0cb86ba522a4a1802afb7cbc98145b",
+ "storage/logs/partnership-room-recovery-frontend-final2-20261103.log": "66d760ad878800cf4a2380d7bbf82e76d9a1ad8e0df8db704f8e83e0d3e5b860",
+ "storage/logs/partnership-room-recovery-frontend-focus-final-20261103.log": "7580ff62e6d6ef47435e0d04393f71cc6656131ebafbfac8c18f4ab090e620a1",
+ "storage/logs/partnership-room-recovery-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-room-recovery-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-room-recovery-types-final3-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-room-recovery-format-verified-20261103.log": "c7cd05fc98a2909d49688b39f311ff337d905acf7d0cfa5d712d2edd835b56bc",
+ "storage/logs/partnership-room-recovery-format-final2-20261103.log": "84beeaea2268ff520e8af9df2b467ee89314de74bee38a9f209f5aa5c7a1fb6a",
+ "storage/logs/partnership-room-recovery-format-final3-20261103.log": "1f19f4c3e5ad137674adc9406cc8575b999d5466de5239457105cd80c6f64114",
+ "storage/logs/partnership-room-recovery-build-final3-20261103.log": "4e5c9e86e16fe8cdb402aa690ce3fe017140a73680689501af1763a1de8a4f6a",
+ "storage/logs/partnership-room-recovery-qa-final2-20261103.json": "c15dc7311bb1e4911cf920a32a219c6fe6c76ec765efb12841b34a894371341f",
+ "storage/logs/partnership-room-recovery-race-proof-20261103.json": "fd124e01ce1deb9c36dbeb6b5e1a158bb5b9e0bdac4c380d93d6ead859b3aa0d",
+ "storage/logs/partnership-candidacies-reproduction-20261103.log": "22a32c994e149f15c290e964dff11412d19edc7380553963d17f453dbc009d4d",
+ "storage/logs/partnership-candidacies-feature-final2-20261103.log": "6ba363c9b99332d0909d5791c6dfa7e1582555385f53506fe601e120a72fc401",
+ "storage/logs/partnership-candidacies-frontend-final2-20261103.log": "df7f7fc3767e8fe8dfc804293a97fae160af8d30891cd7c3e68e13719a5dc117",
+ "storage/logs/partnership-candidacies-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-candidacies-pint-final2-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-candidacies-types-final2-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-candidacies-format-verified-20261103.log": "724651ede526eb51d8a2f2fbcf95a0f874161f9cb5b3802f3abeea4662ef7258",
+ "storage/logs/partnership-candidacies-format-final2-20261103.log": "17a641bab944cdba52b6d1b1575439c5f8d1193f41681fb00587dbb2ce50dc49",
+ "storage/logs/partnership-candidacies-build-final2-20261103.log": "82b575792f03939c80a08e6794ff57467b44571725643956e42607bf8b63f71c",
+ "storage/logs/partnership-candidacies-qa-accepted-20261103.json": "2fd53e9922806aab7540b562fe21edfb4947a6883b01ce64cfda09dfb5d24bf3",
+ "storage/logs/partnership-candidacies-race-proof-20261103.json": "aed31f0ad2e4f9e9b9700e4470f96e86aaa2ffd590d35705b96ec6b3b2bf52bc",
+ "storage/logs/partnership-candidacies-source-preservation-20261103.json": "1018910df562215ccc75bec5e97e9d2109930d7b2f2ceb9701a6fadd1bffef7b",
+ "storage/logs/partnership-history-feature-final-20261103.log": "7f4669fce5f44b86e0a01ef22d42f812c46e3e151a45b5bbf0cd3490eb0667d8",
+ "storage/logs/partnership-history-frontend-final-20261103.log": "aad2efffbcc586c173b4252ac8ad264c65751a72b1a62cc9dd91349dc6ac7df9",
+ "storage/logs/partnership-history-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-history-lint-final-20261103.log": "17f66262693ad77699a971c893c6ef92e7a1aa6bde7a24944b5fcbc7b3526c7e",
+ "storage/logs/partnership-history-build-final-20261103.log": "0e5e22187b9c8aa1150eef25749278375df0b8567aa3439cc3ca44b32186e2fc",
+ "storage/logs/partnership-history-qa-accepted-20261103.json": "b577eabf696bedbed3d1add862a09e6327b2c3c1f423c29663441d2cf0267725",
+ "storage/logs/partnership-dashboard-reproduction-20261103.log": "3fac218acbc9518c3aff42984f5537641205b0f1786e1fb83db363ab38c9425e",
+ "storage/logs/partnership-dashboard-feature-final-20261103.log": "282024d917bfc36f84d520dddaf3ac1a593d13431b0be318bea9e890a6ef35a5",
+ "storage/logs/partnership-dashboard-frontend-final-20261103.log": "5e914d2bc060361316152c9db030e90a311496cf8973ac03c15dac1e2f77ad52",
+ "storage/logs/partnership-dashboard-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-dashboard-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-dashboard-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-dashboard-lint-final-20261103.log": "dab1f820655e28b483ed4e875d9c599e53afb357b1f29e7c784151da9dd8dcb8",
+ "storage/logs/partnership-dashboard-build-final-20261103.log": "ddab75b7bf2711270c102873f1fdb3a8e8e3bc173a0bbeb16f25f6c4bed0a864",
+ "storage/logs/partnership-dashboard-qa-accepted-20261103.json": "0f9bb07c83aa44af9ffa440f9f470d943981cc13ea2fd9b6e2d89eb631ed0db8",
+ "storage/logs/partnership-publication-reproduction-20261103.log": "41f4ec3bdae29dea8e819e07133fc61e2e89d83599ad9c8fda6809a7a5acdc67",
+ "storage/logs/partnership-publication-frontend-reproduction-20261103.log": "92f35719ddecf5afb76aa10fd791c7bb36a6e05248cc90d616505675bb6f1527",
+ "storage/logs/partnership-publication-feature-final-20261103.log": "abac9b3cd9655c4b8c6ff5e419b308bfa3bba1ff99b359080edfde4f8d740ef0",
+ "storage/logs/partnership-publication-frontend-final-20261103.log": "5b2a0ceb0f0c92eee772e8618fa9bab33e3568f843c47a0e0d0f0b70f60c9857",
+ "storage/logs/partnership-publication-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-lint-final-20261103.log": "ad8654b9e893aabf33657ee51a2ddbffabe984fd5d53eaa2865983b5bc3daeac",
+ "storage/logs/partnership-publication-build-final-20261103.log": "587ceee2617bf0e2b3574b4936363768d3f8eae252d4059081558d055f6f5e60",
+ "storage/logs/partnership-publication-qa-accepted-20261103.json": "dc91a36bccc39054db0478017c119579c67b4eecc3a0f57ad6f7250f692b682c",
+ "storage/logs/partnership-versions-feature-final-20261103.log": "1875d74846ad590783de14b1b237d0a61c83b8f5eaec1ea87a734ded71d92c50",
+ "storage/logs/partnership-versions-frontend-final-20261103.log": "7fa4f6a33cd7fc75069634d491670b337a9f12e83d17b31c47e50fdebaba251a",
+ "storage/logs/partnership-versions-phpstan-final2-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-versions-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-versions-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-versions-lint-final-20261103.log": "cd75e33e17e1ea6cf6937ec6591d9c05a839ddd8d9ec7203e598755d59cf9f98",
+ "storage/logs/partnership-versions-build-final-20261103.log": "499aa93f25c1f4dfd5fdbdbe1a2a1ad8de721954dde1ab7b665091c87f4e432e",
+ "storage/logs/partnership-versions-qa-accepted-20261103.json": "12373e0217d60c92739a5be9f49056e6a09053d52f2e28690adf05bee08fcb82",
+ "storage/logs/partnership-draft-recovery-reproduction-20261103.log": "9b10983cc9c8fdb061f456ad9d37bf6af2a4cbc6e316891ebc5084a743b527ce",
+ "storage/logs/partnership-draft-recovery-frontend-reproduction-real-20261103.log": "1aeecaa0c8fbaf6d08468a8a26b914c3c37f849cf97bcd2dc46fdf9eb096aec2",
+ "storage/logs/partnership-draft-recovery-feature-final-20261103.log": "68b71f4ce4872947f2da600ea4d43c1280d5fd1e306d5c865b6d2f943bb4e1b6",
+ "storage/logs/partnership-draft-recovery-frontend-final-20261103.log": "93737bf0e3737138736876a7e5609e960ab6e72cf2ed044badca95ea830e22d7",
+ "storage/logs/partnership-draft-recovery-frontend-verified-20261103.log": "28d6bc8a1d0eb4a0598e30981bab081cfa8e6d0b1704a7a8666e0139383e0c5a",
+ "storage/logs/partnership-draft-recovery-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-draft-recovery-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-draft-recovery-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-draft-recovery-lint-final-20261103.log": "a5946dfdce681173b83b85fe9a47350eb535d0dd3a1d34cedf46f3902942ac47",
+ "storage/logs/partnership-draft-recovery-lint-verified-20261103.log": "36e1a95be4652a3b1353e4838972d327330799409100ddaffc68ca1517e52932",
+ "storage/logs/partnership-draft-recovery-build-final-20261103.log": "b3846a38c3e4bdbae817850e016fa8a7a7152f23e1d75bf61271b74c1d6c747d",
+ "storage/logs/partnership-draft-recovery-qa-accepted-20261103.json": "49bf2fa710f8f7f1d5964137bdb2c36e2ecf6410a55fbfe079ae1b2a00611076",
+ "storage/logs/partnership-agreements-reproduction-20261103.log": "d48176b662ecbce01adce0ce8111e0f678eb0c003f326cb9f1a71651a287e706",
+ "storage/logs/partnership-agreements-frontend-reproduction-20261103.log": "b8fae5ad0e76417574db77e8ed49ca73e3ff8cd2de3fc348972948d77c9168e7",
+ "storage/logs/partnership-agreements-feature-verified-20261103.log": "9b99032f7ddd9af154a0c6db51339f7d36e37f5096cb1a0dcba24ba548122848",
+ "storage/logs/partnership-agreements-frontend-final-20261103.log": "3392de092300ef55e74a3fb69e5970a4f2e8ba22e7c73267270ea8bf964edade",
+ "storage/logs/partnership-agreements-frontend-focused-20261103.log": "e99dd6e72d5fb6f416b486b40e10354175b879842c5f1bf2eb21fef0fa33d2ae",
+ "storage/logs/partnership-agreements-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreements-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreements-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreements-lint-final-20261103.log": "6358c67bd8eeae715ad5350d679e90fca677fda7a1619e825f152fcb8a6e19f6",
+ "storage/logs/partnership-agreements-build-final-20261103.log": "69adf81c6dcf25b5dcb18467bddba98a44cc6a408c8fb40b2b7450ced16804c7",
+ "storage/logs/partnership-agreements-qa-accepted-20261103.json": "7c4816263e1457eff7f87fd88ebd09e98220b8df1941ff98d52df70b4357d4c7",
+ "storage/logs/partnership-agreements-documents-gd-20261103.log": "7a727098983085259b05c483948f8844bd618284a7094ce524b0a2ae2c8a0070",
+ "storage/logs/partnership-agreements-documents-gd-20261103.xml": "86e50927736e772c35ae408afe63699b9bc6206c30fbd87ecd35504e63389928",
+ "storage/logs/partnership-agreement-history-reproduction-20261103.log": "c4a17b62a1a4b746d7efa6971a2fba9df2cd88e32f154e6245fcc13fbb651616",
+ "storage/logs/partnership-agreement-history-frontend-reproduction-20261103.log": "59c4390b1e8ad4407d5b8c93ea8c34b44ab3bf26adbd354135c567bcb8301f2f",
+ "storage/logs/partnership-agreement-history-feature-final-20261103.log": "531380ad74805ddd5e43d4294768a9d796093a2fa31edeea14fe525016632d67",
+ "storage/logs/partnership-agreement-history-frontend-final-20261103.log": "284abcd616a49005c0f7452ff001ad9235ba1afc3f855061ad596d2635d13826",
+ "storage/logs/partnership-agreement-history-frontend-focused-20261103.log": "f397974d8621381415b5d9f8edc73735bddabe35a981ec79d1b7c867f632af7d",
+ "storage/logs/partnership-agreement-history-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-history-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-history-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-agreement-history-lint-final-20261103.log": "405b4b6e4fb697c2681bed9a1a5fba507194ec64a14fbd5a90f269a2a3446e17",
+ "storage/logs/partnership-agreement-history-build-final-20261103.log": "ef2bda27dc404a489a228671b22d67e3591681673b21b6655e2976553b7dbf7b",
+ "storage/logs/partnership-agreement-history-qa-accepted-20261103.json": "d9cfb8e7e2c8e3646d0d7e189f8f6f45bf3dc3e77967f5d0193edc73bcc810ee",
+ "storage/logs/partnership-agreement-projection-reproduction-20261103.log": "c566e0ab0f4ee56a0ba9fd97e0d6c947d2994d985df7d2b36b4689e1c61ac7ce",
+ "storage/logs/partnership-agreement-projection-feature-final-20261103.log": "ff9a38a2f8c10f366c49115f2634f280968178f2b0260e175895fb768f7002bf",
+ "storage/logs/partnership-agreement-projection-frontend-focused-20261103.log": "7e53790dc4020c2357e9ab064424c5f5fe2bbe11c86874d4b16d69edb6807883",
+ "storage/logs/partnership-agreement-projection-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-agreement-projection-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-agreement-projection-qa-accepted-20261103.json": "d18172196da2673f3122a55283d7340835c220e2784be827a553ece98b0f4ea9",
+ "storage/logs/partnership-publication-summary-reproduction-20261103.log": "d8e58b32ade77518ddd00c03fa39ce92057d425dc83f930789f97bdd416c99b0",
+ "storage/logs/partnership-publication-summary-frontend-reproduction-20261103.log": "9248fca7b607b1056c387e90c048ed77e161e33b4dff9c232e04578d5defb6fc",
+ "storage/logs/partnership-publication-summary-feature-verified-20261103.log": "34b2c9c14847e2df060e03ac70ec6a0df800d071b5eef0064719f1eea0c5e42d",
+ "storage/logs/partnership-publication-summary-frontend-verified-20261103.log": "91fd0622bc352f96970ba3598ad97262a99721d52b0842fa363188e06a4eb5c7",
+ "storage/logs/partnership-publication-summary-frontend-focused-verified-20261103.log": "bc5bbc07043f423098abef812c7e007293aac17a0ce74ca43801dd70261e49e3",
+ "storage/logs/partnership-publication-summary-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/partnership-publication-summary-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/partnership-publication-summary-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/partnership-publication-summary-lint-verified-20261103.log": "196949b0dba96738be131fabc2e5fd26670277d9b982bf71b3f3d3832aba0888",
+ "storage/logs/partnership-publication-summary-build-verified-20261103.log": "2dcda7a744d8c116472ab14306a443aec16795d677fb6304212004ee06e3fa8a",
+ "storage/logs/partnership-publication-summary-qa-accepted-20261103.json": "53aaf81baf9c93ca146676a95d1dacfe131700cec60331d008d5668b8c606a8a",
+ "storage/logs/partnership-publication-summary-frontend-refresh-reproduction-20261103.log": "1c1a284e14f825a934498ab15a069dc1fa0e88fd8cebc95d9dd3159e3123b342",
+ "storage/logs/crm-task-creation-reproduction-20261103.log": "5c776e5cea375be46c0fc0c41c28544e4ab62cec9e0741864668f20a043fc32c",
+ "storage/logs/crm-task-creation-frontend-reproduction-20261103.log": "bbe5c3520784af735fd56f107c05e8c713a1b73b6ed45ed24245ec12c9450122",
+ "storage/logs/crm-task-creation-feature-final-20261103.log": "aec12cb7e1af791fc64c9a4548a5ec5a5d6e005ebbbf0996a602ae3cda0559d3",
+ "storage/logs/crm-task-creation-feature-focused-verified-20261103.log": "8229ffad247e1fe14cce94fbd0f9e7ff7fc27e830dde43d3a6d41a682bd25f9f",
+ "storage/logs/crm-task-creation-frontend-verified-20261103.log": "cf0e2d6b5d3c1b6e5a759431feedc7db913844002e2205fe4889b176d4a53e0d",
+ "storage/logs/crm-task-creation-frontend-focused-accepted-20261103.log": "3a2ee3b07de9502af6ad42d688bedea598340c657d38ccdfc0b95f550e6a7a5f",
+ "storage/logs/crm-task-creation-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-creation-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-creation-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-creation-check-verified-20261103.log": "14574d57b4ca6ef1bcfeca413d579d9eaa46805745d40f5cca9d7ec9a730ac1c",
+ "storage/logs/crm-task-creation-build-verified-20261103.log": "f2bab44491af8c4b2efc1c2c820cbc0c0a4f94bfa25f0afab2ce322defed2df8",
+ "storage/logs/crm-task-creation-qa-accepted-20261103.json": "1b778bae8909be7ad4c8a6e417ae598273f2af1d60f6bbc44f89aab660132ce6",
+ "storage/logs/crm-task-preparation-feature-final-20261103.log": "486cc68b60ac4fe85c8585f22b12aabd067a7486403b3edd1cf3df1b9a83ae7f",
+ "storage/logs/crm-task-preparation-feature-focused-verified-20261103.log": "8d2a2cfaaad9a63b32335c88b822dbcffb72b86b1ad3e91d521b845b9c36ec70",
+ "storage/logs/crm-task-preparation-frontend-complete-20261103.log": "8794e86d00b5220dd64f69aa9969c233a2618c3e3a3a0244168c1c68d63ff438",
+ "storage/logs/crm-task-preparation-phpstan-verified-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/crm-task-preparation-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/crm-task-preparation-types-complete-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/crm-task-preparation-check-complete-20261103.log": "29775a285781e33b26ef8efa16936c07144503e76f51f63a2ec0e3c6eed5f1fd",
+ "storage/logs/crm-task-preparation-build-complete-20261103.log": "a2beb00d4a4781e14a85d281cce4bc4b0c0c76f522582a5ecff5b4616eddda1e",
+ "storage/logs/crm-task-preparation-canonical-reproduction-20261103.log": "5b56c460747a308de80955808efae4cab0330933c037e3183e2f604d7690aff5",
+ "storage/logs/crm-task-preparation-timezone-reproduction-20261103.log": "71989f707bfc049a058bddcd3e209787f0de148fa96cbe9d9c95409bb6ed1abb",
+ "storage/logs/crm-task-preparation-qa-accepted-20261103.json": "435896f1b112db969e325bff20b7d33c024c50a22eec5f7c23695a96348a54d3",
+ "storage/logs/education-work-queue-feature-final-accepted-20261103.log": "50624620c5dea8e8cddcd43178380df15c7b02b4312e2d769908a04c5a3a6a1a",
+ "storage/logs/education-work-queue-frontend-verified-20261103.log": "e035e1e6a29c7d7796b2a9929444cd58e9418ea9d27b1761531939698f1dd9ef",
+ "storage/logs/education-work-queue-phpstan-final-accepted-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/education-work-queue-pint-final-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/education-work-queue-types-verified-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/education-work-queue-check-verified-20261103.log": "9c2ffc8cc41975557ac4fb1f858602be4b4ed2522aca8ddad367e3aac67f9b05",
+ "storage/logs/education-work-queue-build-complete-20261103.log": "3d321cf1fcfcff81f0d7228fe2950e96eba6c1a9c49651e8d0d8bf9a7d755a0a",
+ "storage/logs/education-work-queue-frontend-reproduction-20261103.log": "9d0ba2c985cfcc5011c34656ea4c79f16910be105b4a3f70b48360524180b923",
+ "storage/logs/education-work-queue-qa-accepted-20261103.json": "e745801ec68e96f6ec337675ef4785d0af912ee7d66a9acf66de74d400337741",
+ "storage/logs/opportunity-incidents-feature-role-verified-20261103.log": "9883a182dc6278865bdc018cc1980b8bae7d19c32aa596c784ab8eb05f2cd247",
+ "storage/logs/opportunity-incidents-frontend-final-20261103.log": "d701e8eb10a6b98e4c8d3de279cc17ba21004374eda3e9f612e30465fbf4d259",
+ "storage/logs/opportunity-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/opportunity-incidents-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/opportunity-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/opportunity-incidents-check-final-20261103.log": "e206dfe6b6141b05c877ee104b12fa81fca684f64789d02b97565e76b93d6bc8",
+ "storage/logs/opportunity-incidents-build-complete-20261103.log": "8db69d251024cda18cc4215cbd4f9e40570f7ef847a2520f5ac7c1e48d695a25",
+ "storage/logs/opportunity-incidents-qa-accepted-20261103.json": "3d6494f2bec60d084392d39d7c438341a08c135d8451977a1800c7a0d4f5b027",
+ "storage/logs/incident-handling-feature-final-20261103.log": "4e15a136852c005052f886c5cba071417e45b0ce0861d84c57c39025ab549724",
+ "storage/logs/incident-handling-frontend-verified-20261103.log": "3e885cc2c403729cb6aab7a9b59c57a185c0972c5f7f9effc30a9dc6449b3c4b",
+ "storage/logs/incident-handling-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/incident-handling-pint-verified-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/incident-handling-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/incident-handling-check-verified-20261103.log": "431cd742d25d01299c83efb3c9e27c24b98840125b860ea2ccf1f3770950e2b1",
+ "storage/logs/incident-handling-build-complete-20261103.log": "ac53124d5e6055795c65829e013249f1312dbf5718cad4424dd5f18c1552d909",
+ "storage/logs/incident-handling-concurrency-final-20261103.log": "b942812f142d031dba1865aec7191387665cf0eb15de6851a5c1369af9dd5acc",
+ "storage/logs/incident-handling-concurrency-existing-guard-20261103.log": "c96080706322c9907df906376d68452d3c05748ecfbe178f716ade3072cb10de",
+ "storage/logs/incident-handling-prior-mixed-terminal-20261103.log": "88d63770dcbf369c64d7ae83457cb78e063c3af9130fd037c3a9089dcfeab6d0",
+ "storage/logs/incident-handling-qa-accepted-20261103.json": "5df9a0c3c44e9845052b1f254a4db1f95070ba37c32d93bbc34bc81cca23a63f",
+ "storage/logs/incident-handling-prior-mixed-qa-20261103.json": "8873bc042dae27ae1d355274b6876fb748dbe8f0659dc7b0c124a17e0f667787",
+ "storage/logs/support-profile-install-feature-initial-20261103.log": "640ed2b6681d3f7ec232131384adbbeb4fa56410c7aadc4d8cd203fe84b28ee1",
+ "storage/logs/support-profile-install-feature-final-20261103.log": "5be9b6f10347dcd37e80bce9e1d53d2a2706babd4cb6b0988f828466b8851b47",
+ "storage/logs/support-profile-install-frontend-final-20261103.log": "f9c9e8db8d549c69948dbfa073db793b6458399546011dd23d47536a79e08d5f",
+ "storage/logs/support-profile-install-phpstan-current-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-profile-install-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-profile-install-types-current-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-profile-install-check-final-20261103.log": "96e9e4c7cd0fe77de881196f69b77a9e99d44814fbd07d393c5959af128a2313",
+ "storage/logs/support-profile-install-build-final-20261103.log": "a7d88d8cba7bc2a587d03331291dfa536626c46e1f6361ff32ff73a96eb3e257",
+ "storage/logs/support-profile-install-operational-final-20261103.log": "0cd4d35118a283cec55f9366d3dc429a320e1a951551a9a478a31f46fae44d1e",
+ "storage/logs/support-profile-install-operational-existing-guard-20261103.log": "2d5b48cb77f024e16de93b1c8073c42c3f92ed00ade7a08d12ead8d2ca9ac309",
+ "storage/logs/support-profile-install-qa-accepted-20261103.json": "b1133145c8452ef2694366cef6374e04e114fad3beee06ba96be14f312530850",
+ "storage/logs/support-profile-install-operational-proof-20261103.json": "fff495a83c64060862a0f85ad69d8b3dab411164b63d25008fa91dff7210f140",
+ "storage/logs/support-notices-feature-initial-20261103.log": "3f15e1c39a5c9a6c11d406922af4be88387439ec25955a1ed08b0d75ebbf33c6",
+ "storage/logs/support-notices-feature-final-20261103.log": "e9fc650108115089d8559e8b4872a34aef56d5d8f7f9899f64a630b558cd9c79",
+ "storage/logs/support-notices-frontend-verified-20261103.log": "c16395f6f3a65f9d581bcb1cd51ab52a77c8127cdd27a835d119920716710382",
+ "storage/logs/support-notices-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/support-notices-pint-accepted-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/support-notices-check-final-20261103.log": "1c90b622565a244e58613b6335e2e8b605610a6909465e4b0196173f1912bcfa",
+ "storage/logs/support-notices-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/support-notices-build-final-20261103.log": "faf446a5c2fe489afc1d4ecb1bfe8ac949c936e46a2c7d96ade8e8b6bf4c6240",
+ "storage/logs/support-notices-qa-accepted-20261103.json": "478607117a42385b070c108929220c22aaa62191abc0f369aa4a731804b1ee22",
+ "storage/logs/resource-incidents-feature-initial-20261103.log": "c6ebe4d6b595ee6eb0a6d4c7a5408d2f289f351eb8fcbdc74a5e8bb4adb10aba",
+ "storage/logs/resource-incidents-feature-final-20261103.log": "12e151a8666e13b916e1becad5452ff7afe92b45a0ca25969bdb725406e722a7",
+ "storage/logs/resource-incidents-gd-unavailable-20261103.log": "368307b4950c2586c6032f4a078e1d305aa194e54b8da2f8525ee8f79030f67a",
+ "storage/logs/resource-incidents-frontend-final-20261103.log": "75385d23cb5d2b7a864bd3d7edd44cb6dfa6678292218fc897a2dcfb8953ee69",
+ "storage/logs/resource-incidents-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/resource-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/resource-incidents-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/resource-incidents-check-final-20261103.log": "b1a1d76fbd364f4cb1c78b9f7f38cfcc655d2155c27dd6fe7d31e16e6cd30a40",
+ "storage/logs/resource-incidents-build-final-20261103.log": "b82e48cc2c3b620e6204c60cdad6bdfe77659d0129d15ef33ba9c2ca0aee3bea",
+ "storage/logs/resource-incidents-qa-accepted-20261103.json": "d8c8430fca9c956cf10b204bd4409adaf8a187d3592d1e7fc8f7f39a9c777d2f",
+ "storage/logs/resource-incidents-runtime-gd-20261103.json": "d2c14d09f2d317d35ba03666710bef4369c8546038e9acd348359f4df58ef3d8",
+ "storage/logs/resource-incidents-runtime-default-20261103.json": "25eb4909a6cf576969addddc5bca1c97703c1de1e6bfebddaa8a3661f1aa7043",
+ "storage/logs/scan-incidents-feature-initial-20261103.log": "34c0d09fb3cef0583c005a5a21e9cf198e1d4e1b2629208184c100d56b3ef159",
+ "storage/logs/scan-incidents-feature-final-20261103.log": "de586fd101f083af0976b37c8bf80ebf29a22cf7b92e274fbbe67c308e710d35",
+ "storage/logs/scan-incidents-frontend-initial-20261103.log": "6250c3ed8c6ab9fac2dc5f3cb3f757022ac7b2971d5d359a628aabc1209c78b3",
+ "storage/logs/scan-incidents-phpstan-initial-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-incidents-types-initial-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-incidents-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-incidents-check-final-20261103.log": "b605db485894f33b655ec2682f241160d4b03ff0389c8aeebbf27af6eb056df2",
+ "storage/logs/scan-incidents-build-final-20261103.log": "66c51148e850059b6404940f3189399230caa994993d63defb72ad2bd61ec921",
+ "storage/logs/scan-incidents-worker-init-20261103.log": "d1d0ba14bc20a77a8dc85236f9401ce85c9b0f9b93fa65ce875deb95b464380d",
+ "storage/logs/scan-incidents-worker-process-20261103.log": "ba3e512c805f7bb0852c62dd871dae76858919d822587c32208f6118f0e00d12",
+ "storage/logs/scan-incidents-worker-verified-20261103.log": "115c2047c614e5d8faf2ae5d1363d2661f4b092519c3a65501923f2f1fec9f59",
+ "storage/logs/scan-incidents-worker-existing-guard-20261103.log": "580207ff6534089bfa4bbde910e584aa8c55d390689f1095b8e5bf0c6d5ee363",
+ "storage/logs/scan-incidents-qa-accepted-20261103.json": "b23a6f89d98a2c43c32fae97c6b99ce9beadcfaeca610461a467d79895c825e2",
+ "storage/logs/scan-incidents-worker-proof-20261103.json": "8fa6fa596c5c51d20ea42eb8160788479b35e122f29e29ce167d802dcff893d4",
+ "storage/logs/scan-retry-feature-initial-20261103.log": "b6c344f4ba2ed260f1f7414c4d1ab2275a0fbcaecb84670c25f5b9c92bd1c1dd",
+ "storage/logs/scan-retry-feature-final-20261103.log": "0a2926297128a0ed3939e13e2fdc8be1ac947191b53f47ac72c01be1ec25f5e6",
+ "storage/logs/scan-retry-frontend-final-20261103.log": "895f1693f9743bfbce28dc5b33525f619cfc07cff66f0ec3213040f9cf075285",
+ "storage/logs/scan-retry-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/scan-retry-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/scan-retry-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/scan-retry-check-final-20261103.log": "1604d9c53237daed95be6db605b7d83b1b0f71fe48c6d44fe71e75048481aa0f",
+ "storage/logs/scan-retry-build-final-20261103.log": "3954997bdbeda8e30ed8d637596df4ce6c6fe8902597748f378f27ece29ebddd",
+ "storage/logs/scan-retry-worker-init-20261103.log": "c8753f2d7dd3a327848143e808c1e23496d02822b388f692eab4f925801e51c8",
+ "storage/logs/scan-retry-worker-process-20261103.log": "a6f31ed2ba97fa0c8fe1e06ee004e035d54faa40de98cb3612df7b75f5a9108a",
+ "storage/logs/scan-retry-worker-verified-20261103.log": "9e0b0a91d22b2fef8e903884218f3f8516888677a0b29b6de1f7876aa1bc7172",
+ "storage/logs/scan-retry-worker-existing-guard-20261103.log": "90f2209ef3e9880d3fc461e17a5b83ee5a1d67556c349af367fb5b7be158def6",
+ "storage/logs/scan-retry-qa-accepted-20261103.json": "dfaedfd21f8de622b4bf2ea8ee172831b631a795e178eb4c3d2e8a8ecf07772a",
+ "storage/logs/scan-retry-worker-proof-20261103.json": "b0f74cdabf0564cf8dca33370ab72b8d4085cc00a11bcab290a72fb9dbcebbdb",
+ "storage/logs/workspace-profile-feature-initial-20261103.log": "710dbcb04c49c91bfbafdff9ffb15bfb13a4656481241b9c7d52928adf38c171",
+ "storage/logs/workspace-profile-feature-final-20261103.log": "d256c45808794f1e5209ac4946e28374509600cb99801b296ae57153f63f1b96",
+ "storage/logs/workspace-profile-frontend-initial-20261103.log": "00b58f85e3f43e12e2fbf92bc6021121b4929a0dfcee382c0b228733e887af20",
+ "storage/logs/workspace-profile-frontend-final-20261103.log": "0d3779784a8c5babcce77869b52fe57539188801836392b605e029d32525cc14",
+ "storage/logs/workspace-profile-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/workspace-profile-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/workspace-profile-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/workspace-profile-check-final-20261103.log": "d752c22d4c752c723185f92bb2e22f54cb297f211fe845fc452c5087ef168b3b",
+ "storage/logs/workspace-profile-build-final-20261103.log": "48ec8ccc289dfd2c463cfa99d461fa047f2bcd7c089553af8076c5eb7f807949",
+ "storage/logs/workspace-profile-concurrency-final-init-20261103.log": "b7abc147e484337609ca6d3d0852b83db63281e92634f037afb5a9abc111a935",
+ "storage/logs/workspace-profile-concurrency-final-holder-20261103.log": "ebc5891a64bdef23eba411f3f7865fdb5026bbfb85bb9e5620cf3ae8a553e5aa",
+ "storage/logs/workspace-profile-concurrency-final-waiter-20261103.log": "25c1f2d94f7e0132025975b71d2836d8a98169aa8b53aa0185a20ade3a1caab8",
+ "storage/logs/workspace-profile-concurrency-final-verified-20261103.log": "a52acb13a8ab1fdc6ffd8ca859775ea7c1357c44d7cb03887e862d335c8c7289",
+ "storage/logs/workspace-profile-concurrency-final-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "storage/logs/workspace-profile-qa-accepted-20261103.json": "dedd179d9dc34aeb55b72cb5bc99d3dae7df8cc0201b70322c2fdbadfb4c48db",
+ "storage/logs/workspace-profile-concurrency-proof-20261103.json": "2fc4b3865f08230be5d5739869fc547c22a7dfbcfd1702ab2109a4202a03d800",
+ "storage/logs/organization-country-editor-feature-initial-20261103.log": "2878de5d5a95e797abaef832933cf5dc5cdceb3c3120491ce213269ff993b497",
+ "storage/logs/organization-country-editor-feature-final-20261103.log": "e1503875a2f703324ef7d0fb47b89c37927d1767686ed871cbf37e6ea14cc457",
+ "storage/logs/organization-country-editor-frontend-initial-20261103.log": "af099ad22efb3e365e5303c5c6c24377db22f4a70fc6531b2c6270c6d569ad46",
+ "storage/logs/organization-country-editor-frontend-final-20261103.log": "8e2b1cc65e4d113b8d0202c5e4071eb0f9235a9e575b164c0f76a2d9c7e5725f",
+ "storage/logs/organization-country-editor-phpstan-final-20261103.log": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
+ "storage/logs/organization-country-editor-types-final-20261103.log": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
+ "storage/logs/organization-country-editor-pint-final-20261103.log": "cd1a94fc2cf6a965b86e1a4809d6c7fb9148b1ee374e1010ed2ac96ff4876ec2",
+ "storage/logs/organization-country-editor-check-final-20261103.log": "9e9d51c6c9f621426d985f3d7bd521fa051f2348e9f51afeb25d6a78e5bff006",
+ "storage/logs/organization-country-editor-build-final-20261103.log": "9a52ae9a4d95d8a81720832be33735a9e88988976945727c606b1dc167f28c53",
+ "storage/logs/organization-country-editor-concurrency-init-20261103.log": "63d93f82c36bed7a46558a707f66d3ad81000487a576751621f346356ff4ad1e",
+ "storage/logs/organization-country-editor-concurrency-holder-20261103.log": "4d5a929380ac4afd88f6a96003c0f1ae86034c405b244f8d44c4f06038781729",
+ "storage/logs/organization-country-editor-concurrency-waiter-20261103.log": "e33c978249d5b5ec3dd5f83a05a1d5ac1d3f50413cd0112e58d7a813635303eb",
+ "storage/logs/organization-country-editor-concurrency-verified-20261103.log": "9f93a21016a4a48e9143e39f01589b5a33f425a84ca49db1a3294e532eddc337",
+ "storage/logs/organization-country-editor-concurrency-existing-guard-20261103.log": "2825be2b7cdc862ec82c456cf4ff035d228d3850dbc94093360cfa697d2a7d1a",
+ "storage/logs/organization-country-editor-qa-accepted-20261103.json": "dedd179d9dc34aeb55b72cb5bc99d3dae7df8cc0201b70322c2fdbadfb4c48db",
+ "storage/logs/organization-country-editor-concurrency-proof-20261103.json": "04a8e8f9ecf86f986f8d6b42feeea405306386c5bc3bfa5b741967979a2441e8"
+ },
+ "prior_code_baseline_sha256": {
+ "app/Services/DeskAttachments.php": "b32af33605c6456fbb8b6bca6aa41eacbbcb49c8dfd4cfad0ca13e3955cac9ff",
+ "app/Services/DeskServiceEditor.php": "dbb87740b8115623fc5b39a9ab656ec5b9cbe1769f26150688597047981191ed",
+ "app/Services/VirtualDesk.php": "0720acf9a543d3d6b55d37dbf22b9b9b9ca9978a6287e9033e64607b9bbd51ec",
+ "app/Services/DeskRequestCheckpoints.php": "6297395ee76f59cf9e1fea78dca7395d7874df1ec291fcf88142d82d98037829",
+ "app/Http/Controllers/VirtualDeskController.php": "02fd98f0a2db58475c1aa6bed9d187572cc2b144d3cd1ae72ae8aafac054d82d",
+ "app/Http/Controllers/VirtualDeskOperationsController.php": "5d451e1efc3a4cf3229d09aba7236b965f8999653d99ea2fe2509d352d2f4e8a",
+ "database/migrations/2026_11_03_050000_scope_desk_document_links.php": "314ce0ef99d06705ebc48e0a568ebd0c6562de6ecee58fc24a4103f260ebd898",
+ "resources/js/components/desk-attachment-field.tsx": "a7a46acec2179d0f3d5086ac2a47f733ef3a81e1e6a1293fff61f01fba315cda",
+ "resources/js/components/desk-draft-recovery.tsx": "0b8059a6ef2a4ba32c702e504bece168718193a94caa59203ddaad4e5c7abe17",
+ "resources/js/components/desk-internal-operations.tsx": "d0ef10cc8e5cca90c071205503892ae70f6e79525ab5ebe709fd7bb1e4a1bc77",
+ "resources/js/pages/desk/request.tsx": "aaabaf77fa9f4b6ecad6650832daa67718502ac54a4b1ff2a082d18dce299dd4",
+ "resources/js/pages/desk/service-editor.tsx": "cec5e1fd7d179a0a8dffc686cedcbd26bdaf127c64b9674a26d10a93f161c4e2",
+ "resources/js/lib/desk-field-values.ts": "67e2633d815452f33e08afd549dce9842fae007d9e8e3cd5aa8b862c7c0bf36f",
+ "resources/js/lib/profile-json.ts": "efb0ac4dcb7836f13418b84aa490ac82c292d27e2f0203b617e433d0739bda07",
+ "resources/views/desk/receipt-answers.blade.php": "d6a8de179ce2ff88fdc7c2e69699194b4516b8c6dffb2fe95c756815d1647fdf",
+ "resources/views/desk/receipt.blade.php": "656b36a885685e271eb909da140d0f0fa60bc43f19aac12649144eacc61abe6a",
+ "tests/Feature/DeskAttachmentFieldsTest.php": "4ce411bc74f891a9dcba5e3db85df53a89854fe365307a8440f5b1fe6cd5ebfd",
+ "tests/frontend/desk-attachments.test.mjs": "71a65bd547c7e085d12b16abbe4e90bcedb25e45bbef27f76b2fcadb0df3d63a",
+ "tests/frontend/desk-checkpoints.test.mjs": "82850ef89203350f93dcb1d90df15d93ce52e6d70ee4914bfcbff44264ae2509",
+ "tests/frontend/desk-request-conditions.test.mjs": "58bb9fd1342a7e63d1c355ddde9e70720984e5b740abbb81c8aa61954c5325cc",
+ "app/Services/VerifiedDocumentBinary.php": "db893aa538ddffa8905dadc7b76130e5c3314b698d87df820d4f73768534708d",
+ "routes/virtual-desk.php": "f708c25eeec286eaada3fbd4c6e3f9cfcb5212774b75749c8c567b37d36a87e7",
+ "resources/js/pages/desk/case.tsx": "f62879b77bacc76d358028052d2d4cd07d6044ba2a77555509382029bc9ef58b",
+ "resources/js/components/desk-document-picker.tsx": "061e80c429bd5acd32a4712fd61ff46d2dc9db16e0a89ed27b920122903c678b",
+ "tests/Feature/DeskDocumentReuseTest.php": "aceb553bb66c6255fd4ae22a470e013391522f0f2a19fb2bd42fc64d7877e4c3",
+ "tests/frontend/desk-document-picker.test.mjs": "2978bc7404b9a5ffc5d8268bffbcd1bd7ba23ca9a99ac05e0532744513eb05e7",
+ "app/Services/DeskPaymentEvidence.php": "272e1c5eb5fd80fa7f68ea7156f6a1477397a14475ffbd6cefb0c75c25c0254b",
+ "resources/js/components/desk-payment-document-form.tsx": "c916cdc591fc8f2feca7c899890c8e6ea207929ff574030da74896ba6e3c7a98",
+ "tests/Feature/DeskPaymentEvidenceTest.php": "4d3e10f0bdbccd005b18514ea25ad26ec58c746739ab4ec3fbeea73d4dcbdd8f",
+ "tests/frontend/desk-payment-evidence.test.mjs": "90b72311e5f1cb5ff9edcf8af6fd21859b522bc873dbaa4961dbf2a241d9521e",
+ "app/Services/Ai/InvestorGuidance.php": "7e622eb288dd49b116165ba614588ede8af854054fe98b07352cab50556611b1",
+ "app/Http/Controllers/CrmController.php": "dcae4c2cfd2b00916f372ed8a92fe6fcac7d87eeaa37d705424635c8ba1f4268",
+ "resources/js/components/investor-guidance.tsx": "a719ae383628319a10f66878734978ac5a9d4b91bd550d6f58b545b52c924a95",
+ "resources/js/pages/crm/lead.tsx": "c6d21432153099cc257335809aff8be27d84b39d8783a69efeb1a467776ee8dc",
+ "resources/js/pages/crm/types.ts": "ef60195e3fde0dc0bfa8a732557be6ed1e78aeb0f2fe45d83d7024b5ca79d2e6",
+ "tests/Feature/DeskClosedLifecycleTest.php": "5dcb368a61c280067c89bf985f4b5139fc9ca69b4fd03d93275fda14a4b808df",
+ "tests/frontend/desk-closed-lifecycle.test.mjs": "c4653a0f6bc38c3134cd7697da2f3bc78a6fcb4040d1ba7df86785c01e329080",
+ "resources/js/components/desk-case-state-form.tsx": "351e0026bd9b94ec837becaa8cf160e53e02b5c7684f34569f43a21a254e9cfb",
+ "tests/Feature/DeskCaseStateTest.php": "c36a2ed81e54556aaed98c5c29ba0b27e3564646572b3de818eed02cbae840de",
+ "tests/frontend/desk-case-state.test.mjs": "83c7acc74bf0c11b1a837993417b652262aa2eaf2c662213b7506ae0ddc3cbb9",
+ "tests/frontend/desk-effective-dates.test.mjs": "7c21af7ef4b345fb82dc8d4b6c0ea20ebf57890d1660fc24ee5fd8bf4321f93b",
+ "app/Services/PortalAudit.php": "a2f22cd4a03d7b6c59f9a952cdff76f2f517d11732848b2e0f24eb3aa1eff6c4",
+ "resources/js/lib/crm-record-edit.ts": "893997bba5262fa73150baf1cfe518b733588407e162dce764608a2aff548b74",
+ "resources/js/components/crm-edit-comparison.tsx": "83475c45bfc482ce8fee599929988bec3b2e535012cf6f35fcdaa20cc391360c",
+ "resources/js/pages/crm/investor.tsx": "074fb67afa6ca1a67c1292633b5ae19314af7611e8026f8b6e89006fb5d67014",
+ "tests/Feature/CrmRecordVersionsTest.php": "552299a01aa10e350f32537c628527a8ba83301d1e3f8d3a0a778a94946e3c26",
+ "tests/Feature/CrmIntakeTest.php": "15968a226f561a3fa65f58a1e9938c4d6666d112eed887864e23890973ed9c65",
+ "tests/frontend/crm-record-versions.test.mjs": "4c70a8a6c80f4fdeb337796c650dbe75bacf353aadde0f9c877088fee9a3c87a",
+ "app/Services/DashboardWorkQueue.php": "2537f8308d41854346ec5a0b5a5f2f15db0cc8df958770715773b2bf8204aaed",
+ "app/Http/Controllers/DashboardController.php": "ab0e38715142e2aeafe35e41027b76590cce57d0fc29769a8fe0222d9c0203a4",
+ "resources/js/components/dashboard-work-queue.tsx": "bec9cb4c9fd89096550e160f15f503a301c080edddfb7ad6a682757555c1ec02",
+ "resources/js/pages/dashboard.tsx": "3dc33beca65113a9f5366d9991809d9db4e0475294e69079ee2ca067f1ba29f2",
+ "tests/Feature/DashboardWorkQueueTest.php": "c2464fbbafbc71d76348028f0a8efc3347403377254da98b9cbc205cb71c44e2",
+ "tests/frontend/dashboard-work-queue.test.mjs": "d3fede52794bd0a2050df2450dd9f0ba9a591fcf121159eaacca3671c68fd630",
+ "app/Models/CrmTask.php": "030a96c7b1c04d13323c801ee6c1e585df676c9497c5e060ca7f798c24ecf068",
+ "app/Services/CrmNextAction.php": "2b3a29d2aa7124759a8a5490d701facf627fff22b9b3373792869cc7c09e1335",
+ "app/Services/Ai/AssistiveRules.php": "ddf3ee6807318d7bd6245131a5088273a8c7aacdf94546a5880975e00461451b",
+ "tests/Feature/CrmNextActionTest.php": "1f6ab9b9e962703f1b39a6afedc97306b5f417d52b5dc4e36e84c2561b407015",
+ "tests/frontend/crm-next-action.test.mjs": "e73dfab5180f7678951954b33fc6dc1404f509c0ae331590450c42f808264e6d",
+ "app/Services/PartnershipExchange.php": "1a1aac0f52f40442616dcfbb5cf265eb8c40d5d90bdca7311120c48458047d89",
+ "resources/js/lib/partnership-edit.ts": "77ed9f8a13ba0d0dd6727e455b3ee4d95fec0189d7dedeb132e65ddb471cf479",
+ "resources/js/components/partnership-edit-comparison.tsx": "cfa8fced76a23b083501eb587fea5e656e3312f5717614649b1431d4f7201ff1",
+ "resources/js/pages/partnerships/editor.tsx": "ad2003f809565db1ccf379a545603cceb4cba39162cd96bed53bc051c9a5ca62",
+ "resources/js/pages/partnerships/shared.tsx": "0fcae6a208fd03f0e242d84bb383ec5708d50684de1fe534139e12df8ed4dbb5",
+ "tests/Feature/PartnershipEditingTest.php": "bb193dc43d1d9e6ebe05f77fa10241882a20ef021e9cb6147a04118e74eb4ed3",
+ "tests/frontend/partnership-editing.test.mjs": "d1721b9078e44881076ea35c318990b118dc85fdf1d3d401ff41ec8fc2a45b10",
+ "app/Http/Controllers/PartnershipExchangeController.php": "ef0a95b781c61068709055409396bf864f4a414522c0ec4e18a56a006cd51a3e",
+ "resources/js/pages/partnerships/room.tsx": "4b4a72e7610aa4ed4f681ab736dd07f707afc43e6dff257a01fdbe423968cfa3",
+ "tests/Feature/PartnershipParticipantsTest.php": "a72868b417030e45dfd0dc405304e64ff0bdb7d52218729171fcb10c163c4cce",
+ "tests/frontend/partnership-participants.test.mjs": "092037c0b657bf42d1dd18f6b3e2f7b8738a7eece6b19d202c13fb2dde4fb1d8",
+ "app/Services/PartnershipMilestones.php": "301acc1e5ad8d267f5b754a5414b86a1f81d3bc901cf191fac5384807c39c94c",
+ "app/Services/PartnershipRoomUploads.php": "c8730720f1ea305667e6da4973e22d11f73dc7b011658bbf00fc64855c27b4a4",
+ "resources/js/lib/partnership-room-edit.ts": "e1b81b752bb29f8b47599cf8f108ee7a329889160054f64443eb1f586eff89ca",
+ "resources/js/lib/partnership-room-delivery.ts": "5709d9558c51be63ed5b482b708a8ef431636959c2a0919d6c8bd4212ec60c64",
+ "resources/js/components/partnership-room-comparison.tsx": "c3a63bfa39aeca9cddf58cb1d09521841e280b84332fa06f6dc5012d97a1561e",
+ "tests/Feature/PartnershipRoomRecoveryTest.php": "92e1056f698d805caa3bbb16609b83932181874c0403a220df17b5fc7c1aae36",
+ "tests/frontend/helpers/partnership-room.mjs": "61aad03fc00f19ef28c676ce934516739ca97a9bbcc032882a318867bc0319ac",
+ "tests/frontend/partnership-room-recovery.test.mjs": "9ef4bcb7b539523157e951d1bed9aaa661dfe3b7a61f223c60cf84e5fa202aac",
+ "app/Services/PartnershipCandidacies.php": "99d10782066d67735648238663d371e6a76bc8268ca69cd882db4e7a71ed7dd4",
+ "resources/js/lib/partnership-candidacy-edit.ts": "7f768a3c5e16f63c0f2d68b69d9f86ff7458df76f6f786602961e2dc620cf226",
+ "resources/js/components/partnership-candidacies.tsx": "d48e841cb90f67cd21a5652c3c170dfd7e47d7e680dfa95f57123268b08c4da2",
+ "resources/js/pages/partnerships/detail.tsx": "94ac64a8623af9708a53f50435d629e8f8ae18bc5441d40fcfde32389d49533c",
+ "tests/Feature/PartnershipCandidaciesTest.php": "5e4691580b89722eef426c492a90a27be009c07b6ee5114dc814495ed913288e",
+ "tests/frontend/helpers/partnership-candidacy.mjs": "7c1e022803876db3c3b520f65d4536bde822c04e7dc85079f8a09211a1bd7b51",
+ "tests/frontend/partnership-candidacies.test.mjs": "d6850e6fe55d53195080b84113e4b8ee350fa7a10a14a0edf002b60fd3ac7f68",
+ "app/Services/PartnershipCandidacyHistory.php": "abb7216aa0f83105aadf35e2a05cb195aee6ea11a1d37c5dcf521dff99b4b330",
+ "routes/partnerships.php": "fae636a4f0c8d1e8433efe1bb230ff69128d2a671ddc0e64a01c322a30631ead",
+ "resources/js/pages/partnerships/interest-history.tsx": "595ae4a9077363f5d569fa466d896d108e00ef912e3ee667e9bd79e8e51d8426",
+ "resources/js/pages/partnerships/dashboard.tsx": "51a69176acfdbf43339047782388bb308d5e07a2b41da584db4e22bcc2e0bffc",
+ "tests/Feature/PartnershipCandidacyHistoryTest.php": "db684ace5cba2e9a72c9ae04e9ad6d3974984bcce3f4f5895029bea11daaf26d",
+ "tests/frontend/partnership-history.test.mjs": "c7321917b0309aba105875cec4c246cb7b5e6388e7e0dc4cd3b9d513c10ed492",
+ "app/Services/PartnershipNotifications.php": "626d3beee0352430c30bc86b7714714478020fbe2dbc2ee87e2156e7c8260f33",
+ "tests/Feature/PartnershipDashboardPrivacyTest.php": "82d2ccbe43b5326de91c30fc9ded0317310b22b1bb876509a4ecf0bbe22bcb10",
+ "tests/frontend/partnership-dashboard.test.mjs": "69306fdc7b292ee0ae74ee32fc48ff24f28f23b84dbab746436221b9a88d3a8c",
+ "app/Services/PartnershipPublication.php": "3e9d6bafd771cb56ac0a58af55014e21913eab3b2e72f9eaac9c2ea0d27d639f",
+ "resources/js/lib/partnership-publication.ts": "582e01c9fe00dea0833c35b8add91265d92628a9a8550ac98ad2e0f9a3883a23",
+ "resources/js/components/partnership-publication.tsx": "aa5185cd93a79f9a46a0b942d2179f315346647bc2940fa2f85638d0878c9996",
+ "tests/Feature/PartnershipPublicationRecoveryTest.php": "fe7ba8cf0b15c1602b8f013a0f1049c654bb7d64741198fa43e2d0d893dcff5c",
+ "tests/frontend/partnership-publication.test.mjs": "38dc6c397ed7f6e3aaadc341aa68b33b777942ff4dc9b68264c90c3cadd87000",
+ "app/Services/PartnershipPublicationHistory.php": "a5797c73ba743a944a2e256c12020ca801d384644ebc775a5012cf38eaf01379",
+ "resources/js/pages/partnerships/publication-history.tsx": "0731fad86332a6a4a984c4927f49fcd09119e0fa7a67cb89084a17640e3a5763",
+ "tests/Feature/PartnershipPublicationHistoryTest.php": "66795493358397695a7c9a1c703271f3b96dd5749142d6d9c4115c6a3179b956",
+ "tests/frontend/partnership-publication-history.test.mjs": "c77f9acc3e0116b4d746ba6779670cc91b8d1f882c8ec8753cfdc026af64d723",
+ "app/Services/PartnershipDraftSaves.php": "ffcf93eee26142287904ef32610aefbc37a822aac18af0ec22fe49404fa9c633",
+ "tests/Feature/PartnershipDraftRecoveryTest.php": "20403433ae83deb3ec6fe719f8c75c036901610bf4b179613e29ae7317481ac4",
+ "app/Services/PartnershipAgreements.php": "4f034f2fc5ec6f374a6af1bf5dbfb1086c9b52477c90a214860bd8fc43e00bc2",
+ "tests/Feature/PartnershipAgreementRecoveryTest.php": "a46ae9001d9b6b7eae21f027ac0fe22365fb81fef916e3edeaecaf3b704544ef",
+ "tests/frontend/partnership-agreements.test.mjs": "7a5a140c0d1b3b2a9c59cf37ce549d72f4595d04b40f8514a42c39b12881751e",
+ "app/Services/PartnershipAgreementHistory.php": "59892a9d0924e1a546798912a2bbadd7e12b97110eba77b5f42df7d174f14f35",
+ "resources/js/lib/partnership-agreement.ts": "c21a38c7a06839e03ce6db9b6f32868b9795c5752ca89ada56ae4f4ab33ae2b2",
+ "resources/js/components/partnership-agreement-instrument.tsx": "d79e757df3d552f087b64bfbcdfecd08bbb11a0e636591bd1463f7ceb0501a7d",
+ "resources/js/pages/partnerships/agreement-history.tsx": "ee89ff89773f78d9ba410035554cb33710e63ebe9acdc4015ed7acf9b27800cf",
+ "tests/Feature/PartnershipAgreementHistoryTest.php": "0fba808950ca49363d2b090782c1bdc516ab54fb6ba65536a533eb88d12fd41b",
+ "tests/frontend/partnership-agreement-history.test.mjs": "a44bd2bb6977a167abfbe5eb68702a4d9903253f0544260ff7b8ab93d53ec0f5",
+ "app/Services/PartnershipAgreementProjection.php": "71b91a05fce2163db4e30f5ebea535ef28325e4264151dd29245693e205e0bdd",
+ "tests/Feature/PartnershipAgreementProjectionTest.php": "b4768ef6e441c706e372c2268df6718634a8333ee84321ffc93e5f012d796a80",
+ "resources/js/lib/partnership-history.ts": "37d1ef9b02147e4e28d8030d85d9970d3badbac7bf5909d0f0d5cbab8ef4d2ca",
+ "resources/js/components/partnership-publication-summary.tsx": "a7bac1e16cc4b75e54d31cb36593ab2e85bda56ef858990f3b5bb0572ae90322",
+ "tests/Feature/PartnershipPublicationSummaryTest.php": "b41fe778886699a26e5e86f57f4b1fb0baa94d676cb4140fcb0ed48d2537436a",
+ "tests/frontend/partnership-publication-summary.test.mjs": "cfc4ba190a44fcb0d33a22a36bfc0a7488d960ab0981247fce9b66556b4ce282",
+ "app/Services/CrmTaskCreation.php": "64818262b50a01b82da0f8e8dfac62e43dcc3f1b0e587d34f70fc5600a05321e",
+ "database/migrations/2026_11_03_060000_crm_task_creation_commands_index.php": "c117bbb886c195434aa193bd52e702f217fa02ab140bc746c22860122f8f686e",
+ "resources/js/lib/crm-task-creation.ts": "d91b0b4d058b835978ecaf031f06024cc9004330ec366ce612e7d224b40c2f69",
+ "resources/js/components/crm-task-creation.tsx": "f7281182ec967d51149cc73df51a8d9c0f5d96c6145ed9605261b43db20ae722",
+ "tests/Feature/CrmTaskCreationTest.php": "f850cedebe31577bb2749599e3f69f0d2516c1b7fd936eb968b52da25df90693",
+ "tests/frontend/helpers/crm-task-creation.mjs": "d22f7abd199043492e4c34d2e68a1e1204cbab193c7a151d242e8c6ea68dba04",
+ "tests/frontend/crm-task-creation.test.mjs": "ef3754b0bebe6d431a40b620e8f4cf10ed0a80d00038bbc4cf5de4c25cf99975",
+ "app/Services/CrmTaskPreparations.php": "8963dfac5214609dd8cd529890e9b87b76deda151797de02953fb47fc60fabc3",
+ "routes/web.php": "5f83d30124effdfb273813dbd9e11f025a792fe23018c55b7edaa678f5347c4d",
+ "database/migrations/2026_11_03_070000_create_crm_task_preparations.php": "6b8b0f869adc1a4067a862a3ea1cd8cf1cb1fd2aa854541b7a71ba839127a6e0",
+ "resources/js/lib/crm-task-preparation.ts": "1a6e15a4379a83f75c9f5e73e36703a352f373963f39e49a1d004aed204f8e54",
+ "tests/Feature/CrmTaskPreparationTest.php": "05f1e12d70edf475abe6ef79dd6013b52485811ef2afbb3b4fb71b95f8a6af83",
+ "tests/frontend/helpers/crm-task-preparation.mjs": "565347b7cd918d929023eddac6130d6ce625f2d3d61a6897597de1f7218d3706",
+ "tests/frontend/crm-task-preparation.test.mjs": "57ed56de9beb025c8ad9ae18f1d95edab387b6ce1f06a5f0da1b3d9d63908216",
+ "app/Services/EducationAccess.php": "7b18bf8ecb93b5f233df61b50e0802ea52b7097eee81ee2b16690cde5029a4a3",
+ "app/Services/EducationReviews.php": "27d4319fac542c20605a9ad46cf2749ffa52f42bec411cdb67c9d34d94731d70",
+ "app/Services/EducationWorkQueue.php": "3e066d2ff0af23908bb4dff173b0179574e1f8b50069ceef16244fb00e5a150d",
+ "app/Services/EducationDeclarationDrafts.php": "6d2fc47d8c5dda38ec462b98a43525f4e0b5f50b065f48c0b1089003e75bb320",
+ "app/Http/Controllers/EducationController.php": "8381edb521c2be12035cd320630148053a6a158bef7f704e56505668fc1e96f9",
+ "resources/js/lib/education-review.ts": "f5b7b3f782e53f86614e6788297373562d0266ea4734d4f6f0ce21331f1263eb",
+ "resources/js/components/education-review.tsx": "016cdfd9304e077e236dd2bcf0676f75265780777fd50db4eb7f07d16b339aa8",
+ "resources/js/pages/education/declaration.tsx": "b147c284fc75f2a9131bea7b1c6dd66c9d35f4474dfcb08f0e747ee7d9f5bd3b",
+ "resources/js/pages/education/index.tsx": "4dc787065f2200fd37e1c559ba200ba922253f057dc146e03c81010e4dca170e",
+ "tests/Feature/EducationWorkQueueTest.php": "15362ff006c3fdfa1c48ee4e01c9da67a2797aaf82480a7a95e1b20ebd432f2e",
+ "tests/frontend/education-review.test.mjs": "e57353fa7f2d3311e6bf4864f322c7292bcdeb95299891e8e736e8803e09da1e",
+ "tests/frontend/education-work-queue.test.mjs": "d6dabade28b8a22b41b237ca775ece4ad212d9aabb49cc9fc615db3e1ba8f4a1",
+ "tests/frontend/helpers/education-review.mjs": "0b9cf596d1439d37a0fea7fb19d837f04c13622bbe8e04f346f46b1e160bd0d9",
+ "app/Exceptions/OpportunityWorkflowUnavailable.php": "85afbdd37aedf98ce790a84e0cacd450449a9abde0b160d0c82e38f8004efb67",
+ "app/Services/OpportunityTechnicalIncidents.php": "f4a2d9e3cebbff32b4179755beb478ccb4308a5bf2847ca5c02c1f9ed4509c8b",
+ "app/Services/OpportunityWorkflowExecution.php": "71106a9e8301470017b1acbd36d6fa2c293b02e21a4b7d926357dcc598fe24cd",
+ "app/Services/OpportunityTechnicalSupport.php": "42726cc86061ddefcf69c8703cbc5b0d0ac6e2658cdcdde98331223dcbb12d58",
+ "app/Services/PortalProfileAdministration.php": "cae57b49f2e1c8ac5ef88ddf8a809f4a0bf243e138aa14d9576f0368c9534282",
+ "app/Services/PortalProfileAccess.php": "082feb1260929da484c4e82f9a3b51e342366042f2363f1b2f78952c1661c538",
+ "app/Http/Controllers/PortalProfileController.php": "84b75f7948864169f7cfd0b3d95f1f087690ee4ab74c54204182072de0b3b05c",
+ "app/Http/Controllers/OpportunityManagementController.php": "088770c1765583b6b3a62772603c07aaa946d5d7560a9cb12cc801371162069f",
+ "app/Http/Controllers/TechnicalSupportController.php": "12cfe77a41958b114080ca5447b2a12999ba2c571936a2d4b91865b5340a50e9",
+ "database/migrations/2026_11_03_080000_add_technical_support_profile.php": "8d21f79c986cf80d77cf5372d9a9c58413cfb696a907d8a4abe5e1625ae2f87c",
+ "tests/Feature/OpportunityTechnicalIncidentsTest.php": "125cacab79b6f2497468d6e453e71827205db88fd711c47add1c3d568e4f36ae",
+ "resources/js/components/opportunity-technical-incidents.tsx": "5c306084dd845266676511a36f47392ac3e9df47ea9d99995eae9b20892ba83e",
+ "resources/js/components/profile-navigation.tsx": "5f6bf0e28856dd1a56af2f98095d2014bd689eb8981363e3e2cefd4829447a47",
+ "resources/js/pages/management/opportunity-draft.tsx": "cde3f3a3e1fa63adbbaa7e63c03e1a7ddf21bd48ba1a8a69ab05ea7e86c64c11",
+ "resources/js/pages/profiles/administration.tsx": "3e1cfb96045525117fb9da912fd2c5daae3caed36cad666207081a41cd23ade8",
+ "resources/js/pages/profiles/technical-support.tsx": "6a3b25328b24d89476ab4208ca0ae5432bf694de6f9c833ae8a116f76c76f4ff",
+ "resources/js/types/profile-access.ts": "501d6eaa9719ffa6d73973587b19b1de59a393c88274faca7c74217380204ee5",
+ "tests/frontend/opportunity-technical-incidents.test.mjs": "c9b5ee7eae3392ace105b9e671aad973cf4b5934a633f3803a66020d825ece60",
+ "app/Services/TechnicalIncidentHandling.php": "65827356a05dfc70a8aea9fc488a9bd5f37e718ca283e6ae49c7ad26e18ab03e",
+ "tests/Feature/TechnicalIncidentHandlingTest.php": "e4436a1a3ba6ae9e917c781a49cbb8d214874d5c5ab98903e2c3c0637272c8a9",
+ "resources/js/lib/technical-incident-handling.ts": "a484ee08102e9efcb0e4b8b67ce1cdd6e20aac8f4ea7cff28d3ba746bc637d7e",
+ "resources/js/lib/technical-incident-labels.ts": "2d05e03069eb8fc8c590d790f8d0b90f32f56a3aa69f2b683e8d6d0bf6d1569c",
+ "resources/js/components/technical-incident-handling.tsx": "d1f15f7d38897250e71d3a7a54359545ce19a21f67b75f227ebe0a673130a819",
+ "resources/js/pages/profiles/technical-incident.tsx": "ba1cb12972cc6424dab7404c69d43aa933abc686dbbea852b3538ebd16ef1b8a",
+ "tests/frontend/technical-incident-handling.test.mjs": "412ef6f0da01439442b5325f61748456bbe0cb1bf40dfdc99d5fea977377aa1e",
+ "tests/frontend/helpers/technical-incident-handling.mjs": "23936d1925d2623ea034fbf9d13d0cc467b819df1fb67ea4cce0a373dff571e0",
+ "app/Services/TechnicalSupportProfileSchema.php": "c5b062141880aad2356cfbfb258ba0484551da8b65f9d8f625ba702dc4e35816",
+ "app/Services/PortalProfileInstallation.php": "d6f7e54712e4d15a3b1f9783c154ad8a7ca5a58372d7d703e2fa9a5a755ec751",
+ "app/Http/Controllers/PortalProfileInstallationController.php": "e15a5fa9045c28e2e95a327a5af279744d5f0db9943ecf3b0e02e8716c5c808c",
+ "resources/js/lib/page-preparation-guard.ts": "7bfb0e2e066eb8c3f345d7ad41c6ac0423a96d8ba3f2cb3b964b37a2c9d836eb",
+ "resources/js/lib/profile-support-installation.ts": "01172f840dba706dcf7f9d89cb4b6987118bf6ec39321bef870e73916cbf1143",
+ "resources/js/pages/profiles/support-installation.tsx": "d9dc3f20786bde0467e02be7b05a415848412d8cd71f05a640d11270b3155823",
+ "resources/js/pages/profiles/installation.tsx": "5bc40ee0955afa35bd245359f68d5b108008eb2169a7d78da6aab610d1a533b2",
+ "tests/Feature/SupportProfileInstallationTest.php": "eda89fb96bdbb475d0e438e64c524b700fda551f2602d743f55560e06cbde87a",
+ "tests/frontend/profile-support-installation.test.mjs": "ca3afe77b5c051683bb4671b56e8af33e2e989a6421b29ab09286af7a8566b97",
+ "tests/frontend/helpers/profile-support-installation.mjs": "951ecfe983d975ce7fe0bbdef6fe06026e9f16b465d72d17f53722043d73fdfc",
+ "resources/js/components/technical-incident-notice.tsx": "612db81b83bc419eb1851838a41482430a78b9d4911adc5ad8cdafcf23ee266e",
+ "tests/Feature/SupportIncidentNoticesTest.php": "d2e4327bbe55daa30e11774372fb0e356f222ae045df96c72f332106c5fafd21",
+ "tests/frontend/technical-incident-notices.test.mjs": "5fca0aae9e1408f8ad5ad07f7b86348856e15aba768ba069f28183c8c949a101",
+ "app/Services/OpportunityTechnicalExecution.php": "cefb077d0f8f767c764672e164ec67dd011932b2ab466ce955bab46cb290d147",
+ "app/Services/OpportunityResourceFileCleanup.php": "a946314b6753c5da07b58e7b60fe46651dc5744fdbc4b9d6036629eee3ab7340",
+ "app/Services/OpportunityResources.php": "20975150c4f425dc3a59985aa3c94cc16b5f1469a49af5babe4087a4b364d8f6",
+ "app/Services/OpportunityImageProcessor.php": "6275b72070afd7aef902f1e0cb66675b1e51739321df5fd1b17eb84c382cf711",
+ "app/Http/Controllers/OpportunityResourceController.php": "48b8b547ad701bf31a01c7b5cbfdeb2900ef7b907f88d0dc2e487a69d17b4c8b",
+ "resources/js/pages/management/opportunity-resources.tsx": "74fb837959010b5b1919de4d24474aed5dd395c76d44b0d87cf6006dc272978e",
+ "tests/Feature/ResourceTechnicalIncidentsTest.php": "ac06121cd8f43844de27ad565f9d986199b2a3b9c7bb98501c1c8b14b8e8b684",
+ "tests/frontend/resource-incident-form.test.mjs": "814854c628d5e7c1704617bdb70b69d68e25abcf38db3f01505195f81229e49b",
+ "tests/frontend/helpers/resource-incident-form.mjs": "aa3ec4ab6fa2f53bab901d198838ab0ad568bacba0998d58243a15d0eaa8718a",
+ "app/Jobs/ScanDocumentForMalware.php": "7c9e3e8b55a3b635b39c1834953184dd413aacdebf5a5d7a29cd3b35a8b6055f",
+ "app/Services/Malware/DocumentScanAttempts.php": "55ea55ad4def90e6244fd64d49b3492c2afaad60788af8c7faa542cd4bfede65",
+ "app/Services/OpportunityScanDispatch.php": "cb0e80cd69d0052a4a350d1d19283e2f6a7a19511b753920dc3f0a5894d9969a",
+ "tests/Feature/ScanTechnicalIncidentsTest.php": "6eb53d7f0a0c6f02968229e10473f9a2f3f5e9b3a11ea4a6aa4d7a1f7775d153",
+ "app/Services/Malware/DocumentScanDelivery.php": "d34bef072621d88d49588e7498a9b5f4a881f438d259d868fa97dd91eef9e061",
+ "app/Services/Malware/DocumentScanRetry.php": "ddac00577280355c51c8345ec53e0805e75aacb7df0b183b9ef7a2507d5b5216",
+ "app/Http/Controllers/DocumentMalwareController.php": "0a6f88460a214185ed53b5e2edc1fd955d2360e3c5888a37c4831abab84d2fce",
+ "resources/js/pages/management/shared.tsx": "fd61a937262dc62dfb08b1122a1ed2f442109728ce1738eebc92ad0f57906e77",
+ "resources/js/pages/investment/zone-attachments.tsx": "e1e64cdea70aa668ce39056f0b1a08c349b583418c303ae205da33f5bee9662b",
+ "tests/Feature/DocumentScanRetryTest.php": "574c86d9a4a93c6226a0dcd37baa7da8cec1989f72fa72db90f8b1fa6d564d13",
+ "tests/frontend/document-scan-retry.test.mjs": "27e4df0b31622d8d0c28e37511e98579c44bf47b48d88ac6a62055f521fc7937",
+ "app/Services/InvestmentProfileCommands.php": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "app/Http/Controllers/InvestmentWorkspaceController.php": "b4a5ffd723fb00d6a3a7b376f7c99e334ff4d1c8a1a3cba5aed1e299e757dac6",
+ "resources/js/lib/investment-profile-editor.ts": "54f2f450130c09533e85615a3f1a4959cb079c087ea7a306333e9097456e5f2f",
+ "resources/js/components/investment-profile-editor.tsx": "d53714731f456d10ff65b8886edaada3f79361267389c6d7ac7bcbc3fce88885",
+ "resources/js/pages/investment/profile.tsx": "8bfb74247596fb0767869a8bd007e8453e959417ce218ba4d7fafbe68aa913d4",
+ "tests/Feature/InvestmentProfileCommandsTest.php": "515564e26321c449427b114ad7b009519f774f0a8443f2aa1997b6fd636971b5",
+ "tests/frontend/investment-profile-editor.test.mjs": "3fe4f8c527f15ab10c96328a16049ee7ad42c539adeb5c16b973de282d480b8d",
+ "tests/frontend/helpers/investment-profile-editor.mjs": "be40b797348c0488d158cade713599e1db31c0a7deaa3f8e063eea02ced3e084",
+ "app/Services/OrganizationCountry.php": "7c41807102d9cf8dac11f6a438b2c3fae079543d6b1d3bc245996ced5bb517c3",
+ "resources/js/components/organization-country-editor.tsx": "6e280f7a08a9d1632cefac977005be1d5e8e48fe6a5ff6b09b880e5ff0dfa15c",
+ "tests/Feature/OrganizationCountryCommandsTest.php": "4aa127bbed6b735ffd0df11f0237411dee59793ed219f48ae66ec757bcd6709f",
+ "tests/frontend/organization-country-editor.test.mjs": "2c626f14ee55c8c43f91d2505eb8fcfc1722d5e54cc0b1788574ec936eb66c63"
+ },
+ "prior_code_deltas": {
+ "app/Services/InvestmentProfileCommands.php": {
+ "previous": "cd776486e89c7973a6465f72e25453b085edb1811fc1c334d8459543a3554d8c",
+ "current": "618575ebbd92a091b5b698879524909b997bf2dc036209733593fc96a2139bcd"
+ },
+ "app/Http/Controllers/InvestmentWorkspaceController.php": {
+ "previous": "b4a5ffd723fb00d6a3a7b376f7c99e334ff4d1c8a1a3cba5aed1e299e757dac6",
+ "current": "5467100057507b1eacb0480c5e415371f6d921229e2974fcab1d8d3270e8124f"
+ },
+ "resources/js/lib/investment-profile-editor.ts": {
+ "previous": "54f2f450130c09533e85615a3f1a4959cb079c087ea7a306333e9097456e5f2f",
+ "current": "eec551780b8ac4a75253c6144fe206d3dcc776381209b4b412562e0d16317143"
+ },
+ "resources/js/components/investment-profile-editor.tsx": {
+ "previous": "d53714731f456d10ff65b8886edaada3f79361267389c6d7ac7bcbc3fce88885",
+ "current": "33289a039394cf238880225acd4f0d3dedec966eef535bb96987f3296b238495"
+ },
+ "resources/js/pages/investment/profile.tsx": {
+ "previous": "8bfb74247596fb0767869a8bd007e8453e959417ce218ba4d7fafbe68aa913d4",
+ "current": "fc10d0c4f73c3eb9a0a144f4b5e078eb43324b9b49e96401314c2c3378496d09"
+ },
+ "tests/frontend/helpers/investment-profile-editor.mjs": {
+ "previous": "be40b797348c0488d158cade713599e1db31c0a7deaa3f8e063eea02ced3e084",
+ "current": "5fbb8132c85aeb6b880a4dcaa58d12c815b38b0037ef137def92f428fd646bab"
+ },
+ "app/Services/OrganizationCountry.php": {
+ "previous": "7c41807102d9cf8dac11f6a438b2c3fae079543d6b1d3bc245996ced5bb517c3",
+ "current": "a703b8b5db5229ee1d2dacd3355c5a8613d0a37f15175d11b4104c9a6652b250"
+ }
+ },
+ "build_artifacts_sha256": {
+ "public/build/manifest.json": "b48b8589eb07f82b8f3fedcd78bcc1ee4f166c0c3f620a074c61239ebaaf0bb4",
+ "public/build/assets/app-RYZbWMP8.js": "1d4e4a7e11c116bc05bb55bb1d954f6d0fc9687b42ac3f799b27e182346e47b8",
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "public/build/assets/dist-BRfsww6z.js": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "public/build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "public/build/assets/dist-BobFCjoG.js": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "public/build/assets/dist-qw3FPjRO.js": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "public/build/assets/es2015-CxBLTPXy.js": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "public/build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "public/build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "public/build/assets/opportunity-resources-DQpYK7zJ.js": "6477b1195b32d23e8976d928c6cceaf1481ac112a74dfc96db84fe497659fdea",
+ "public/build/assets/investment-territory-DuB1XAZj.js": "fa141b34f46839fb74942120521da58a4865b6f6f249ea1c4c35e1996bdf7ea4",
+ "public/build/assets/search-state-RHLy6yI7.js": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "public/build/assets/shared-B3p6474N.js": "49bb2b7d692ddc584ebbedf59a1da0fbece146cbef42d01af691e8a55bf4e952",
+ "public/build/assets/territory-geometry-preview-C8upfWSJ.js": "4ecb8370c77bdeb377f010f87ebe75d84335e45a201e81f95034597c47103e7e",
+ "public/build/assets/interactive-investment-map-D5PzJo0v.js": "00f8690aca83c269445cf547d756ed72751ced317cbf22fe5395bbea60bed195",
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "public/build/assets/shared-B-FE4xRF.js": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "public/build/assets/content-management-entry-C_oY4VyW.js": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "public/build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "public/build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "public/build/assets/opportunity-draft-CtWZvabG.js": "74900f3032e06390d7c2c6823b962c4c42ac41f31ad389c1bbed768dc2a7e7cd",
+ "public/build/assets/input-text-BlEFHnL-.js": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "public/build/assets/profile-json-LwabPZWt.js": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "public/build/assets/opportunity-search-filters-UNNqYsx-.js": "4e12080f95f399bcae63b440b0e02785442b08a2e46d038832017ec8fea825e8",
+ "public/build/assets/proactive-investment-CYz0tbgM.js": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "public/build/assets/manage-BzsCf6FW.js": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "public/build/assets/zone-CtbkCeDl.js": "8cd7c7c46279211f073d90b0d88e61dbecd1ef2713069ceb839e14d7d148432f",
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "public/build/assets/investment-map-panel-xSZVcH3I.js": "289afcbd59f03ca977734a8e780b899927eaec7f8667c5782baceacec15dd701",
+ "public/build/assets/catalogue-investment-map-DcnxdlZ4.js": "6d9d0fd7ed5dbcadf8c720cc06796bd3a98574dd0041749755505931adc1dde7",
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "public/build/assets/zone-attachments-pUK5x8xI.js": "13f4d709a0c1c1568f588c488f3f895de887a30232b4c8cfff9398fc2273ba46",
+ "public/build/assets/zone-map-BKgh7dcX.js": "cd3c1b1304eb6a7ae04604fb9b2e5e604f28cb231c86327beed9c71b87b9441f",
+ "public/build/assets/zone-relations-Baw14zHF.js": "39cef17489216c8d52142f3cdc99e3a05221210502b6ce4cad40141fe3aecde9",
+ "public/build/assets/catalogue-context-0cqK2kfq.js": "0c3e444963db46a8b8d517c789b1825f2973c61b85cc62f7e42257a4c535ecbc",
+ "public/build/assets/profile-_km_Pvg5.js": "9dff408692d0849d32699ee0521d7ef3f5d1fba1dc89c413ad42285c86644302",
+ "public/build/assets/portal-api-CpQBRfcu.js": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "public/build/assets/country-select-4uP5BvMf.js": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "public/build/assets/installation-B0nI9WAi.js": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "public/build/assets/support-installation-3F6rIOG2.js": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "public/build/assets/technical-support-CpP0Ki7O.js": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "public/build/assets/technical-incident-CYL9UpWe.js": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb"
+ },
+ "prior_build_artifacts_state": {
+ "public/build/manifest.json": {
+ "previous": "153438bc5dd39813a55cdfae33ecb3789802e467a83404868467ba1a4a8ecf23",
+ "current": "b48b8589eb07f82b8f3fedcd78bcc1ee4f166c0c3f620a074c61239ebaaf0bb4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/app-BwqXO-kt.js": {
+ "previous": "e7a76d89a3d143c4533669406e40473e393460484c7245d3af0804bf2087997a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/rolldown-runtime-Dd_uD5pT.js": {
+ "previous": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "current": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BRfsww6z.js": {
+ "previous": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "current": "1b5218b53553fd01fd50cb0ce2102864c5359d450d4d71f00806f812f1e1870a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/jsx-runtime-BpzPEenQ.js": {
+ "previous": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "current": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/compiler-runtime-sKsOXjDo.js": {
+ "previous": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "current": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-Ddn_hEUd.js": {
+ "previous": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "current": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-BobFCjoG.js": {
+ "previous": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "current": "e1048a2479e7f5ec8e825051cf0e1fee004fea1b50794854e15dd80e456a68c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/dist-qw3FPjRO.js": {
+ "previous": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "current": "b2677db930997afabb45d321e11af857589fff1929b21d8ac67cda90f415f5f3",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/es2015-CxBLTPXy.js": {
+ "previous": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "current": "26b191d9dfbd4195f5d78ea298707452cc1c6747a054c60dfcc9bbaef4ac1096",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/utils-CCDJ05Ll.js": {
+ "previous": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "current": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/createLucideIcon-oMeAlXbs.js": {
+ "previous": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "current": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/wayfinder-Dp7PqxvV.js": {
+ "previous": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "current": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-resources-CSDk-OYk.js": {
+ "previous": "0e263792b1aa23267e7e3599b316dabb23db99cc132b1e0fd639f6d80065bfe1",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-territory-BTAmsxbu.js": {
+ "previous": "c34d74d9b88a3956537e3dccebbb1e72e55b1bb5253d05587e8403d00c922e10",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/search-state-RHLy6yI7.js": {
+ "previous": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "current": "166ecb1e2117abfa784a555d7461fd672182eb12153b87087b27cb5eae6ce58b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-CpMjXVgs.js": {
+ "previous": "cae8a225d7edeaed9857919ab35ddc5d4024fb0dbd2a37fe6a4aeb8085be83d8",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territory-geometry-preview-B20FuvJI.js": {
+ "previous": "70b84fbe19bfc78c37c28152c7954186414fd5db5eaede18dc85469fdbf7ebbb",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-Ctkdk-9k.js": {
+ "previous": "eb205a42a51016cd1e7fd8a57dd8782534f5c670dbb9673ebaf12e1073e63505",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/interactive-investment-map-1DTFk8zz.css": {
+ "previous": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "current": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/shared-B-FE4xRF.js": {
+ "previous": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "current": "7e89ef90ce8151315da68a26f7932671f0381c309fca0b50eb8ef1b21010ead4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/content-management-entry-C_oY4VyW.js": {
+ "previous": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "current": "34278c426c4c86c63099074ce94deeaeff10c36f6f97195d25a911286900211a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/operation-key-Dr4VtGxa.js": {
+ "previous": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "current": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/value-text-BztaYdGl.js": {
+ "previous": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "current": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-technical-incidents-C4aVbut7.js": {
+ "previous": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "current": "793c7212e15581f8fae658a0a101ab57fe1b248e36bff078e06d764a3c963a68",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-labels-DlL6bSeE.js": {
+ "previous": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "current": "fbc8a8c75414f64bbae720acb6edf9975aff0653f6018dbac33054e7b9733de2",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-draft-B4uAe0VJ.js": {
+ "previous": "d594e165589268701f769d83aa266791baf7547bb12ca43361f24af114d3f3d2",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/input-text-BlEFHnL-.js": {
+ "previous": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "current": "e33a59a8d120a7aab614cdb6c2e78370ecc2a63770eb61ab98efac37580318c4",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-json-LwabPZWt.js": {
+ "previous": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "current": "820232451a308f62ce448110f77e2c30b4d12b599bc3f41be46b4b20696dc2d0",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-classification-CWBQCCYR.js": {
+ "previous": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "current": "d5f4764791711b8b03ce273332cceeee4f01f4092ed15881628abf4435a1098a",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/opportunity-search-filters-DJOMnDUd.js": {
+ "previous": "d873371c2a689b00c5725133f04ea652f2fd9be1e96faf0d970679d90e75405e",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/proactive-investment-CYz0tbgM.js": {
+ "previous": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "current": "adeb6e9aecca00f619d3780b5928f3eb263e0c4113932280f1ca0f6ac55cf62b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/manage-BzsCf6FW.js": {
+ "previous": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "current": "9b41e7293443323760ba89d86bbc86eebd9c1f060ef487a823b1675f2ec64ab6",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-l3FoBiQ3.js": {
+ "previous": "7b7331f93d5824394ea13f1d95c47adf82093415db2fc3125920306febd6c9f0",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/partnership-source-links-VfrXk2FZ.js": {
+ "previous": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "current": "a4d6c8500f2417983312ae667b96f035df9654f37aa4a7bc86f0cc01fda0ddd8",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/investment-map-panel-BChaE46z.js": {
+ "previous": "22efeed920548942682fcac210f8db0d6c3917b6e01b6a6787402f67877da79a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-investment-map-Lxdld7TL.js": {
+ "previous": "d655638ce24be7e624b6beb2e88397e02562eb52504136d90def2ffc4089c5ce",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/territorial-source-evidence-eKB4ZB36.js": {
+ "previous": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "current": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-attachments-yo9XOR91.js": {
+ "previous": "1476aa61eaad06532f70aef89a16d0ee49195168e4f46d1725a22e7e10e7e00f",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-map-DEudEadc.js": {
+ "previous": "e391b0963bd928f47c1ea27cb64c4c9b26a7c568ace6f4864878a1506cd1813d",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/zone-relations-ttYEfvQE.js": {
+ "previous": "7723ce1efff48a5a812172ccf999aff407fab4fcc6677580a922636116437ec5",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/catalogue-context-B1GeKTzL.js": {
+ "previous": "987fa08c273148f4f19985663215d1ac11142fc2cc043baf7cf06ea3d57ded9c",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/profile-CI6GR1H6.js": {
+ "previous": "643d17a1d3a9c0c6abe166d6d757962edfa35f6951c15522ab9baca020419f6a",
+ "current": null,
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/portal-api-CpQBRfcu.js": {
+ "previous": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "current": "b5adf9c07c4136aa012acb04c1bbc617c20f2f080573b70ba6e6efc50bc69a38",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/country-select-4uP5BvMf.js": {
+ "previous": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "current": "a596bcf6c6a6ea521f343482f469ad38ab96294c772b4fb81832cb9f54497d7b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/page-preparation-guard-B-OckhBt.js": {
+ "previous": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "current": "6eabb17a34fdd418ab46e30f6fa64a2ee6fdfd18eed9249a05837e8e7e798535",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/installation-B0nI9WAi.js": {
+ "previous": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "current": "d40c0dfb0d25ac55ac9c7d94b495d66a1bba90cd42c85fc71bfdf82912b5253b",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/support-installation-3F6rIOG2.js": {
+ "previous": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "current": "8c37431cd96ffe3a7400594bec4abf219473b0c21c1a40bdcc9fb53f02244c19",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-support-CpP0Ki7O.js": {
+ "previous": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "current": "1b972ebb78a2241822e4beeb100dd07040c26aeffead74d458ff3f87bbbff660",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-notice-ru4qf3Jw.js": {
+ "previous": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "current": "196d0fd2b6db83d756baf58d012c12efffcc87aa9521a813a8486d894a13b06f",
+ "reason": "superseded_by_current_build"
+ },
+ "public/build/assets/technical-incident-CYL9UpWe.js": {
+ "previous": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "current": "9fa125a8767d715f5cb60c8b517df0f574de80d52ccbd0f6aac503dcfb7470eb",
+ "reason": "superseded_by_current_build"
+ }
+ },
+ "new_migrations": 0,
+ "active_migrations": 0,
+ "active_writes": 0,
+ "external_messages": 0,
+ "limitations": [
+ "Optional operation keys preserve legacy semantics; unkeyed legacy reuse is not claimed idempotent",
+ "Preview, frozen reuse and profile preparations remain page memory with one leave guard; durable navigation/reload/authentication recovery and expiry remain pending",
+ "Known version changes require comparison; the operation copies only the selected authorized source and never infers organization identity from names",
+ "The actual concurrency proof covers two processes replaying the same viewer-authorized command, not every interleaving or load",
+ "Browser/real-user acceptance, active deployment, real authorized country completion and destination backup/restore remain pending"
+ ]
}
}
diff --git a/docs/investmoz/unification/traceability-and-manual.md b/docs/investmoz/unification/traceability-and-manual.md
index e7098d6d..5575b0c3 100644
--- a/docs/investmoz/unification/traceability-and-manual.md
+++ b/docs/investmoz/unification/traceability-and-manual.md
@@ -8013,3 +8013,1061 @@ Com a observação corrigida, reproduzido **SQLSTATE 40P01** no quinto cenário:
Após a correcção, os cinco cenários passaram em funding_concurrency_20261102c_test: uma referência, uma versão publicada, um interesse e uma auditoria por preparação/publicação/interesse/retirada. A gravação concorrente recusou uma versão obsoleta; retirada concluiu e o interesse concorrente recebeu indisponibilidade, preservando a referência anterior. Consulta final confirma uma referência privada válida e nenhuma publicação activa. São pares de processos com sobreposição observada, não prova de carga nem de todas as intercalações possíveis.
Provas: funding-concurrency-before-20261102.log (verificador inicial), funding-concurrency-baseline-20261102.log (impasse do produto), funding-concurrency-after-20261102.log (cinco cenários aprovados), funding-concurrency-preservation-20261102.json, e logs guard-environment/guard-existing. Sete Feature/235 asserções de compatibilidade aprovados (funding-concurrency-feature-20261102.log), PHPStan sem erros e Pint/sintaxe/diff aprovados. Frontend não alterado; conservadas provas de tipos/lint/compilação do incremento anterior. Matriz e recibo funding_concurrency_increment_20261102 reconciliados. Sem alterações no activo. Próxima acção: integração dos fundos/incentivos nos alertas existentes; vínculos de referência, visual e disponibilização continuam pendentes.
+
+### 02/11/2026 — ACT-11 / AUD-FUND-01: alertas de fundos, programas e incentivos publicados
+
+Integrado o catálogo de fundos no motor existente InvestmentOpportunityAlerts, nas preferências/notificações existentes e no mesmo comando/agendador. Nova migração 2026_11_02_220000_investment_funding_alerts.php acrescenta origem por versão pública e marcador único por pessoa/versão; preserva as fontes, critérios cifrados e notificações anteriores. Nenhuma conta é inscrita automaticamente. Alterar/activar fontes ou critérios toma os IDs públicos existentes como ponto inicial, sem avisos retroactivos; rascunhos e versões intermédias já substituídas não são tratados como novas publicações disponíveis.
+
+Escolha explícita de fundos/apoios, âmbito documentado ou inclusão assinalada de desconhecidos, e estado de uma janela. Reutiliza os filtros do catálogo, com sector/local do programa distintos da cobertura de cada chamada. O aviso não garante elegibilidade ou candidatura aberta e não é candidatura enviada. Regista versão, fonte/referência/data de consulta, data de publicação, preferências aplicadas, explicação do âmbito e estados de janela na data do aviso; não copia respostas, documentos ou rascunhos. Link vai à ficha pública e preserva a fonte da edição notificada. Alteração das datas sem nova versão publicada não gera segundo aviso.
+
+Leitura e marcação conferem a própria conta, disponibilidade do catálogo e publicação actual da ficha. Avisos de versões públicas anteriores conservam o conteúdo original enquanto a ficha tem publicação pública; retirada oculta avisos e impede leitura sem apagar dados. Indisponibilidade de fundos não impede as outras fontes ou o cancelamento. Lote máximo de 200 por fonte/ciclo; fila restante mantém execução devida e não impede a outra fonte. Falha na entrega de fundos reverte também os avisos/marcadores das outras fontes daquela pessoa nesse ciclo. Bloqueio da conta nas preferências usa NO KEY UPDATE, preservando serialização e compatibilidade com referências de auditoria/notificações; concorrência específica do gerador ainda precisa de ensaio com processos.
+
+Provas finais de servidor: **36 testes/612 asserções aprovados** (funding-alerts-verified-feature-20261102.log): sete novos testes de fundos e compatibilidade com alertas de oportunidades/concursos, catálogo e manifestações. Cobrem escolha das três fontes, ausência de inscrição automática, ponto inicial, âmbitos desconhecidos, datas, versões/retirada, propriedade dos avisos, fonte indisponível, cancelamento, lote com 201 fundos e uma oportunidade, reversão de entregas e migração/reversão com dados anteriores preservados. Seis testes frontend aprovados, incluindo selecção voluntária, campos aplicáveis, fonte e ligação/estado histórico do aviso (funding-alerts-verified-frontend-20261102.log). PHPStan e lint/formatação sem avisos aprovados; tipos e compilação finais em acompanhamento. Reutilizadas as provas anteriores de concorrência do catálogo; não as confundir com concorrência do gerador.
+
+Sem instalação, activação de preferências, envio externo ou alteração no activo. ACT-11 continua parcial para canais externos/outras fontes e disponibilização/agendador no destino; fundos/incentivos aqui significa exclusivamente versões publicadas no catálogo do portal. Visual, vínculos de referência e restantes requisitos agregados continuam pendentes.
+
+Fecho das verificações do incremento de alertas de fundos, 02/11/2026: 36 testes/612 asserções e seis frontend, PHPStan, tipos, lint sem avisos/formatação e compilação aprovados, com processos terminais conferidos. Logs finais funding-alerts-verified-*, funding-alerts-final-* e funding-alerts-build-20261102.log; recibo funding_alerts_increment_20261102 com hashes. Matriz AUD-FUND-01 e MASTER-471012ab-0124 reconciliadas como parciais, sem apagar provas históricas. Próxima acção: ensaiar concorrência do gerador e das preferências com processos, e rever perguntas aplicáveis no percurso de conferência de critérios. Sem alterações no activo.
+
+### 02/11/2026 — ACT-11 / AUD-FUND-01: concorrência do gerador e critérios aplicáveis
+
+Estendido tools/verify-funding-concurrency.php com quatro cenários de alertas, conservando os cinco anteriores. Execução em funding_concurrency_20261102d_test, base nova e descartável, com duas sessões por cenário e bloqueios efectivamente observados. Dois geradores concorrentes entregam um aviso; duas gravações idênticas das preferências conservam uma só revisão; cancelamento com precedência impede entrega; gerador com precedência conclui uma entrega antes do cancelamento efectivo e nenhuma depois. Reactivação usa a publicação existente como ponto inicial, sem aviso retroactivo. Nove cenários aprovados, sem novo impasse. Não equivale a ensaio de carga ou de todas as intercalações possíveis.
+
+Conferência final directa: uma ficha, quatro versões imutáveis, um interesse com referência válida, dois avisos e respectivos marcadores, preferências na versão cinco desactivadas. Auditoria com três gravações efectivas de preferências e dois cancelamentos, sem duplicação pelas repetições. Provas em funding-alert-concurrency-20261102.log e funding-alert-concurrency-preservation-20261102.json. Não houve mudança adicional de regras de negócio ou publicação no activo.
+
+No formulário público de conferência, perguntas específicas só aparecem depois de escolher pessoa singular/entidade, e perguntas de outro tipo não são apresentadas. Respostas locais ficam conservadas ao alternar tipo/janela, mas apenas respostas aplicáveis são enviadas. Campos de janela não aparecem quando não há janelas. Selecções/edições limpam resultado e erro anteriores; mudar ficha/versão reinicia a conferência, evitando transportar respostas/resultados para outra edição. Servidor e critérios imutáveis existentes mantêm a distinção desconhecido/não aplicável, sem concessão automática de elegibilidade. Extraída uma única implementação em funding-criteria-assessment.tsx, removendo a anterior da página.
+
+Oito testes frontend aprovados (dois novos de conferência e seis de alertas), logs funding-assessment-frontend-20261102.log. Tipos e lint/formatação sem avisos aprovados; compilação em acompanhamento. Sem alteração no PHP da aplicação neste incremento, reutilizadas as provas anteriores de 36 Feature/612 asserções e PHPStan; o script CLI foi formatado e executado nos nove cenários. Visual, vínculos sectorial/cartográfico da referência e disponibilização/agendador no destino continuam pendentes; canais externos permanecem fora da integração demonstrada.
+
+Fecho do incremento em 02/11/2026: nove cenários concorrentes e oito frontend aprovados; tipos, lint sem avisos/formatação e compilação terminaram aprovados. Verificados hashes actuais do PHP da aplicação contra a prova anterior antes de reutilizar os 36 Feature/612 asserções. Matriz reconciliada e recibo funding_assessment_concurrency_increment_20261102 com fontes, logs e limites. Nenhum processo de validação ficou pendente. Mantêm-se visual, vínculos de referência e disponibilização; o objectivo global de auditoria continua activo. Próxima acção: voltar à matriz consolidada para seleccionar a próxima lacuna funcional autorizada e verificar os vínculos já existentes antes de acrescentar novos dados.
+
+### 02/11/2026 — AUD-EDU-01: rascunhos privados das declarações de Educação
+
+Reconciliados matriz, código e provas: procura de trabalhadores/capacidade formativa já têm submissão, revisão independente e análise; faltava guardar informação incompleta. Implementado o núcleo de rascunhos, ainda sem ligação à interface. Migração 2026_11_02_230000_education_declaration_drafts.php: origem por pessoa/tipo, chave de repetição, versão, dados cifrados, estado e referências com FK para uma única declaração submetida. Reversão recusa eliminar rascunhos/história. Guardas reutilizam activação de Educação e administração efectiva existentes; nenhuma competência ou acreditação nova.
+
+API sob /management/education/drafts/{demands|capacities}: listar apenas os próprios, criar, recuperar, editar com versão e submeter. Respostas privadas/no-store. Permite informação incompleta e quantidade zero apenas em rascunho; não entra nas tabelas/indicadores de trabalhadores ou vagas antes da submissão válida. Dados de outro destino são excluídos; campos de decisão, revisão ou não declarados são recusados. Repetição da mesma chave/payload não cria outra ficha/revisão; comparação estrita preserva diferenças deliberadas em texto numérico.
+
+Extraídas as regras já existentes para EducationDeclarationRules, partilhadas pela submissão directa e pelo rascunho. Ao submeter: mesma validação de referências, datas, quantidade e fonte; criação de uma única declaração com estado submitted e autor, mantendo a revisão por outro gestor. Transacção conserva corpo e snapshot cifrado dos cadastros efectivamente utilizados; alteração futura do nome de projecto não reescreve o snapshot. Rascunho submetido não é editado ou ressubmetido com dados diferentes. Histórico de rascunho/auditoria não expõe texto livre ou empregador em claro no evento.
+
+Provas: **14 testes/291 asserções aprovados**, cinco novos de rascunho e nove existentes de Educação (education-drafts-verified-feature-20261102.log). Cobrem recuperação pela própria conta em novo contexto, isolamento entre gestores, cifragem, repetição, versão obsoleta, tipo distinto, dados incompletos, exclusão de campos não aplicáveis, validação de curso retirado, submissão única, revisão própria recusada, snapshot conservado e guarda de reversão. PHPStan sem erros e Pint/sintaxe/diff aprovados (education-drafts-verified-phpstan-20261102.log). Ensaios só em PostgreSQL isolado 127.0.0.1:55441 *_test; não migrado no activo.
+
+Saldo explícito: faltam interface para guardar/abrir/continuar rascunhos, apresentação da submissão/snapshot, painéis e restantes perfis previstos no requisito, testes de concorrência e visual. Não declarar AUD-EDU-01 concluído pela disponibilidade da API. Próxima acção: ligar os controlos ao formulário existente, conservando edições e regras, e validar o percurso recuperável pela interface.
+
+Fecho das provas do núcleo de rascunhos em 02/11/2026: 14 testes/291 asserções e PHPStan aprovados, processos terminais conferidos. Pint/sintaxe/diff passaram. Matriz AUD-EDU-01 actualizada e recibo education_drafts_increment_20261102 com hashes. Interface continua por ligar e não foi declarada concluída. Próxima acção mantém-se no formulário existente; não criar outro roteiro ou alargar competências por conveniência técnica.
+
+### 02/11/2026 — AUD-EDU-01: rascunhos ligados aos formulários existentes
+
+Interface de procura de trabalhadores/capacidade formativa ligada ao núcleo anterior. Botão de guardar é independente da validação HTML obrigatória da submissão; conserva dados incompletos sem criar declaração. Resposta guardada actualiza identidade/versão local sem navegar ou apagar o outro formulário. Submissão de rascunho usa o seu ID/versão e os campos actuais, preservando validação e revisão existentes. Após sucesso, mostra os dados e cadastros históricos, sem outro formulário de envio, e actualiza declarações/indicadores por recarga parcial que conserva o estado dos formulários.
+
+Lista privada paginada na página de Educação, limitada no servidor ao actor, com tipo, qualificação, data, estado e versão. Reabre por /management/education?draft=UUID; mantém campos em falta vazios, quantidade como declarada e caminho territorial recuperado. Referência fora da lista não é eliminada; local retirado é explicado para reconciliação antes de submeter. Submissões derivadas do rascunho mostram o snapshot preservado, incluindo nome de projecto/curso e local utilizados, separado do estado de revisão actual. A lista não pretende reunir todas as declarações antigas feitas pelo percurso directo.
+
+Conflito de versão mantém as edições locais e orienta recuperação da versão guardada. Navegação que descartaria estado e fecho da página têm protecção para alterações não guardadas; recarga parcial de indicadores não substitui os campos. Campos ficam desactivados durante a gravação. Respostas HTTP privadas/no-store e histórico Inertia cifrado; lista projecta apenas metadados próprios, sem corpo integral dos rascunhos. Datas devolvidas em ISO para consumo consistente pelos navegadores. Quando a migração não existe, os controlos de rascunho não aparecem e o percurso directo anterior mantém-se.
+
+Provas finais: **14 testes/333 asserções** aprovados (education-drafts-ui-verified-feature-20261102.log), incluindo os nove testes anteriores de Educação, recuperação autenticada sintética, rejeição de rascunho de outro gestor pela página, lista privada e snapshot de submissão. **Cinco frontend** aprovados (education-drafts-ui-verified-frontend-20261102.log): página completa/lista e ambos os formulários, gravação incompleta/continuidade/submissão pela mesma identidade, conflito sem sobrescrever edições, caminho territorial estável e snapshot sem novo envio. A verificação de tipos apanhou uma mensagem de recuperação fora do formulário; corrigida e acrescentado ensaio da página completa. PHPStan, tipos, lint/formatação sem avisos, Pint e compilação aprovados, com processos terminais conferidos.
+
+Verificações técnicas não substituem observação visual ou login real; não foram declarados aceites. Restam concorrência deste percurso, visual, painéis dos restantes perfis e disponibilização. Sem migração na base activa. Próxima acção: ensaiar gravação/submissão concorrente em base descartável e conferir o saldo dos restantes actores sem criar competências ou acreditações por inferência.
+
+Fecho da ligação à interface em 02/11/2026: 14 testes/333 asserções, cinco frontend, PHPStan, tipos, lint sem avisos/formatação, Pint e compilação aprovados; processos terminais conferidos. Matriz AUD-EDU-01 e recibo education_drafts_ui_increment_20261102 actualizados com hashes. Reutilizada a limpeza de histórico existente no LogoutResponse (AppServiceProvider), sem novo mecanismo de autenticação. Interface implementada localmente não equivale a aceitação visual ou por contas reais. Próxima acção: concorrência de gravação/submissão em base descartável, preservando as provas actuais e os rascunhos/submissões existentes.
+
+### 02/11/2026 — AUD-EDU-01: concorrência real dos rascunhos e submissões
+
+Criado tools/verify-education-draft-concurrency.php, exclusivamente CLI e limitado a testing/PostgreSQL 127.0.0.1:55441, nome ancorado education_draft_concurrency_20261102[a-z]?_test, URL de ligação vazia e identidade/base efectivas conferidas. Reutiliza a guarda de execução QA; exige base sem pessoas, rascunhos ou declarações antes de criar cenário sintético. Recusa de ambiente não explícito e de repetição numa base já não vazia verificadas, sem reset ou remoção de registos. Base usada: education_draft_concurrency_20261102_test, mantida com as provas.
+
+Dez cenários, cinco por tipo (procura de trabalhadores/capacidade formativa), com dois processos PHP e sessões PostgreSQL independentes. O processo de controlo mantém o bloqueio até observar ambos os trabalhadores à espera no PostgreSQL; limpa o snapshot de estatísticas entre observações. Casos: mesma chave de criação, edições diferentes com a mesma versão, repetição da submissão, gravação com precedência sobre submissão e submissão com precedência sobre gravação. Todos passaram. A gravação vencedora fica conservada e a submissão obsoleta recebe conflito; no inverso, a declaração/snapshot submetidos ficam imutáveis e a edição é recusada.
+
+Conferência final directa: seis rascunhos (dois abertos e quatro submetidos), duas declarações de procura e duas de capacidade, quatro snapshots e quatro vínculos válidos ao respectivo autor. Auditoria com dez gravações efectivas de rascunho e quatro submissões. Repetições não duplicaram rascunho, revisão ou declaração; todas as quatro declarações continuam submitted, sem reviewed_by, mantendo a revisão independente. As linhas pertencem a casos técnicos distintos, não a procura ou capacidade reais.
+
+Provas em education-draft-concurrency-20261102.log e education-draft-concurrency-preservation-20261102.json, com guardas em logs guard-environment/guard-existing. Script executado/formatado e sintaxe/diff aprovados. Não houve delta no PHP/JS da aplicação; provas anteriores de 14 testes/333 asserções, cinco frontend e verificações estáticas/compilação são reutilizadas após conferir hashes. São pares de processos nos casos delimitados, não ensaio de carga nem de todas as intercalações possíveis. Visual, painéis/perfis restantes e disponibilização continuam pendentes; não alterar o estado agregado para concluído.
+
+Próxima acção: retomar o saldo da matriz e confrontar os restantes consumidores/perfis com o código e permissões existentes, avançando nas lacunas independentes sem inventar papéis ou decisões institucionais. Nenhuma migração, conta ou dado foi alterado na base activa.
+
+Fecho da concorrência de Educação, 02/11/2026: dez cenários aprovados e conferência de dados/auditoria concluída. Aplicação sem alterações neste incremento; hashes conferidos contra a prova anterior de 14 testes/333 asserções, cinco frontend e verificações estáticas/compilação. Matriz e recibo education_drafts_concurrency_increment_20261102 actualizados. Guardas de ambiente/base não vazia recusaram execução sem apagar dados. Nenhum processo pendente. Próxima acção: seleccionar o próximo saldo funcional autorizado na matriz, mantendo visual e restantes perfis/painéis como pendências concretas, sem declarar a auditoria global concluída.
+
+
+### 02/11/2026 — AUD-MARKET-01: pesquisa de negócios por raio, sector e classificação
+
+Reutilizados o UUID/catálogo público de negócios, classificação divulgada e cartografia existentes. O detalhe oferece comparação por raio quando a ficha tem ponto primário marcado público e precisão exacta. A consulta aceita referência pública por UUID e raio de 0,1 a 2000 km (limite técnico da consulta interactiva, sem nova regra organizacional). O selector de similares oferece distâncias usuais; no catálogo é possível indicar qualquer valor dentro desse intervalo. Retirar o raio recupera o filtro de área; no comparador o raio substitui a área, conservando modalidade, sector e classificação. No catálogo a área adicional restringe também os resultados. Paginação, abertura da ficha, regresso e manifestação de interesse conservam os filtros efectivamente aplicados. Editar a próxima pesquisa não altera o contexto das fichas já apresentadas.
+
+BusinessProximitySearch usa PostGIS/geography (distância geodésica em linha recta, sem itinerário rodoviário). Só utiliza geometrias Point válidas/não vazias/4326 com longitude/latitude nos limites e sinalização pública exacta; não transforma polígonos em centróides, não geocodifica nomes e não usa pontos privados/secundários ou fichas expiradas, futuras, eliminadas ou não publicadas. Referência sem ponto utilizável é recusada explicitamente, sem alargar a pesquisa silenciosamente. A API projecta distância arredondada e data de registo, nunca geometria/EWKT/coordenadas, payload ou titular privado.
+
+PublicBusinessLocations centraliza divulgação e precisão: um distrito guardado numa localização com precisão apenas provincial deixa de permitir inferir esse distrito por filtro. Referências retiradas/privadas nos níveis divulgados não alimentam o ponto ou a projecção; campos mais finos não divulgados não apagam a província ainda pública. A lista explica a fonte interna, data de registo da localização, cobertura com/sem ponto utilizável antes do raio e limites. Cobertura considera os restantes filtros e pode incluir a própria referência; o painel de similares retira a própria ficha dos seis resultados. Registo/publicação não são datas comprovadas dos dados de origem, nem verificação da localização real.
+
+Provas finais: 11 Feature/384 asserções em business-proximity-final-feature-20261102.log, incluindo os quatro cenários novos de proximidade, quatro anteriores do catálogo público e três da pesquisa rápida. Casos sintéticos com distância próxima/fora do raio, ordenação/paginação, sector/modalidade/classificação combinados, área combinada com raio, ponto privado/secundário, polígono, coordenada fora dos limites, referência sem cobertura, vigência/publicação e precisão territorial. Dez frontend aprovados: controlos e troca de referência, classificação/raio, recuperação de área, cobertura/datas/distância, respostas tardias ou malformadas, filtros aplicados versus edição e pesquisa rápida com preenchimento automático. PHPStan, tipos, lint/formatação sem avisos, Pint e compilação aprovados; logs/hashes no recibo business_proximity_increment_20261102.
+
+O exemplo do proprietário «plantio de algodao» foi revalidado: com/sem acentos e variantes de cultivo, sem apresentar transformação como plantio. Se só existem fichas de transformação, a pesquisa mostra-as separadamente como relacionadas e conserva os restantes filtros. Não foi inventada oportunidade para completar o resultado.
+
+Estado parcial: não há demonstração de cobertura real de pontos públicos exactos, alimentação desse cadastro pela gestão, visual no navegador ou disponibilização no destino. A localização existente não guarda citação/data própria da fonte; updated_at é identificado apenas como data de registo. Não foi criada outra origem, geometria ou correspondência territorial no activo; nenhum schema, pessoa ou dado activo foi alterado. Próxima acção: confrontar o percurso editorial de localizações com os cadastros/fontes autorizados e acrescentar rastreabilidade e edição reutilizando a mesma identidade, sem divulgação automática. Manter as demais lacunas da matriz activas.
+
+
+### 02/11/2026 — AUD-MARKET-01: ponto preparado no formulário e publicado pelo roteiro existente
+
+Verificação inicial encontrou território, precisão e fontes no formulário, mas nenhum escritor de existing_business_locations. A alimentação foi ligada ao mesmo formulário/UUID, sem novo editor, rota, perfil ou ordem de aprovação. O suplemento é opcional: território específico/múltiplo, localização conhecida, precisão exacta e escolha explícita de preparar o ponto. Para vários caminhos, escolhe-se uma das localizações já declaradas; a primeira não é inferida. Reutiliza-se a fonte da etapa Fontes quando também sustenta o ponto, ou indica-se uma fonte diferente. Coordenadas WGS84 com limites, referência e data são conservadas no payload cifrado. Rascunho incompleto continua gravável; campos sem aplicação ficam reservados/preservados e não activam ponto. Asteriscos assinalam os campos necessários ao suplemento activo.
+
+Guardar/submeter/rever/aprovar não altera o cadastro geográfico público. ExistingBusinessIntake valida o candidato na submissão e novamente na publicação; o escritor só corre após as competências, versão e independência já exigidas, na mesma transacção com bloqueio do negócio. A publicação cria ou substitui o ponto primário, conserva o UUID existente e as localizações secundárias. Prévia privada distingue local já cadastrado e ponto proposto e explica o efeito da substituição. O journal cifrado preserva a geometria/fonte anterior, valores/fontes/nomes territoriais utilizados e a nova localização; alterações posteriores de nomes/cadastros não reescrevem esse histórico. Sem opt-in, o cadastro anterior é conservado. Anúncios já publicados conservam o seu percurso anterior de alteração; este incremento não lhes concede edição ou reabertura.
+
+Migração aditiva 2026_11_03_000000_existing_business_location_sources acrescenta referência pública opcional, data real da fonte, origem do adaptador e versão do payload usada. Não preenche dados históricos nem publica localizações. Rollback recusa perda de fontes preenchidas; sem as colunas, o catálogo mantém projecção nula da fonte, e um suplemento escolhido não é publicado silenciosamente: exige actualização do destino. O ponto só divulga a referência se a escolha expressa o permitir; a fonte integral continua no processo reservado. Data em falta fica desconhecida, sem usar published_at/updated_at como substituto. A interface pública mostra referência/data da origem separadas da data de registo, sem transmitir geometria ou coordenadas cruas. Datas só de calendário são apresentadas em UTC para evitar recuar um dia em fusos a oeste.
+
+Provas finais: **28 Feature/677 asserções** em business-point-publication-final-feature-20261102.log: oito cenários do suplemento, pesquisa por raio e percursos anteriores de intake/wizard/catálogo público. Incluem publicação por actor independente, versão obsoleta, coordenadas inválidas, referência territorial retirada entre aprovação/publicação, fonte reservada/data desconhecida, caminho múltiplo explícito, substituição com histórico/UUID/locais secundários e preservação sem opt-in. **17 frontend** aprovados: formulário real e mesma API de gravação, caminho/declaração múltipla, fonte reutilizada/diferente, campos condicionais preservados, selecção retirada visível, resumo preparado/publicado, datas/cobertura e consumidores anteriores. Tipos, lint/formatação sem avisos, Pint e compilação aprovados. PHPStan falhou primeiro na criação de uma pasta da cache global; passou com a mesma configuração incluída e cache privada isolada, sem supressões ou alteração das regras. O limite textual das coordenadas foi separado do limite numérico após o ensaio detectar max:16 aplicado como tecto numérico.
+
+Provas e hashes no recibo business_point_publication_increment_20261102. Bases exclusivamente sintéticas em investmoz_test, loopback PostgreSQL55441, guardas anteriores mantidas. Nenhuma migração no activo, fonte oficial real importada, conta real ou mensagem externa. Não há prova visual no navegador, cobertura real de pontos ou disponibilização no destino. Coordenadas declaradas e caminhos não certificam a correspondência espacial. Estado agregado parcial; próxima acção: retomar o saldo da matriz e as restantes funcionalidades/actores, preservando estes percursos e distinguindo cobertura real, aceitação visual e disponibilização de desenvolvimento em falta.
+
+
+### 02/11/2026 — AUD-CHECKLIST-01: entrada em vigor das versões do Balcão
+
+Conferido o saldo contra o código e as provas anteriores: o editor/histórico já existiam e foram preservados. A lacuna deste incremento era a escolha da edição aplicável por data; todas as publicadas eram anteriormente oferecidas imediatamente. Acrescentada a data opcional de entrada em vigor à publicação, com calendário/fuso da aplicação indicado, prévia do efeito, confirmação invalidada quando a data muda e distinção entre última edição publicada, edição actualmente disponível e futuras edições agendadas. Ao editar uma edição futura, o formulário conserva essa data até alteração deliberada. A passagem do calendário não transforma um formulário sem alterações numa nova publicação; a alteração apenas da data tem de ser escolhida expressamente.
+
+DeskServiceAvailability é a única selecção usada no catálogo, dossier, percurso do investidor e criação de pedidos. Considera publicação efectuada e início já atingido; prevalece a data de início mais recente e, na mesma data, o maior número de versão. As linhas históricas sem data permanecem fallback, com ordem por versão, sem inventar datas ou reescrever a história. Uma correcção para hoje não cancela edições com início posterior; a gestão lista a edição futura vencedora por cada data. Para corrigir uma edição futura, publica-se nova edição com essa mesma data. É escolha técnica de selecção apresentada na prévia, sem alterar a sequência, as competências ou os critérios de decisão existentes.
+
+A criação de pedidos partilha o bloqueio transaccional da publicação. Um identificador futuro ou já substituído não cria um novo pedido; devolve erro no campo para conferir a versão actual. A interface actualiza apenas os serviços, conserva os outros formulários e torna explícita uma escolha que saiu da lista. Repetir uma criação já efectuada recupera o mesmo pedido, mesmo após mudança da edição corrente; respostas, fonte e snapshot continuam vinculados à FK original. Uma data passada é recusada numa publicação nova, mas a repetição da mesma publicação anterior continua idempotente. Repetição imediata e repetição agendada são distinguidas pela intenção registada no evento, preservando a data/autoria iniciais e recusando uma intenção diferente sobre a mesma base obsoleta.
+
+A migração 2026_11_03_010000_desk_service_effective_dates é aditiva, com data nullable e índice; não preenche versões antigas. Rollback recusa perda de datas preenchidas. Sem a coluna, o percurso imediato anterior continua a funcionar e o servidor recusa agendamento não suportado. A publicação inicial dos modelos também regista a data quando suportada. O ensaio desta rota revelou duplicação por comparação estrita da ordem de chaves JSONB; a comparação normalizada do editor foi reutilizada, conservando a primeira versão, autoria e data em repetição. A falha anterior está preservada em desk-effective-dates-final-feature-20261102.log e desk-effective-dates-complete-feature-20261102.log; não é uma perda de dados demonstrada no activo.
+
+Provas finais: **21 testes Feature/314 asserções** em desk-effective-dates-ready-feature-20261102.log, dez casos temporais/compatibilidade mais onze anteriores do editor, condições, preenchimento, localização, análise e recibo. Verificados calendário na fronteira da data, correcção imediata/edição futura, desempate na mesma data, data sem mudança de perguntas, selecção forjada, recuperação de criação anterior, snapshots/submissões preservados, datas inválidas/passadas, autoridade, fallback legado/rollback e integração real com o percurso do investidor. **Nove frontend** aprovados: data/confirmar/edição futura, calendário sem alteração implícita, lista agendada, actualização parcial e escolha retirada, metadados no catálogo e regressões do editor/histórico/perguntas condicionais. Tipos, lint/formatação sem avisos, Pint, PHPStan (mesmas regras com cache privada) e compilação aprovados; processos terminais conferidos.
+
+O fingerprint de instalação passa a incluir também editor, selector, controlador, histórico e migração temporal, para não reutilizar prova de código anterior para este comportamento. Não houve instalação no destino nem migração na base activa; apenas QA sintético PostgreSQL loopback55441, com guardas anteriores mantidas. As datas são avaliadas na leitura/criação e não dependem de agendador ou IA. A decisão permanece interna e não equivale a licença ou acto oficial. Estado transversal parcial: outros tipos/contextos de checklists, observação visual e disponibilização ainda por conferir; não se declara toda a aplicação parametrizável. Próxima acção: continuar os restantes saldos autorizados da matriz, conservando as versões e provas aqui delimitadas.
+
+
+### 02/11/2026 — AUD-EDU-02: reconciliação com os rascunhos de Educação já demonstrados
+
+[EDUCATION-DRAFT-RECONCILIATION-20261102] AUD-EDU-02 é também coberto pelos incrementos já registados em AUD-EDU-01: rascunho incompleto privado de procura/capacidade, dono/tipo/versão, guarda/recuperação pela interface, conflitos, submissão única e revisão independente; sem zeros/datas fictícios ou inclusão nos agregados. Reutilizadas provas de 14 Feature/333 asserções, cinco frontend e dez cenários reais de concorrência em QA, com hashes das seis fontes UI/serviço/testes e sete logs conferidos em02/11. Recibos education_drafts_ui_increment_20261102 e education_drafts_concurrency_increment_20261102. Não é desenvolvimento novo ou instalação no activo. A indicação antiga de ausência na linha AUD-EDU-02 e nos planos anteriores é histórica e fica superada por estas provas, conservadas sem reexecução. A matriz/backlog foram corrigidos para parcial local. O saldo deste requisito é visual/disponibilização; AUD-EDU-03/01 conservam os restantes perfis e painéis. Nenhuma alteração no código, dados ou competências foi necessária para esta reconciliação.
+
+
+### 02/11/2026 — AUD-ESTABLISHMENT-01: listas privadas preservadas e conferência das pendências
+
+Reconciliação com prova aceite de28/10/2026: importação privada específica já entregue, com361464 observações administrativas,147165 repetições conservadas e214299 projecções distintas; nenhum destes números é contagem de empresas únicas. Recibo proactive-supply-git-delivery-20261028.json e motores prepare/export/load-proactive-supply.py preservados. Os estados anteriores a essa entrega são históricos, não prova de ausência actual.
+
+O saldo da matriz dizia não existir importador. Essa formulação foi reconciliada com a entrega posterior já aceite: preparação, exportação, carregamento idempotente, hashes/linhas/fontes e consulta privada por território já existiam. O inventário histórico abrange13 ficheiros e o recorte tem quatro fontes aceites. O recibo de28/10 contém a prova de replay, backup/restauro, autorização/RLS e entrega Git; não se repetiu o lote nem se apresentou essa entrega como desenvolvimento novo. A leitura actual do código e os hashes dos originais foram confrontados com esse acervo. As361464 observações,205608 sem correspondência territorial e demais contagens desse recibo são a fotografia histórica, não um novo censo ou medição actual do destino.
+
+Lacuna concreta corrigida: a pesquisa territorial não conseguia recuperar linhas sem território, incluindo ambiguidades. A rota privada /minhas-oportunidades/oferta-interna/revisao, acessível pela consulta interna da preparação de oportunidades, permite conferir todas as linhas retidas por origem, texto sem acentos, estado e referência. Mostra origem/SHA256, folha/linha, data original, período e data da importação separadamente; os valores originais de província/distrito não são substituídos pela referência canónica actual. Datas Excel em formato serial mantêm-se como na fonte; importação recente não confirma actualidade da actividade. Repetições ligam à observação original mesmo entre fontes; paginação e ligações conservam os filtros aplicados e o contexto da ficha. A forma de pesquisa usa os valores efectivamente submetidos pelo navegador e acompanha a navegação entre filtros.
+
+Os totais por origem antecedem os filtros de texto/estado/linha; indicadores sobrepostos são identificados e não somados como empresas únicas. Distinguem-se ausência de correspondência, ambiguidade, referência canónica actualmente indisponível, designação de actividade em falta, denominação em falta, identificador com nomes divergentes e projecção repetida. Nenhuma destas situações é fundida ou corrigida automaticamente. Ausência de resultados significa informação insuficiente. A página não altera linhas, cria empresas, publica listas ou aplica georreferenciação. Os motores e o histórico existentes continuam únicos.
+
+A mesma autorização interna é verificada antes da validação/consulta de fichas, preservando também o âmbito de leitura da ficha quando fornecido. A leitura reutiliza o contexto RLS existente e os cabeçalhos private/no-store; a projecção exclui entity_key, fingerprint, recibo privado, contactos, identificadores fiscais e geometria. Nomes canónicos provêm apenas das referências públicas disponíveis. O componente territorial foi corrigido para não pintar resultados de uma localização ou ficha anterior após mudança/abort, nem substituir resultados novos com um erro tardio. A conferência independente da política SQL com papel sem privilégios confirma ausência de linhas sem contexto e acesso ao recorte sintético com o contexto esperado; não concede novas competências.
+
+Provas finais: **nove Feature/138 asserções** em proactive-supply-review-final-feature-20261102.log e **seis frontend** em proactive-supply-review-final-frontend-20261102.log. Cobrem linhas sem território, ambiguidade, repetições, conflitos, privacidade da projecção, âmbito/autorização antes de enumerar fichas, caracteres literais/acentos, paginação/referências, rota Inertia, origem das comparações e política RLS; na interface, escape, datas desconhecidas, filtros/contexto, navegação e respostas/erros tardios. PHPStan com as mesmas regras/cache privada, tipos, lint/formatação, Pint e build aprovados. As onze tabelas inventariadas na QA mantêm contagem e checksum de todas as linhas após rollback dos cenários; ver recibos before/after. São ensaios sintéticos exclusivamente em proactive_investment_20261027_test, PostgreSQL loopback55441, com guardas mantidas; não são aceitação por utilizadores reais. Não houve migração, importação de lote ou escrita no activo.
+
+O primeiro ensaio do cenário antigo falhou no fixture que exige sectores não existentes nesta QA; log proactive-supply-review-feature-20261102.log preservado. Isso não demonstra eliminação de sectores no activo nem revoga a aceitação anterior. Os novos testes usam actores, referências geográficas e observações explicitamente sintéticos dentro de transacções revertidas, sem semear permanentemente cadastros para mascarar o ambiente. A suite antiga completa não foi declarada verde.
+
+Estado parcial: falta reconciliação/consolidação rastreável de entidades e extensão a outros formatos/lotes concretos. Observação visual e instalação deste delta continuam pendentes; a limitação anterior da ferramenta de navegador permanece registada, sem substituir prova visual por testes técnicos. Não foi criado outro backlog nem condicionada a fonte aceite a nova validação genérica. Próxima acção: prosseguir os saldos autorizados da matriz, reutilizando importadores, referências e provas preservados.
+
+
+### 02/11/2026 — reconciliação das vistas principais de Fundos e Educação
+
+O quadro inicial e as secções15/20 da visão consolidada ainda descreviam estes motores como ausentes, apesar dos incrementos e recibos posteriores. Foram reconciliados com as provas existentes, conferindo os hashes do código abrangido. Fundos conserva catálogo/editor, critérios, filtros/guardados/alertas e concorrência; Educação conserva o rascunho privado, interface/snapshot e concorrência. Os saldos de fontes, painéis/perfis, visual e destino continuam explícitos. Não houve testes, código de aplicação, dados ou disponibilização novos nesta reconciliação, nem outro backlog.
+
+
+### 02/11/2026 — AUD-OP-05: maturidade na publicação e na limpeza de uma etapa opcional
+
+O cadastro de oito etapas e a pesquisa consciente da versão já existiam; foram preservados, sem outro catálogo ou conversão de números históricos. A leitura do código delimitou um risco na republicação quando não há etapa. O primeiro ensaio confirmou que a simples omissão no pedido conserva a etapa pelo merge do rascunho; não era uma perda demonstrada nesse percurso. O cenário com null explícito reproduziu a falha: a nova publicação perdia a versão/código da etapa mas mantinha o número e a designação anteriores. Assim, podia continuar a mostrar um valor que o autor tinha limpo e, nos números1–6, ser interpretada pelo filtro histórico. Logs iniciais conservados; não foi declarada regressão no activo.
+
+OpportunityProfileWorkflow passa a distinguir as respostas na projecção aprovada. Uma etapa indicada usa o catálogo spec-v2 existente. Uma etapa opcional explicitamente limpa publica valor/designação/código null e mantém a identificação de spec-v2, sem adivinhar uma etapa ou nível histórico. Se não foi fornecido esse campo, o valor anterior conservado mantém também os metadados anteriores, incluindo fichas preparadas por editores antigos. O histórico de publicação conserva integralmente a versão/código/valor/designação anteriores. A edição do rascunho continua privada e não altera a publicação até à revisão, aprovação e publicação competentes; nenhuma etapa de decisão foi removida ou automatizada.
+
+Provas dirigidas: **15 Feature/371 asserções**. Os oito códigos passaram pelo formulário HTTP de rascunho, submissão, revisão técnica/jurídica, aprovação independente, publicação, suspensão/revisão e republicação após limpeza. Verificados a designação/posição de cada etapa, o resultado do filtro por etapa antes/depois, ausência de correspondência histórica indevida e histórico anterior conservado. Seis cenários adicionais conservam cada valor/designação legado sem campo de etapa e distinguem o filtro histórico do actual; um código desconhecido é recusado no campo pelo validador de rascunho já existente, sem destruir a preparação anterior. As publicações de ensaio mantêm visibilidade interna e não entram nos consumidores públicos; são testes da projecção e do filtro partilhado, sem os apresentar como publicação pública ou aceitação visual. A prova anterior de pesquisa pública com escalas separadas continua no manual/manifesto opportunity-search-qa-manifest.json.
+
+Pint e PHPStan aprovados para o delta PHP. Não houve alteração de interface ou de rotas nesta etapa; a compilação e os testes frontend anteriores não foram repetidos sem necessidade. A QA exclusiva maturity_publication_20261102_test em PostgreSQL loopback55441 foi criada vazia para estes ensaios, com as guardas de teste e bloqueio mantidas. Não se reiniciou nenhuma base de provas anterior nem se alterou o activo. As localizações/actores/documentos são fixtures explicitamente sintéticas; a indicação antimalware no fixture de política não é novo scan real. O primeiro erro de cenário, por falta do pai territorial sintético, foi corrigido apenas no fixture deste recorte, sem relaxar a hierarquia ou atribuir localizações reais.
+
+O ensaio inicial de código desconhecido encontrou a rejeição já existente no rascunho, mais cedo que a hipótese inicial; foi corrigida a expectativa do teste, mantendo esse validador. A primeira execução alargada passou três etapas e recusou as cinco a partir de Viabilidade por faltar o cenário/indicadores/modelo exigidos. O fixture foi completado com valores declaradamente sintéticos e documento de política já pertencente ao cenário, sem enfraquecer a regra ou apresentar esses valores como cálculo/negócio real. Logs de falhas intermédias não são resultados de produção nem prova de ausência das funcionalidades já entregues. Recibo maturity_publication_increment_20261102 contém fontes e hashes dos logs finais/intermédios.
+
+Estado transversal parcial: faltam adopção explícita de legados, restantes variantes/categorias, observação visual e disponibilização do delta. Não se declara toda a maturidade/publicação do portal concluída pelo recorte interno. Próxima acção: continuar o confronto dos saldos autorizados com o código e provas existentes, conservando classificações, submissões e decisões anteriores.
+
+
+### 02/11/2026 — AUD-COMPANY-01: comparador societário informativo e recuperação no dossier
+
+Conferido o requisito contra código/matriz e o exemplar confirmado de segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5. Leitura apenas, sem alterar o original ou produzir outro DOCX; 907 parágrafos OOXML conservam os locators, incluindo vazios. A primeira extracção auxiliar contava só 889 parágrafos não vazios; foi corrigida antes de usar os locators. A secção 9/§§9.1–9.6 não constitui modelos de contratos entregues. O comparador e os modelos mantêm IDs próprios, sem transformar propostas em código existente.
+
+A base legal aceite foi recuperada da [edição republicada do Código Comercial no portal do Tribunal Superior de Recurso de Maputo](https://tsrm.gov.mz/wp-content/uploads/2025/10/Dec_Lei_1_2022.pdf), 76 páginas, BR 99/I Série/3.º Suplemento de 25/05/2022. A nota da Imprensa Nacional identifica a republicação; a conferência delimitou a edição, sem voltar a exigir aceitação genérica da fonte oficial. Original privado conservado em company-sources-20261102/commercial-code-republished-20220525.pdf, SHA256 8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f. Não foi importado/publicado como novo recurso da biblioteca e não se atribuiu scan antimalware novo ao ficheiro; a interface referencia o exemplar oficial externo. As fontes/artigos e a data de consulta acompanham cada resultado; não se declara cobertura de todas as alterações ou legislação especial.
+
+Consulta pública em /formas-juridicas, acessível de Como Investir e do perfil; o dossier oferece /investimentos/{id}/forma-juridica. As perguntas recolhem apenas preferências codificadas e dados novos da preparação: finalidade, participantes, participações, capital, gestão, responsabilidade, Bolsa, regras específicas e alternativa a aprofundar. Não repetem nome, NUIT, residência, orçamento ou identidade da entidade. Gestão permite esclarecer poderes dos sócios e nomeação da administração em conjunto, sem falsa alternativa exclusiva. Desconhecidos são permitidos e indicados como questões por esclarecer; cada pergunta produz uma explicação ou preparação aplicável.
+
+A comparação distingue empresário individual dos quatro tipos societários enumerados na edição citada. As modalidades unipessoais são identificadas no respectivo âmbito. Incompatibilidades documentadas são mostradas sem esconder a preferência do utilizador, aprovar constituição ou criar uma pontuação. Representação de sociedade estrangeira e cooperação têm encaminhamento próprio; não são novas formas societárias. As perguntas sem aplicação ficam ocultas e fora da avaliação, conservando os valores para futura recuperação. A interface apresenta fundamentos, fonte, limites e próximos pontos a preparar. Este recorte não gera contratos nem certifica registo, responsabilidade pessoal, habilitação, financiamento ou admissão em Bolsa.
+
+Escolher um dossier transporta os códigos pelo percurso existente de autenticação; o middleware conserva o URL pretendido. O utilizador pode escolher dossier existente ou criar um novo com título/consentimento habituais. A criação não grava automaticamente a comparação: as respostas chegam como preparação e Guardar no dossier é explícito. Os testes de HTTP/estado não são prova de login real no navegador. Em erro, as respostas continuam no formulário; Reabrir com estas respostas faz GET com os valores actuais, permitindo recuperar sessão/versão sem os descartar. Nenhum nome ou contacto privado é colocado nesse transporte de códigos.
+
+CompanyComparison é o único avaliador. Reutiliza autorização e bloqueio de linha de VirtualDesk, a versão de desk_cases e os eventos cifrados existentes. Não criou tabela, entidade ou competência paralela. Guardar congela respostas, perguntas/opções, resultado, edição/hash/artigos da fonte, autoria e data. A edição anterior permanece no evento; a lista é paginada e recupera edições antigas pelo identificador no âmbito do mesmo dossier. Resultados/perguntas de uma edição anterior não seguem silenciosamente o motor actual. Preparar nova comparação a partir de uma edição histórica é explícito e cria outra revisão, preservando a anterior. Mudanças da configuração do comparador não reescrevem o cadastro, as declarações de empresa, o dossier anterior ou as etapas do percurso.
+
+Repetir a mesma operação e conteúdo recupera a revisão original, inclusive quando as perguntas da edição actual já mudaram. A normalização dessa repetição usa a definição congelada na operação anterior; versões inteiras recebidas como número ou texto são normalizadas após validação. Reutilizar a chave com respostas diferentes é recusado. Uma nova operação sem alteração de respostas/resultado reutiliza a edição existente, sem aumentar a versão, criar outro evento ou aviso redundante. Operações novas com versão obsoleta/dossier fechado são recusadas; a repetição de uma gravação anterior não escreve num dossier fechado. A permissão efectiva é conferida novamente; revogação de coeditor impede leitura, repetição e gravação na sessão anterior. Um membro só de consulta não ganha edição.
+
+Provas finais: **14 Feature/385 asserções**, dez casos novos e quatro anteriores de InvestorPath, em company-comparison-finalized-feature-20261102.log. Cobrem consulta pública sem IA, incompletude, códigos inválidos, efeitos das perguntas, conflitos/unipessoalidade, campos inactivos, gravação/cifragem, ausência de alterações nos cadastros/etapas, repetição/no-op/conflito, fonte/perguntas históricas após nova versão, 26 edições/paginação, âmbito, coedição/revogação, encerramento, escolha/criação de dossier e retorno. **Seis frontend** aprovados: escape, fonte e formulário GET real; visibilidade com recuperação; transporte dos valores efectivamente presentes no navegador; falha sem perder edições e recuperação por GET; leitura histórica com perguntas próprias; gravação/retorno e links no mesmo âmbito. Tipos, lint/formatação sem avisos, PHPStan com regras herdadas/cache privada, Pint e compilação aprovados, processos terminais conferidos.
+
+QA exclusiva company_comparison_20261102_test, PostgreSQL loopback 55441, guardas existentes mantidas; a conferência final regista zero utilizadores, dossiers, organizações e declarações de empresa após rollback. São cenários sintéticos de política e interface técnica, sem pessoas reais ou aceitação por clientes. Não houve migração nova/activa, importação no activo, mensagem externa, publicação de modelos ou disponibilização remota. Os primeiros avisos de tipos e de tratamento de FormData foram corrigidos no código, sem supressões ou relaxamento de autorização.
+
+Estado parcial: observação visual e login real continuam pendentes devido à limitação de navegador já registada, bem como disponibilização e casos especiais/redacções adicionais. AUD-COMPANY-02 conserva o saldo de exemplares específicos, versionamento e derivadas dos modelos; a biblioteca genérica e esta comparação não os substituem. Próxima acção: continuar os saldos autorizados da matriz, reutilizando esta comparação e os mecanismos documentais existentes quando o recorte concreto de modelos/guiões for implementado.
+
+
+### 02/11/2026 — AUD-COMPANY-02: preparação factual privada, exemplares pendentes
+
+Foi lido o complemento fornecido, SHA256 b20c6517784b6d44aa22beb67748d3f3b224f58c60a7dcb378a185669c2c543e, sem alterar o DOCX original. O documento propõe sete minutas e oito requisitos; não contém os sete exemplares. A orientação final permite desenvolver a estrutura/formulário sem publicar cláusulas não fornecidas. A pesquisa nas pastas conhecidas não localizou os modelos. O proprietário informou «nao tenho neste momento a url»; pendência de fonte registada, sem nova solicitação repetida e sem a converter em bloqueio dos outros desenvolvimentos. Propostas ou prompts incluídos no documento não foram tratados como ordens executáveis, provas de implementação ou competências outorgadas.
+
+/investimentos/{id}/preparar-empresa reutiliza o dossier e as autorizações existentes. Sete secções: forma, intervenientes/papéis, nome/sede, actividades, capital/participações, administração/forma de obrigar e conferência. Nome, sede e poderes são propostas. Não se recolhem NUIT, documento de identidade, assinatura, morada residencial ou contactos repetidos. As origens disponíveis são o proponente conservado na criação e a declaração de empresa já associada ao dossier; a escolha é explícita. O servidor resolve os valores, referência e versão, ignora a tentativa de trocar identidade através de um nome enviado e recusa snapshots forjados. Uma origem já utilizada na mesma linha mantém os valores congelados mesmo que outro contexto ou cadastro mude. Não há fusão por igualdade de nome; cada linha tem identificador próprio e duplicação de uma origem é assinalada. Sócio, administrador, representante e beneficiário efectivo declarado são papéis distintos/acumuláveis; a representação exige identificar outra linha na conferência. Não se validou identidade nem se atribuiu qualquer desses papéis de autoridade automaticamente.
+
+Aritmética decimal exacta com a dependência Brick Math já instalada pelo framework; sem floats, câmbio, mínimos legais ou prazos inventados. Valores ausentes não são zero. Entradas em dinheiro e espécie compõem a subscrição; realização declarada é distinta de prova de pagamento. São conferidos soma versus capital, realização acima da subscrição e, nas formas em acções, número vezes nominal por participante e total. Trabalho fica separado e não integra capital (artigo 266 da edição já citada no comparador). A ficha incompleta/inconsistente é um rascunho guardável, com questões visíveis. Capital é ocultado no percurso individual e valores de outras escolhas são preservados, fora dos totais aplicáveis. Actos de administração, objecto e origem não se convertem em poderes, licenças ou registo.
+
+CompanyPreparation conserva facts/definição/fonte/conferência/autoria/data por revisão nos payloads cifrados de desk_cases/desk_events. Reutiliza locks de linha, versão do dossier e eventos/notificações existentes. A auditoria não contém nomes ou valores da ficha. Repetir uma operação confirmada devolve a revisão original; a repetição usa as formas/definição congeladas, mesmo depois de mudar a configuração actual. Mesma chave com outro conteúdo, versão obsoleta e nova escrita em dossier fechado são recusadas; uma repetição anterior não escreve no dossier fechado. Novo pedido sem mudança reutiliza a revisão existente. Histórico de 25 com cursor permite recuperar revisões antigas no mesmo dossier; ID de revisão de outro dossier não é aceite. Revogação de coeditor é efectiva antes de leitura, replay ou validação, e membro de consulta não ganha escrita. A gravação não altera o cadastro, as etapas, os contratos ou os pedidos do Balcão.
+
+Interface usa profileJson/XSRF e lê valores reais do formulário incluindo preenchimento automático. Em falha conserva dados; consulta privada da edição actual permite comparação legível e adopção explícita da nova versão antes de voltar a guardar. Os dados privados não são transportados na querystring. Edição histórica e consulta têm campos só de leitura. Não houve prova de sessão expirada/login real no navegador.
+
+Provas finais: **18 Feature/343 asserções**, oito casos novos e dez do comparador anterior; **12 frontend**, seis novos e seis anteriores. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build passaram. A primeira ronda revelou uma chamada incorrecta à API decimal e a análise de tipo de uma colecção; corrigidas sem supressões. Um valor esperado num cenário extremo de acções foi corrigido após conferir o produto exacto. Só as provas finais aprovadas sustentam este recibo. QA exclusiva company_preparation_20261102_test, loopback 55441, guardas intactas, rollback conferido com zero pessoas/dossiers/organizações/declarações/pedidos. Não se ensaiou concorrência em dois processos como nova prova nem se importaram dados no activo.
+
+**Cobertura parcial:** preparação factual e histórico demonstrados; sete exemplares, biblioteca específica, cláusulas/derivadas contratuais, catálogo de actividades/licenciamento integrado, revisão profissional e percursos de assinatura/submissão/registo continuam pendentes. Não foi criado aprovador jurídico ou motor documental paralelo. Não se declara minuta pronta, contrato assinado, sociedade constituída, aceitação por cliente, observação visual ou instalação remota. Próxima acção: continuar os outros saldos autorizados; integrar os exemplares na biblioteca existente quando disponíveis, preservando estes dados e revisões. Recibo company_preparation_increment_20261102.
+
+
+### 02/11/2026 — AUD-CAPITAL-01: guia público de capitalização e referência privada recuperável
+
+Incremento iniciado em 02/11/2026; provas finais encerradas em 03/11/2026 (Africa/Johannesburg). As datas dos exemplares e o identificador do incremento mantêm a consulta original.
+
+Confrontados matriz/código/provas e segmentar processos v1.docx, original SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo 154 e bloco CAP-001 (702–708). O roteiro financeiro existente não continha o guia público e referência recuperável pedidos. Não se criou outro roteiro nem se contou a lacuna de evidência como desaparecimento das etapas financeiras. O incremento societário anterior e respectivos recibos permanecem preservados.
+
+Guia em /guias-investimento/capitalizacao, acessível de Como Investir e Documentos do dossier. Distingue capital próprio/entrada de sócios, private equity/capital de desenvolvimento, dívida e híbridos/convertíveis. Expõe conceitos, riscos e pontos a discutir, preparação/documentos, elegibilidade por entidade, fontes/edição/locators/data/hash e próximos passos. A selecção organiza os cartões, sem pontuação ou recomendação. Sem selecção, consulta-se o conjunto. Exemplos de BNI/IFC pertencem às respectivas entidades; nenhum montante, prazo, taxa ou percentagem é convertido em condição universal. O artigo educativo Chase suporta conceitos gerais de dívida/capital e riscos, não regras dos EUA aplicadas a Moçambique. Não há promessa de retorno, aprovação, produto disponível ou adequação a um caso concreto.
+
+Fontes primárias efectivamente lidas: [BNI Capital de Risco](https://www.bni.co.mz/banca-de-investimento/capital-de-risco/), [IFC Equity Investments](https://www.ifc.org/en/what-we-do/products-and-services/equity-investments), [IFC Loans](https://www.ifc.org/en/what-we-do/products-and-services/loans), [IFC How to Apply](https://www.ifc.org/en/what-we-do/products-and-services/how-to-apply-for-financing) e [Chase Debt vs Equity](https://www.chase.com/business/knowledge-center/grow/debt-vs-equity-financing). Cinco HTML originais em capital-guidance-sources-20261102, privados, com SHA256 conferidos no recibo. São exemplares da consulta de 02/11; não foi inventada uma data editorial. O guia conserva síntese própria e referências, não serve estes HTML ou scripts nem publica originais na biblioteca sem o percurso documental existente. Não se atribuiu scan novo ou direito de redistribuição ao arquivo auxiliar. O PDF IFC de 1999 foi encontrado mas não serve de norma vigente ou condição de produto; páginas BVM com mínimos de 2024 até 31/03/2025 não foram usadas como limites de 2026. Autenticidade oficial anteriormente aceite não foi novamente posta em aprovação genérica; fonte/edição/período continuam distintos.
+
+Escolher/criar dossier passa pelo InvestorPath.contexts e autenticação normal. Só códigos, slug e hash da edição seguem na URL. O servidor valida a edição antes de criar um dossier e não guarda a referência por arrasto. Criar contexto e confirmar referência são acções distintas. Selecção vazia é explicitamente transportada para não recuperar inadvertidamente uma escolha anterior. Não são repetidos nome, NUIT, contactos, morada, orçamento ou dados financeiros. A única informação livre adicional é uma nota opcional da preparação, introduzida no dossier privado e enviada por POST/XSRF. Não houve prova de login real no navegador.
+
+InvestmentGuides conserva a referência cifrada em desk_cases.payload.investment_guides e desk_events, com guia/fontes integrais da edição, instrumentos, nota, autor/data, âmbito dossier_reference e revisão/hash do contexto. A fonte externa pode mudar, mas o conteúdo guardado não é reescrito. Nova edição é explícita; escolhas que deixaram de existir são identificadas e permanecem no histórico. Referência histórica/antiga/retirada fica em consulta. Remover o guia actual não apaga a referência privada. Histórico paginado de 25, filtrado pelo mesmo guia/dossier; ID de revisão alheia é recusado. Alteração do contexto é visível e não reescreve a revisão anterior. Não se anexou por nome uma empresa, projecto, documento ou oportunidade de outro contexto.
+
+Permissões do dossier, bloqueio de linha e versão são reutilizados. Coeditor revogado não pode ler/repetir/validar na sessão anterior; membro só de consulta não ganha escrita. Mesma operação/conteúdo devolve a revisão original mesmo com guia alterado/retirado, usando a definição congelada. Mesma chave com outra nota é recusada; nova operação sem mudança não duplica evento/versão/aviso. Versão obsoleta e nova escrita em dossier fechado são recusadas; replay anterior não escreve. Falha conserva nota/escolhas, permite consultar a edição guardada e exige conferência explícita antes de adoptar outra versão do dossier. Se o guia tiver mudado ou sido retirado durante a preparação, não se confirma silenciosamente uma edição antiga. Auditoria e avisos existentes não expõem a nota.
+
+21 Feature/524 asserções: sete casos novos e 14 anteriores de InvestorPath/comparador; 13 frontend, sete novos e seis anteriores. Cobertura: consulta pública sem IA, instrumentos válidos/inválidos, fonte/hash, percurso HTTP de autenticação/escolha/criação, fonte desactualizada sem dossier extra, dados cifrados sem mudança de cadastro/etapas/pedidos, replay/no-op/conflito/encerramento, fontes/edições/retirada, 26 revisões/paginação, âmbito de histórico, mudança de contexto e revogação/consulta. Interface técnica: escape/fontes/edições, cartões, selecção vazia, valores reais incluindo preenchimento automático, gravação privada, recuperação de erro sem URL privada, escolha de dossier e leitura histórica/retirada. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build passaram, processos terminais conferidos. O primeiro cenário de contexto preparava uma chave de payload errada; fixture corrigida para a estrutura real, sem enfraquecer produção ou autorização. A revisão final acrescentou protecção da selecção vazia e recuperação perante guia alterado.
+
+QA exclusiva capital_guidance_20261102_test, PostgreSQL loopback 55441, guardas intactas; zero utilizadores/dossiers/organizações/declarações/pedidos após rollback. São cenários sintéticos. Sem migração nova, escrita no activo, contacto externo, submissão, intermediação, concessão, cálculo fiscal/financeiro ou mudança de etapas. Não foi alegada nova prova de concorrência em dois processos.
+
+Estado parcial local: o guia base e referência recuperável estão implementados. Restam observação visual/login real e disponibilização; condições particulares e decisões pertencem às contrapartes. AUD-CAPITAL-02 continua distinto: recuperar Código do Mercado de Valores Mobiliários e regulamentos por segmento, conferir artigos/redacção/períodos/alterações e explicitar intervenientes e lacunas sem usar mínimos expirados. Não apresentar o guia de capitalização como guião de admissão à Bolsa concluído. Recibo capital_guidance_increment_20261102.
+
+
+### 03/11/2026 — AUD-CAPITAL-02: guião BVM por segmento, fontes e recuperação no dossier
+
+Confrontados matriz, fontes e código. O guião bolsista estava efectivamente ausente; o guia de capitalização entregue no recibo capital_guidance_increment_20261102 e o seu mecanismo de referências foram reutilizados. Não se criou outro percurso, serviço de negociação, tabela de admissão ou competência de decisão do portal. O pedido de segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo155/bloco CAP-002, mantém o ID existente.
+
+Seis PDF BVM recuperados e conservados por hash em bvm-guide-sources-20261103: CMVM/DL4/2009 (68p), admissão1/2010 (28p), Segundo Mercado2/2010 (13p), Terceiro04/2021 (6p), mínimos01/2024 (2p) e Central25/2006 (10p). Reutilizado, sem duplicar original ou pedir nova aprovação da autenticidade, o Código Comercial republicado de25/05/2022, BR99/I Série/3.ºSuplemento,76p e SHA2568009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f. A data de aprovação em Conselho de02/06/2009 do exemplar do CMVM foi distinguida da publicação de24/07/2009 identificada no DL1/2022. Art.4 desse diploma altera arts.8 e52 do CMVM; o art.444 do Código Comercial limita as acções SAS. Não foi feita uma consolidação silenciosa dos dois textos.
+
+Skill PDF aplicada apenas a leitura/extracção/renderização, sem editar/criar PDF ou executar marcador de autoria. PyMuPDF/pypdf instalados em dependências privadas de leitura; a instalação terminou correctamente, apesar do wrapper PowerShell assinalar a notificação de nova versão pip em stderr. As imagens do Terceiro Mercado e dos mínimos não contêm texto extraível; todas as seis/duas páginas foram conferidas visualmente. Pontos críticos do CMVM, anexos de documentos, Segundo Mercado, Código Comercial e Central também foram vistos em imagem;20 PNG inspeccionados estão identificados por hash no recibo. Extracções completas por página e inventário privados conservados. O HTML da BVM é uma shell React e não foi tratado como conteúdo normativo completo; bundle público foi consultado como fonte auxiliar de navegação, sem executar scripts ou contornar autenticação. O leitor web deu timeout em PDFs, mas HTTP directo recuperou os originais, conferidos pela assinatura PDF e hashes. Não se declarou scan antimalware novo ou publicação desses originais na biblioteca.
+
+Guião público /guias-investimento/bolsa, ligado de Como Investir, Documentos do dossier e guia de capitalização. Cinco percursos: acções e obrigações no MCO, acções e obrigações no Segundo Mercado, acções no Terceiro Mercado. Selecção organiza comparação; não decide admissibilidade ou aplica critérios a partir de nacionalidade do utilizador. Os exemplos empresariais não são automaticamente aplicados a fundos públicos/equiparados, outros valores, operações especiais ou valores estrangeiros. Os limites e bases dos casos especiais são identificados.
+
+Cada requisito/dispensa/lacuna referencia fonte, edição, artigo e página do PDF, com ligação directa ao ponto de partida da disposição. O guião distingue condições de contas e dispersão dos segmentos, documentação e prospectos: Anexos A/B de instrução documental do processo de admissão não são confundidos com Anexos A/B dos prospectos do Segundo Mercado. Dez grupos documentais, com identificador único e âmbito por percurso; comuns aparecem uma vez na escolha múltipla. Auditoria de entrada fica fora do grupo documental do Terceiro Mercado, mas as demonstrações PGC-NIRF assinadas por contabilista OCAM e a conferência da declaração de actualidade permanecem. Reutilizar documentos no dossier é o percurso existente; não se pediu nova introdução de nome, NUIT, morada, capital ou participações.
+
+Divergências concretas: Reg04/2021 revoga04/2019 (art9), define horizonte de até dois anos para conformidade, com eventual prorrogação excepcional fundamentada de mais um ano, e prestação semestral de informação. A página informativa ainda referia nove meses e exclusão geral dos pontos5/10 do AnexoA; esses enunciados não foram importados como regras de 2021. A dispensa de contas auditadas é de entrada, não perpétua; não foi estendida sem base à declaração do ponto10. O regime de2022 dos valores nominativos e a limitação de acções SAS foram incorporados, sem inventar uma nova regra organizacional. Prazos notificação/publicação são apresentados com condições e fonte; não criam aprovação por silêncio, extensão automática ou calendários do portal.
+
+Os mínimos01/2024 vigoravam até31/03/2025, conforme imagem do próprio preâmbulo. Não se reutilizaram os seus valores como mínimos de2026 nem se derivaram limites actuais por proporção de montantes expirados. Cada percurso conserva value:null/unit:MZN no requisito de montante; relações legais com mínimos de outros mercados são descritas sem cálculo. O regulamento anual actual e encargos/preçário ficam explicitamente por obter/conferir com BVM/operador, sem converter desconhecido em zero ou impedir a gravação privada. Os procedimentos operacionais CVM de2025 foram identificados no portal oficial mas não integralmente recuperados/codificados; o decreto de2006 serve a identificação institucional, não uma alegação de cobertura desses procedimentos recentes.
+
+Intervenientes e seis etapas distinguem emitente/requerente, operador patrocinador/interlocutor, BVM decisora, Banco de Moçambique supervisor e respectivas competências sobre ofertas públicas, e CVM como serviço gerido pela BVM. Encaminhamento oferece ligações oficiais de informação, sem transportar nota, dossier ou documentos; não há mensagem, pedido, oferta, registo, negociação ou admissão enviados pelo portal. Decisões externas e documentação real conservam os passos financeiros existentes, sem avanço por guardar o guia.
+
+InvestmentGuides existente mantém fontes/guia/escolhas/nota/contexto por snapshot cifrado e revisão. Não houve nova alteração ao motor de persistência. Provas novas verificam dois guias no mesmo dossier, protecção contra replay de chave de outro guia, recusa de revisão alheia e paginação de26 revisões BVM intercaladas com26 do guia de capitalização. As referências não se misturam; notas/fontes anteriores permanecem recuperáveis. Os sete casos anteriores de guias mantêm âmbito, autenticação, fonte desactualizada, ausência de criação por arrasto, permissões, revogação, encerramento, replay/no-op e snapshots de edição retirada.
+
+Provas finais: **14 Feature/474 asserções**, sete casos BVM e sete de guias anteriores; **18 frontend**, cinco novos e13 anteriores. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build aprovados; processos terminais conferidos. A primeira ronda teve13/14 testes aprovados: a expectativa de citação só aceitava Art maiúsculo e recusava art.444; o teste foi corrigido para comparação de letra/Unicode, sem relaxar as referências de produção. Interface técnica confere requisitos/edições/links, dispensa de auditoria no percurso devido, OCAM/actualidade, documentos comuns uma vez, diferenças entre contas/prospectos, ausência de dados privados em links externos e leitura histórica sem escrita. Não se confundiu a inspecção visual dos PDFs fonte com aceitação visual da aplicação, login real ou utilização por cliente.
+
+QA exclusiva bvm_admission_20261103_test, PostgreSQL loopback 55441, guardas intactas; zero utilizadores/dossiers/organizações/declarações/pedidos após rollback, com visibilidade/owner das tabelas registados. Não houve migração, importação no activo, activação de cálculo, alteração de cadastro, mensagem externa, instalação remota ou nova prova de concorrência em dois processos.
+
+**Saldo concreto:** montantes anuais actuais, encargos/preçário actual, procedimentos CVM recentes completos, casos especiais não abrangidos/alterações posteriores, observação visual/login real e disponibilização. O guião base e a referência privada são demonstrados; admissão real e cobertura integral da regulamentação não foram declaradas concluídas. Próxima acção: continuar os outros saldos autorizados da matriz, mantendo estes campos indeterminados até recuperar as fontes aplicáveis e preservando os dois guias já entregues. Recibo bvm_admission_increment_20261103.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: indicadores operacionais, bases e cobertura
+
+[PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103.
+
+Fonte funcional efectivamente relida: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420; confronto com métricas dos parágrafos 865–871 da segmentação bf26caee e com o código. O painel específico estava ausente; contagens do dashboard e DeclaredOriginStatistics existentes foram preservadas. AUD-STATS-01 continua separado e parcial; AUD-HUMAN-03 continua dependente dos pesos/limiares/pilotos concretos, sem bloquear as contagens factuais autorizadas nem inventar um score.
+
+Consulta em /management/product-usage, ligada do dashboard do gestor global. Autenticação, correio verificado e manage-portal já existentes; revogação volta a negar acesso. Período UTC inclusivo por dias, limite superior exclusivo min(dia seguinte, agora), código do serviço cobre as suas edições históricas. Não há limite arbitrário de dias ou mistura de linhas entre dossiers, pedidos e pessoas. Segmento de serviço dos dossiers/ referências exige um pedido desse código também criado no período; a definição é visível.
+
+Taxas: primeira submissão por pedido com draft_created v1 e versões contíguas observáveis até ao corte; o campo submitted_at mutável não é usado como primeira data. Histórico insuficiente fica excluído e quantificado; taxa de um subconjunto não é publicada como funil integral. Devolução conta uma vez após a primeira submissão, mesmo com reenvios e decisões repetidas. Causa específica exige código explícito validation_error/missing_documents; texto livre não é interpretado. Um pedido com causa comprovada permanece positivo apesar de outra devolução sem categoria; nos restantes, desconhecido impede taxa específica exacta. Numerador conhecido e denominador ficam visíveis. Média rascunho→primeira submissão usa apenas intervalos não negativos, identifica excluídos e não se intitula tempo de criação do projecto ou SLA. Rascunho ainda sem submissão não é abandono.
+
+Categoria de devolução opcional, configurada uma vez e entregue à interface; servidor exclui-a nas restantes transições e mantém as regras de independência, campos de correcção, versão e fundamento anteriores. Regista código, rótulo e versão da definição no payload cifrado do evento, sem reescrever o passado. Eventos VirtualDesk novos passam a registar explicitamente a hora da aplicação: o default PostgreSQL now() era a hora de início da transacção, podendo anteceder o rascunho criado dentro dela. Registos anteriores são preservados; intervalos negativos não são corrigidos por suposição.
+
+Consulta PostgreSQL numa transacção read only/repeatable read quando possui a transacção exterior; dentro de transacção já existente identifica essa condição e não substitui o contexto de acesso. Leitura por lotes de 100 pedidos; só desencripta payloads de devolução necessários à categoria, sem devolver motivos/nome/ID/payload privado. Exportação JSON reutiliza exactamente o relatório aplicado, sem nova chamada ou guardar filtros por aplicar. Fingerprint identifica o conteúdo, não certifica fontes independentemente. Não há migração ou novo evento de visitante, termo de pesquisa, IP, cookie ou identificador de navegação.
+
+Verificações: 24 Feature/338 asserções (7 casos novos e 17 regressões de guias/edições de serviço), 11 frontend, PHPStan/Pint, tipos e lint aprovados, build terminal aprovado. Primeira ronda apanhou um fecho de array em falta na validação e consequentes falhas; corrigido e repetido o lote, sem reduzir asserções. Formatação inicialmente abrangente foi interrompida e substituída por ficheiros explícitos; inventário de horários não mostrou edição de ficheiros alheios ao incremento. QA product_usage_20261103_test em loopback 55441, guardas preservadas. A prova posterior sem transacção de PHPUnit confirmou SHOW transaction_read_only=on e repeatable read em todas as consultas observadas; após rollback, seis colecções vazias conferidas com proprietário/RLS, sem actor ocultar linhas. Não é prova visual/login em navegador real, concorrência em dois processos, medição com utilizadores reais ou instalação no destino.
+
+Saldo 03/11/2026: primeiro painel operacional local implementado; não equivale à cobertura integral de métricas de produto. Restam aquisição/activação, pesquisa e zero resultados, comparação pública, correspondência individual CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão do roteiro versionado, tempo projecto/submissão e etapas, abandono, satisfação/suporte, pós-investimento e registo de experiências controladas com hipótese/indicador/período/segmento/resultado/decisão. Não foram inventados pesos, baseline de pilotos, limiares, consentimentos ou eventos de visitantes. Visual/login real e disponibilização continuam pendentes.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: registo de experiências, planos e observações por versão
+
+[PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa.
+
+Fonte funcional: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420, já conferida no incremento de indicadores. Reutilizados a matriz, o recibo product_usage_metrics_increment_20261103, os indicadores operacionais e a competência global manage-portal existente. O registo estava ausente no código/schema; não se reclassificou contagem anterior como experiência ou piloto real. AUD-HUMAN-03, AUD-STATS-01, contratos modulares experimentais e SLA mantêm os âmbitos/decisões próprios.
+
+Entrada pelo painel de indicadores, com lista/filtro/paginação de registos e novo rascunho que aceita informação ainda incompleta. Plano registado exige hipótese, indicador, período UTC, segmento, controlo/variante, método de comparação, critério e medidas de transparência/consentimento/segurança/igualdade. A declaração de preservação dos requisitos não executa ou aprova a alteração. Observação/resultado/decisão distinguem datas previstas das efectivamente observadas, evidências declaradas, limitações, controlo/variante descritos e fundamento. Pode registar conclusão inconclusiva; não há números, amostras, limiares, responsáveis nominais ou decisões automáticas fabricados. Rascunho/plano/observação/decisão/cancelamento são estados documentais, corrigíveis por nova versão e motivo, sem substituir o workflow dos processos.
+
+Cada versão guarda values cifrados, autoria real do actor autenticado, data de servidor, motivo, vocabulário, edição da definição do indicador e hashes. Indicador próprio é uma definição manual explícita; indicadores do painel reutilizam a definição do servidor e conservam a edição anterior até adopção explícita da nova. Dados de campos inactivos conservam-se sem os exigir ao ramo activo. Actualização meramente descritiva não actualiza silenciosamente a definição manual. Leitura histórica usa o vocabulário/definição realmente guardados. O primeiro plano registado conserva a data real, sem aceitar autoria/data de registo impostas pelo cliente ou alegar pré-registo por inferência.
+
+Alterar plano já registado exige confirmação explícita e motivo; conta revisões e identifica alteração após observação. A observação mantém plan_sha256 do plano em que foi registada. Alterar período pode preparar outro plano sem reescrever datas/resultados anteriores: fora do âmbito actual, permanecem históricos e identificados. Para registar observação/decisão como referente ao novo plano, o autor revê/reforça essa ligação explicitamente; datas devem então caber no período correspondente e não ser futuras. Nada disto transforma um resultado anterior em prova do plano novo.
+
+Relatório operacional opcional é capturado pelo ProductUsageMetrics, no servidor e em leitura consistente antes da transacção de escrita, conservando o seu âmbito efectivo quando já existir transacção exterior. Apenas filtros/datas autorizados são aceites; payload/report forjados não são usados. Fonte/edição/corte/cobertura/numerador/denominador/indeterminados ficam no snapshot. A legenda operational_cohort_not_experiment_arm é explícita: esse relatório não mede o segmento livre, não separa grupos e não comprova causalidade. Mudar datas/serviço conserva o relatório anterior e assinala divergência; anexar outro/remover da próxima versão exige acção explícita, sem apagar o histórico. Referências livres de evidência são texto, sem fetch/importação ou afirmação de validação dos documentos referidos.
+
+Product_experiments mantém origem/versão/estado e liga a revisão actual por FK diferível; product_experiment_revisions conserva snapshots cifrados, operação/hash/autoria, unicidade e versões. Gatilhos PostgreSQL rejeitam alteração/remoção/truncagem do histórico, remoção de registos, recuo/salto de versão ou alteração da origem. O rollback da migração recusa dados já existentes. Autorização volta a ser verificada no serviço; autenticação/correio verificado/privacidade e throttle existentes aplicam-se às rotas. Não há novos perfis/aprovadores, dependência de IA, mensagens externas, distribuição de visitantes, cookies ou termos de pesquisa.
+
+Repetição de escritas conserva a primeira versão/autor/snapshot, mesmo após revisão posterior ou mudança de catálogo. Conteúdo diferente com chave já consumida dá conflito; versão desactualizada não substitui a actual. A interface mantém o rascunho em erro, consulta a versão actual e compara três vias: acompanha os campos editados, inclusive quando o autor os repõe deliberadamente no valor inicial; funde apenas os não editados, exige escolha nos conflitos reais e só adopta a base após revisão. Relatório/indicador corrente do coeditor são reutilizados, sem copiar payloads do cliente como autoridade. Histórico e exportação referem-se à versão consultada; o formulário histórico usa a versão dessa origem e bloqueia submissões, mesmo se o evento for disparado programaticamente. A gravação também fica bloqueada enquanto a comparação estiver pendente. Esquema indisponível é distinguido de zero registos e não desactiva os indicadores anteriores.
+
+Verificações finais: 18 Feature/271 asserções (11 casos novos e 7 regressões de indicadores), 7 frontend (5 novos e 2 anteriores), análise estática/Pint/tipos/lint/build aprovados. Primeira ronda: referência errada a tabela de interesses e teste de TRUNCATE interrompido por FK diferível ainda pendente; corrigida a referência pela entidade real e validada a FK antes de testar o gatilho, sem alargar os SQLSTATE aceites. A repetição de migrate:fresh revelou funções de gatilho conservadas após remoção das tabelas; a migração passou a usar CREATE OR REPLACE para as suas funções, sem enfraquecer os gatilhos ou alterar as guardas de QA. A repetição final instalou efectivamente o esquema sobre essas funções existentes e passou. Três diagnósticos de tipos iniciais resolvidos na origem, sem supressões. A revisão delimitou também a preservação das observações ao alterar o período e acrescentou prova específica. Todos os logs anteriores foram conservados. QA product_experiments_20261103_test, loopback 55441, guardas inalteradas; uma migração ensaiada apenas aqui. Após rollback, nove tabelas e eventos de auditoria do módulo vazios, com visibilidade/proprietário/RLS e três gatilhos/FK conferidos. Não é prova visual/login em navegador, concorrência em dois processos, experiência real com utilizadores ou instalação no destino.
+
+Saldo 03/11/2026: painel factual e registo manual versionado implementados/ensaiados localmente. Restam ligação transversal das alterações/editores ao registo, atribuição/execução de variantes e eventos por grupo com consentimento/âmbito definidos; aquisição/activação, pesquisa/zero resultados, comparação pública, CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte e pós-investimento. Pesos/pilotos de AUD-HUMAN-03 permanecem uma definição distinta; nenhum score inventado. Visual/login real e disponibilização/migração no destino continuam pendentes.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: respostas de pesquisa, edições e recolha independente
+
+[PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa.
+
+Fonte funcional preservada: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420. Recibos product_usage_metrics_increment_20261103 e product_experiments_increment_20261103 reutilizados; o registo e as contagens anteriores não foram reabertos como ausentes. AUD-HUMAN-03 continua separado, sem aprovação/garantia de sucesso por métrica. Inventário do código distinguiu as respostas públicas com total principal dos pedidos auxiliares, buscas privadas e fontes ainda não instrumentadas. A política de privacidade já previa estatísticas agregadas; foi acrescentada apenas uma descrição factual dos dados destes contadores e dos sinais respeitados, sem interpretação legal, cookie novo ou recolha de identidade.
+
+Nove canais: página de oportunidades, API de oportunidades (moderna e alias legado pelo seu próprio controlador), página de oportunidades educativas, negócios existentes, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Os controladores assinalam o total realmente obtido no paginador/lista principal depois da validação. Middleware global conta uma vez apenas depois de uma resposta HTTP200 produzida, GET e primeira página, com critério explícito normalizado; navegação sem critérios, apresentação/sort, paginação seguinte, HEAD, prefetch e erros não entram. Filtros implícitos da página de educação não fazem dessa entrada vazia uma pesquisa. Metadados internos não são aceites de um endpoint cliente ou de um parâmetro de total. Mapas, referências, sugestões, exportações, gestão e consultas privadas não entram. Pesquisas nos restantes canais, incluindo fundos e correspondências internas de educação, permanecem saldo concreto.
+
+Unidade: respostas HTTP registadas, não pessoas, pesquisas únicas ou todas as interacções no navegador. Actualizar/repetir a primeira página conta nova resposta; cache/CDN pode não executar a aplicação, bots não são separados e uma falha de recolha pode omitir amostras. O denominador é sempre a base registada, com cobertura parcial explícita. Sem linhas não é zero pesquisas; canal nunca observado fica sem medição, enquanto zero respostas vazias com base positiva produz uma taxa0% legítima. Uma pesquisa com total principal0 e sugestões relacionadas mantém-se sem resultados principais; não se alarga o critério original para melhorar a estatística. Mantida a pesquisa plantio de algodao e as suas regras demonstradas.
+
+Product_search_counts contém apenas dia UTC, código fixo de canal, edição, número de respostas/zeros e primeiro/último instante agregados; não contém consulta, valores de filtros, actor, endereço, cookie, IP, token ou identificador de pedido/visitante. DNT:1 e Sec-GPC:1 omitem recolha. Product_search_definitions conserva uma vez a definição/vocabulário/exclusões/hash por edição; FK e gatilho impedem substituir ou remover a definição. Reutilização de uma edição com configuração diferente recusa novas contagens, regista diagnóstico redigido e assinala conflito ao gestor. Outra edição cria série própria; o relatório permite escolher as anteriores, usa a definição efectivamente conservada e não soma silenciosamente métodos diferentes. Sem backfill ou inferência de tráfego anterior.
+
+INSERT ON CONFLICT incrementa atómicamente os dois contadores e preserva os limites temporais com LEAST/GREATEST. A recolha usa transacção/savepoint e limites técnicos configuráveis de bloqueio/statement (predefinições100/300 ms), respeitando limites mais curtos do chamador e restaurando as definições originais. Falha SQL, bloqueio ou falha do próprio log não substituem a resposta de pesquisa nem deixam a transacção exterior abortada. Ausência da tabela desactiva a recolha de modo delimitado; configurar desligado conserva a consulta histórica. Diagnósticos incluem só canal/edição/classe de erro, sem mensagem/SQL/pedido ou valores pesquisados. Os limites técnicos não constituem SLA ou prazo de negócio.
+
+Painel ProductUsageMetrics com três indicadores de respostas/zeros/taxa e tabela por canal, edição seleccionável, base/cobertura/exclusões e exportação do snapshot aplicado. Contagens diárias são lidas no snapshot da transacção; o dia actual é parcial e não permite corte por fracção de segundo. Esse âmbito foi distinguido do corte de eventos do Balcão. O filtro de serviço não é associado por inferência às pesquisas públicas e deixa estes valores sem cálculo. ProductExperiments conserva o relatório contextual e a sua edição; a comparação de datas/serviço considera esses campos, sem rejeitar o novo metadado da edição de pesquisa. Não transforma esses totais em amostras de controlo/variante, causalidade ou score. Relatórios antigos sem a extensão continuam legíveis.
+
+Provas: 32 Feature/501 asserções (11 casos novos, 3 regressões da pesquisa rápida, 7 de indicadores e 11 do registo), 9 frontend (2 novos e 7 anteriores), PHPStan/Pint/tipos/lint/build aprovados. Primeira ronda passou30/32: faltava o ponto de recolha do alias, que usa outro controlador, e o exemplar legado sintético não continha os metadados exigidos; corrigidos sem remover validação/publicação, reduzir asserções ou alterar resultados. Provas cobrem os nove canais reais, ausência de PII na estrutura, exclusões, sinais de privacidade, erros de escrita/log, recuperação da transacção, datas, separação/imutabilidade de edições, desligamento/histórico e ausência de associação a serviço. Duas conexões PDO reais provaram o limite de bloqueio e reposição do funcionamento após libertação.
+
+Concorrência adicional: base exclusiva search_metrics_concurrency_20261103_test com apenas as duas tabelas novas; dois processos PHP/PIDs diferentes, 1.861790s de sobreposição real,100 chamadas sintéticas cada e retenção de300ms na primeira transacção para provocar disputa. Orçamentos técnicos alargados apenas neste ensaio. Resultado confirmado no PostgreSQL após commits:200 respostas,150 sem resultados e uma única linha/definição, sem perda de incrementos. Relógio e dados sintéticos explícitos; não representa visitantes reais ou aceitação. Essa base conserva a prova, sem limpezas de dados activos.
+
+QA funcional search_metrics_20261103_test em loopback55441, guardas preservadas; após rollback, onze tabelas vazias com proprietário/RLS/visibilidade e gatilho conferidos. As duas bases/provas anteriores de indicadores/registo são preservadas. Uma migração nova ensaiada apenas em QA, funções CREATE OR REPLACE compatíveis com a repetição de migrate:fresh, sem aplicar no destino. Não é prova visual/login em navegador nem instalação activa.
+
+Saldo 03/11/2026: painel factual, registo manual de experiências e contagens de pesquisa dos nove canais implementados/ensaiados localmente. A medição é de respostas HTTP registadas, não pessoas/pesquisas únicas, visitas ou utilização integral; recolha best effort e fontes não instrumentadas, incluindo fundos e correspondências internas, continuam identificadas. Restam aquisição/activação, comparação pública, correspondência CRM/qualificação/reuniões/diligência/propostas, investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte/pós-investimento; ligação transversal dos editores/alterações e execução/eventos de variantes. Pesos/pilotos de AUD-HUMAN-03 são definição distinta, sem score inventado. Visual/login real e disponibilização/migração no destino pendentes.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: selecção múltipla e declarações versionadas no Balcão
+
+[DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo.
+
+Fonte: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo extraído481: tipos texto/número/data/lista/selecção múltipla/localização/anexos/consentimento, versões/vigência/condições/obrigatórios/limites/formatos/erros/rascunhos. Parágrafos161 e565 mantêm três camadas de obrigações, registo/publicidade e licenciamento sectorial e o modelo reutilizável. Identidade/hash do original novamente conferidos; sem reimportação ou alteração. Inventário anterior: editor/histórico, validação de perguntas aplicáveis e vigência já implementados em desk_forms_increment_20261102, desk_analysis_scope_increment_20261102 e desk_effective_dates_increment_20261102. Não foram reclassificados como ausentes. Os37 logs de vigência/métricas/registo/pesquisa acima reconferidos conservam bytes/hashes; recibos anteriores preservados integralmente.
+
+Âmbito: mesmos códigos de serviço, fontes, rotas, permissões e motor. O editor publica tipos multiselect/consent e statement (texto obrigatório exclusivo de consentimento); valida códigos, referências, ciclos e adequação equals/contains. A fonte territorial tem de continuar disponível sempre que a localização se aplica. Ao converter lista simples/múltipla, opções mantêm códigos e condições directas passam a igualdade/inclusão; a alteração é visível na comparação e exige confirmação de publicação, sem reescrever versões.
+
+O requerente pode guardar rascunho inteiramente vazio; omitir payload continua inválido e submeter exige respostas aplicáveis. Multiselect aceita lista distinta de até100 códigos string declarados, incluindo string0; escalar, objecto, código numérico, repetido ou desconhecido são recusados. A ordenação normaliza a semântica de conjunto, permitindo retry sem nova submissão. Ausência/null/lista vazia não satisfaz obrigatório; opções não seleccionadas não se tornam decisões implícitas.
+
+Consentimento conserva texto e escolha explícita accepted/declined; nenhum valor predefinido ou herança de perfil/contexto. Obrigatório exige aceitar ou recusar, sem forçar aceitação ou inventar um impedimento organizacional. Campo opcional por responder permanece desconhecido. Consentimento geral de submissão, competências, decisões de processo e licenças continuam separados. Cada declaração respondida e aplicável recebe no snapshot cifrado texto/label/hash/escolha/actor/instante e service_version_id gerados pelo servidor; metadados enviados pelo cliente não substituem esse vínculo. Declaração oculta conservada no payload não integra declarações aplicáveis. A interface permite limpar a resposta e respeita leitura/correcções autorizadas.
+
+Tipos e valores mantidos na reutilização: escolhas múltiplas, zero numérico e recusa não são apagados por trim/coerção ou por prefill sem substituição explícita; consentimento nunca é herdado, mesmo ao substituir outros dados. Rótulos de multiselect e texto/hash/escolha no recibo HTML provêm da edição ligada ao pedido; original técnico TXT continua a transportar o snapshot completo. Valores ocultos permanecem na secção histórica, sem activar descendentes; texto escapado, permissões e no-store mantidos. Publicar nova edição/texto/opções não modifica pedidos ou snapshots anteriores.
+
+Provas:27 Feature/347 asserções (11 novos casos + regressões editor/vigência) e13 frontend (6 novos casos + condições/vigência); análise estática em cache isolada sem supressões, Pint, tipos, lint e compilação terminados com sucesso. Avisos de compilação existentes relativos ao tamanho de chunks, fontaine opcional e tempo de plugins não são erros de execução. Primeira execução:24/25, falha por asserção com nome de evento incorrecto (submitted), corrigida; tipos unknown incompatíveis com contrato Inertia foram substituídos por união real das respostas, remoção de array_values redundante após sort conforme diagnóstico PHPStan. Ficheiros/logs de diagnóstico anteriores conservados em storage/app/private.
+
+QA exclusiva desk_typed_fields_20261103_test, loopback127.0.0.1:55441, role/owner investmoz_test e DB_URL vazio, sem alterar a guarda do TestCase. Doze tabelas sem linhas retidas após rollback, RLS/FORCE false conferidos com a identidade efectiva. Nenhuma migração nova, publicação real de formulários, conta real, mensagem externa ou escrita na base activa. Compilação local não equivale a disponibilização.
+
+03/11/2026: editor, histórico, vigência, selecção múltipla e declarações de consentimento do Balcão implementados/ensaiados localmente. Restam outros consumidores/contextos de checklist, cobertura transversal dos tipos/regras/limites/anexos, autosave/recuperação nos contextos ainda não demonstrados, três camadas de obrigações/registo/licenciamento por fonte e âmbito, visual/login real e disponibilização. Não equivale a homologação, licença ou parametrização integral. Conferência visual/navegador continua limitada pela ferramenta já documentada; HTTP/SSR/SQL não são aceitação visual/utilizadores reais. Próximo resultado: conferir consumidores e os restantes critérios p481/p161 sobre o mesmo motor, distinguindo lacuna real de capacidade já demonstrada. ACT-16 mantém resposta ainda nao; modelos societários continuam sem URL fornecida, sem impedir estes incrementos independentes.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: gravação automática, recuperação privada e conflitos
+
+[DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa.
+
+Fonte já identificada: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo481 exige gravação automática/recuperação, condições, formatos, limites e versões; p161/p565 mantêm os contextos/modelo próprios. Conferidos código e provas de editor/vigência/tipos, não recriados. A cópia automática faltava no pedido do Balcão; simulador e outros rascunhos existentes mantêm motores/âmbitos próprios. Constrangimentos técnicos resolvidos antes de activar: formatos incompletos não podiam passar pela submissão estrita, o save manual incrementava a versão principal e notificava intervenientes, resposta perdida exigia repetição idempotente e dois separadores não podiam sobrescrever silenciosamente. Não foram transformados em novas regras da Tempo.
+
+Implementação: tabela desk_request_checkpoints com uma cópia corrente cifrada por request_id/actor_id; versão própria, base_request_version (coluna request_version), chave/hash da tentativa e datas. FKs e versões positivas; rollback recusa apagar cópias retidas. Mesma autorização de escrita do VirtualDesk, estado draft/returned e dossier aberto, confirmação da versão principal sob lock. Representantes com escrita conservam cópias separadas; gestor/analista sem representação não lê a recuperação, membros de consulta/revogados não acedem. GET/POST /balcao-virtual/pedidos/{id}/rascunho são autenticados/verificados/privados/no-store, no mesmo throttle e CSRF. A cópia não concede papel/competência nem aprova/submete nada.
+
+Payload/razão/base/intenção cifrados; auditoria regista apenas versão da cópia e versão principal, sem respostas. Nenhum desk_event, notificação ou snapshot de declaração é criado por autosave. Reutilizada a validação comum: tipos/limites/opções/consentimento/território/keys continuam controlados; apenas formatos textuais de número/data/email/URL podem ficar incompletos na cópia. Gravação manual e submissão conservam os formatos estritos existentes e campos obrigatórios aplicáveis. Base do pedido é obtida no servidor; parâmetros de submissão/consentimento/base forjada são recusados. Campo removido/omisso/limpo e zero mantêm intenção; alterações são derivadas também no servidor. Em devolução, dados e intenção respeitam somente campos autorizados.
+
+Interface: pausa técnica2s e uma tentativa em curso; alterações entretanto digitadas mantêm-se e são guardadas a seguir. Pedido/consentimento global/revisão do contexto não entram na tentativa. Resposta perdida conserva exactamente corpo/chave da tentativa para repetição; não substitui essa tentativa por edições novas. Erro de validação espera nova edição, sem ciclo de retry; normalização do servidor não gera writes incessantes. Falha de rede/sessão mantém a página e permite repetir ou comparar; aviso de saída apenas quando há edições ainda não confirmadas. Sem localStorage/sessionStorage/cookie de respostas, nem alegação de escrita garantida no unload. Confirmar saída pode perder alterações ainda sem confirmação; estado explícito e cópia confirmada no servidor distinguem-se.
+
+Recuperação: compara base antiga, página, cópia da conta e versão principal actual. Edição deliberadamente revertida ainda é intenção; conflitos exigem escolha e campos não alterados adoptam a versão actual. Oportunidade/contexto associado recuperam-se como unidade, sem mostrar hashes/JSON técnicos no formulário. Listas apresentam rótulos da definição ligada ao pedido e declarações distinguem aceitação/recusa/desconhecido. Resolução é gravada com CAS antes de adoptar os dados/base na página, de modo que falha de rede também permite retry da resolução congelada. Recuperar limpa consentimento global e revisão/revisão do contexto; precisa de nova acção explícita para submeter. Estado encerrado/submetido impede nova cópia; a consulta autorizada continua disponível. Falta da migração conserva o percurso manual, sem declarar autosave disponível.
+
+Correcção conexa: VirtualDesk::save não verificava closed_at antes da escrita, embora criação e anexos já o fizessem. Agora rejeita gravação/submissão num dossier encerrado e preserva consulta/idempotência sem escrita do que já está submetido. Não redesenha fecho, alçadas ou sequência do workflow.
+
+Provas: 38 Feature/487 asserções (11 novos casos de recuperação +27 regressões editor/vigência/tipos) e21 frontend (8 novos +13 anteriores); PHPStan em cache isolada, Pint, tipos, lint e build terminados com sucesso. Incluem snapshot cifrado, privacidade por actor/organização/revogação, ausência de notificações/submissão, formatos parciais vs submissão estrita, vazio/zero/limpeza, CAS/retry/base principal, âmbito de devolução e migração ausente/rollback. Frontend exercita debounce/serialização/edições durante write, resposta perdida/normalização/validação, recuperação e versão/flags no pedido, contexto atómico e navegação pendente. Primeira ronda35/36: expectativa do teste omitia regime pré-preenchido efectivamente removido no payload; corrigida a expectativa sem esconder a intenção real. Diagnósticos anteriores mantidos em storage/app/private.
+
+Concorrência real: dois processos PHP/conexões PG sobrepostos por0.266754s na base desk_checkpoint_concurrency_20261103_test; A guardou, B recebeu409, checkpoint v1 e uma auditoria, principal v1/cifra original intactos. Dataset sintético de corrida preservado, não representa utilizadores reais. QA funcional desk_checkpoint_20261103_test, loopback127.0.0.1:55441, DB_URL vazio/role investmoz_test;13 tabelas sem linhas retidas e owner/RLS/FORCE conferidos após rollback. Guarda de testes intacta. 45 logs anteriores reconferidos;56 recibos anteriores conservados e deltas intencionais de VirtualDesk/página/teste de condições/política discriminados no novo recibo.
+
+Uma migração apenas em QA, nenhuma escrita/migração no activo ou comunicação externa. Política de privacidade recebe descrição factual/condicional da cópia cifrada, sem nova interpretação legal. Avisos de chunks/fontaine/tempos de plugins na compilação continuam não bloqueantes. 03/11/2026: Balcão tem editor/histórico/vigência/tipos múltiplos/declarações e gravação automática/recuperação privada demonstrados em QA. Restam outros consumidores/contextos de checklist e respectivos critérios p481, configuração transversal de limites/anexos/formatos/mensagens, camadas de obrigações gerais/registo/licenciamento por fonte e âmbito, observação visual/login real e disponibilização/migração no destino. Não é homologação nem parametrização integral. Conferência visual/login por navegador continua limitada pela ferramenta documentada; HTTP/SSR/SQL não substituem essa aceitação. Não se declarou cobertura integral da fonte p481, outros consumidores ou inventário legal das três camadas. Próxima acção: restantes limites/tipos/regras por consumidor e fonte, com os mesmos motores. Modelos societários sem URL e línguas nacionais sem tradução mantêm as respostas já registadas.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: perguntas de anexos, limites e reutilização documental
+
+[DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa.
+
+Fonte preservada: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, p481 (campos/anexos/versões/vigência/condições/obrigatórios/limites/formatos/erros/rascunhos); p161/p565 mantêm as três camadas e o modelo documental. Hash do original reconferido, sem reimportação. Inventário inicial e recibo desk_checkpoint_increment_20261103 confirmaram editor/vigência/tipos/recuperação existentes; faltavam perguntas documentais com limites por edição. Não foram recriados os motores nem declaradas ausentes as capacidades anteriores.
+
+Editor: attachment, mime_types, max_size_kb e max_files, com declaração explícita de formatos/limites/obrigatoriedade, comparação/histórico pelo mesmo formatador, confirmação/motivo/base_version/vigência e auditoria. Tipos canónicos existentes conservados. Limites pertencem apenas ao tipo de anexo; formatos distintos por pergunta e nunca globalmente entre perguntas. Formatos suportados mantêm PDF/PNG/JPEG/TXT e limites técnicos anteriores; não se activou DOCX/formatos arbitrários. Condições comparam respostas apropriadas, sem usar anexos ou números como comparadores; fonte retirada/incompatível fica visível para correcção no editor. Pedidos antigos mantêm a FK e os limites da sua edição.
+
+Armazenamento/identidade: o payload guarda IDs de vínculo desk_documents, seleccionados por nome/versão/estado/referência; não duplica ficheiros. Uma migração troca a unicidade antiga case/document por dois índices parciais: uso global do dossier e uso por pedido. Todas as linhas/UUID/FKs/originais são conservados; rollback recusa perder usos que a regra anterior não consegue representar. Duplicação de upload é por bytes dentro do dossier, como já acontecia; não se fundem entidades/ficheiros por igualdade de nome nem por hash entre dossiers. O mesmo document_id pode ter vínculos específicos distintos e apoiar várias perguntas. Aliases do mesmo original não contam como dois documentos na mesma pergunta. O tecto de100 ficheiros do dossier conta originais distintos, sem consumir lugar por nova utilização do mesmo original.
+
+Reutilização por interface: os intervenientes com escrita no dossier recebem inventário autorizado dos seus pedidos; analista/gestor sem essa representação não recebe esse catálogo de reutilização. O inventário apresentado ao analista do pedido continua apenas o seu âmbito/global. O selector agrupa apenas utilizações do mesmo document_id com fonte/etapa/validade exactamente iguais, conserva alternativas de proveniência e envia reuse_link_id escolhido. Backend verifica origem e documento correspondentes e âmbito autorizado; não pede UUID, proveniência ou datas já disponíveis. Nova ligação conserva referência/validade declarada, recebe a etapa do pedido e regista em evento cifrado a origem exacta e os factos utilizados, sem expor o processo/interveniente antigo na cópia. O vínculo antigo não se torna global nem é alterado; analista do novo pedido continua sem acesso ao vínculo do pedido antigo. Validade declarada não é renovada ou interpretada como alvará válido por esta operação. O selector novo cobre o mesmo dossier; o formulário geral legado e catálogo entre dossiers ainda têm saldo específico.
+
+Validação: upload e documento reutilizado passam pelos limites da definição ligada ao pedido e pelo acesso actual. Só uma alternativa (ficheiro ou documento) é aceite. Referência existente é reutilizada; se não existir, pede-se apenas o dado em falta. Uploads ficam na quarentena e no job de scan existentes, sem cópia/novo job para reutilização de original. Rascunho e checkpoint conservam selecção pendente; estado oculto conserva IDs/metadados, sem exigir suporte nem o declarar aplicável. Submissão de pergunta activa exige suporte disponível/scan válido e verificação de autorização/hash/original pelo VerifiedDocumentBinary. Mede MIME e tamanho reais no original, incluindo após decifrar; metadados conhecidos divergentes não passam silenciosamente. Ausências antigas são medidas para o snapshot, conservando no cadastro e no snapshot a ausência registada, sem exigir reenvio, preencher zero ou reescrever a fonte. Campo com nome financeiro e tipo de anexo não entra no motor numérico nem gera perguntas de financiamento; regras financeiras numéricas continuam verificadas.
+
+Interface/recuperação: limites e estado visíveis, upload/reutilização só por acção explícita, sem submeter o pedido. A proveniência já registada fica em leitura; ficheiro/referência local continuam disponíveis após falha. Multipart reutiliza transporte/CSRF da aplicação, deixando boundary ao navegador e conservando JSON nos outros consumidores. Associação devolve inventário/versão/vínculo e indicação de repetição; repetir não substitui referência antiga. Ficheiro seleccionado no equipamento ainda não é suporte associado e não integra o rascunho do pedido até confirmar o envio. Selecção local de ficheiro ainda não enviado não é recuperável após fechar/recarregar, e o original continua no equipamento. Refresh de documentos conserva respostas, não duplica aliases nem apaga edições em curso; inventários de scan com a mesma versão do dossier deixam de esconder respostas mais recentes. Recuperação mostra nomes em vez de UUIDs e não herda anexos de texto de perfil/contexto. Guardas de navegação existentes abrangem envio em curso, sem guardar respostas em browser storage. Pedido encerrado mantém consulta mas não oferece edição/catálogo de reutilização.
+
+Histórico/recibo: field_attachments no snapshot cifrado captura rótulo/aplicabilidade, edição, limites e ficheiros/versão/hash/MIME/tamanho medidos/valores registados/referência/validade/etapa/estado efectivamente utilizados. HTML/TXT recuperam essa informação e distinguem perguntas ocultas de evidência aplicável. Nova publicação/opção/limite não reescreve submissão anterior. Conferência documental usa o verificador binário comum, incluindo cifra e autorização da origem, e bloqueia pedido antes de dossier como a gravação/associação, evitando a inversão de locks anterior. Mantêm-se revisão independente, auditoria e distinção entre conferência interna e acto oficial.
+
+Provas: regressão de81 Feature/1110 asserções (editor/vigência/tipos/checkpoint/análise/métricas/orientação/conferência), seguida de20 testes específicos/251 na versão final com selector/proveniência/fecho. São rondas sobrepostas e não uma soma de testes únicos.38 frontend, com8 novos casos de anexo/transporte/editor/reutilização e regressões dos consumidores existentes. PHPStan sem supressões, Pint, tipos, lint e build terminaram com sucesso. Ensaios validam formato/tamanho/quantidade, fonte seleccionada/datas sem reintrodução, permissões/revogação/âmbitos, pendente vs submissão, originais alterados/em falta/cifrados, medição de legado desconhecido, replay, versões/recibos antigos, rollback e migração ausente. Nova conferência de original cifrado foi exercitada com bytes sintéticos e corrupção posterior recusada. Estados de scan nas fixtures são sintéticos; não equivalem a novo ensaio real de ClamAV ou aceitação humana.
+
+Concorrência: dois processos PHP/conexões PG efectivamente sobrepostos por0.373360s, invocando o controlador com actor sintético autenticado na fixture isolada, conservaram1 document/1 vínculo/1 ficheiro físico/1 evento. A guardou, B recebeu409, dossier v2 e pedido v1/cifra intactos, hash físico conferido. Prova delimita controlador/DB/disco, não browser/visitantes reais; testes HTTP separados conferem autenticação/permissões. Dataset desk_attachment_concurrency_20261103_test e ficheiro privado de prova preservados. Primeira tentativa técnica perdeu o resolver de actor no rebinding de Request da fixture:0 documentos/0 vínculos/versões1 conferidos antes da v2, sem alterar autenticação da aplicação. Saídas falhadas conservadas em storage/app/private.
+
+Diagnósticos preservados: distinct do wildcard de MIME validava indevidamente campos diferentes, corrigido para unicidade dentro de cada pergunta; fixture PNG deixou de depender de GD; correcção de sintaxe da fixture e representação de MIME desconhecido como string vazia, respeitando NOT NULL real. Falhas assíncronas iniciais dos testes frontend eram espera insuficiente do harness, corrigida sem enfraquecer o fluxo. Logs anteriores às provas finais permanecem privados.
+
+QA funcional exclusiva desk_attachments_20261103_test, loopback127.0.0.1:55441, DB_URL vazio/role investmoz_test;16 tabelas sem linhas retidas após rollback, owner/RLS/FORCE e ambos índices válidos conferidos. Guarda do TestCase intacta. 57 recibos e57 logs anteriores reconferidos/preservados; deltas intencionais do checkpoint estão discriminados no novo recibo. Migração apenas em QA, sem migração/escrita activa, conta real, mensagem externa ou importação de exemplar oficial. Compilação conserva avisos conhecidos de chunks/fontaine/tempo de plugins, sem erro de execução.
+
+03/11/2026: Balcão tem editor/histórico/vigência, tipos múltiplos/declarações/anexos, recuperação automática e limites de ficheiro por pergunta demonstrados localmente. Restam outros consumidores/contextos p481, limites/formatos/mensagens parametrizados transversalmente, catálogo/selector legado geral e reutilização entre dossiers sem UUID manual, camadas de obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização/migração no destino. Os quatro MIME e tectos técnicos existentes (10MiB/100 ficheiros por dossier) não são parametrização integral da aplicação. Não é homologação, aprovação documental ou aceitação real. Conferência visual/login real continua limitada pela ferramenta já documentada; HTTP/SSR/SQL não são prova visual. Próxima acção: substituir entradas legadas por UUID por selecção de cadastros/documentos autorizados com o âmbito completo, depois restantes tipos/limites/contextos p481 e três camadas p161, sem apagar capacidades demonstradas. Os sete modelos continuam sem URL e ACT-16 sem tradução/prioridades, conforme respostas já registadas; não impediram este desenvolvimento.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: pesquisa e selecção documental no âmbito autorizado
+
+[DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa.
+
+Inventário anterior reconferido: desk_attachment_fields_increment_20261103 conserva perguntas/limites/versões/recuperação e provas de concorrência do upload. Código e documentos mostravam o formulário geral por UUID, enquanto o servidor já autorizava reutilização de originais do próprio e de dossiers pessoais. Este incremento resolve esse saldo de interface, sem reapresentar a reutilização anterior como motor novo. Fonte segmentar processos v1.docx/p481 e p565, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, original reconferido; orientações de reutilização/percurso adaptativo no AGENTS.md, 23/10/2026.
+
+GET privado autenticado/verified documentos-disponiveis valida escrita efectiva e dossier aberto, pesquisa literal de nome/referência/título nas fontes acessíveis e pagina sem expor armazenamento, intervenientes, IDs dos dossiers de origem ou dados de fontes alheias. Direitos sobre o ficheiro não herdam dados da sua utilização numa organização. Upload próprio sem fonte autorizada permanece seleccionável, pedindo apenas a referência efectivamente ausente. O catálogo conserva alternativas por vínculo, com versão, etapa e validade declarada; não escolhe automaticamente outro exemplar nem renova validade. A autorização específica dos anexos de oportunidade é a mesma do VerifiedDocumentBinary e é conferida também antes da associação, sem ler ou divulgar bytes na pesquisa.
+
+Componente comum de pesquisa usado no formulário geral e nas perguntas de anexos. Enter pesquisa sem submeter o formulário envolvente; todos os botões de pesquisa/paginação são type=button. Paginar ou falhar conserva a origem deliberadamente seleccionada; editar a pesquisa retira resultados/cursor antigos para não saltar páginas da nova pesquisa. Resposta tardia de outro dossier é ignorada. Pesquisa e selecção não fazem escrita de negócio. A associação continua explícita, com consentimento, fonte exacta e verificação no servidor; limites por edição, original/scan/hash/cifra e snapshot anteriores continuam no mesmo motor. Mudar de ficheiro para origem existente limpa a selecção local de ficheiro para impedir envio posterior de um ficheiro oculto; falhas de associação mantêm a escolha actual. Nenhum ficheiro é guardado em browser storage.
+
+Suporte da etapa: lista os vínculos já associados por nome/versão/referência/validade. document_link_id é resolvido apenas no dossier e tem de corresponder ao document_id quando ambos são enviados. Workflow/evento conservam o vínculo e os factos de origem utilizados; alterações posteriores da origem não os reescrevem. Clientes que enviam só document_id continuam disponíveis, resolvendo de forma determinística o vínculo anterior; decisões/revisão independente não foram substituídas. A interface geral deixa de oferecer upload em dossier encerrado, que continua consultável.
+
+Provas em base sintética exclusiva desk_document_reuse_20261103_test, 127.0.0.1:55441, DB_URL vazio e role investmoz_test, guardas inalteradas. 56 testes Feature/766 asserções incluem 8 novos casos e regressão de anexos/checkpoints/recibos/orientação; 40 frontend incluem 10 novos casos de pesquisa/consumo. Testados âmbito, revogação/viewer/gestor sem representação, origem organizacional privada do próprio uploader, fontes pessoais/unlinked/deleted/alheias, origem de oportunidade sem autorização, filtros literais %/_, paginação, datas/proveniência, sem segunda cópia física, selecção por vínculo e compatibilidade por documento, leitura de dossier fechado e anonimato. PHPStan sem supressões, Pint, tipos, lint e build aprovados. Dezasseis tabelas sem dados retidos, owner/RLS/FORCE e índices de âmbito existentes válidos conferidos. A primeira ronda falhou apenas na fixture de paginação por reutilizar uma storage_key única; passaram a existir chaves/ficheiros sintéticos distintos, sem enfraquecer o schema. Logs iniciais preservados privados.
+
+58 recibos e 70 logs aceites preservados por hash; quatro deltas intencionais da implementação anterior discriminados no recibo. A prova anterior de concorrência continua a delimitar o upload e não é apresentada como novo ensaio do catálogo. Sem nova migração, escrita activa, conta real ou mensagem externa. Build conserva avisos não bloqueantes já conhecidos; prova de componentes/HTTP/SQL não é conferência visual.
+
+03/11/2026: selector geral do dossier, anexos por pergunta e suporte da etapa já não exigem UUID manual. Catálogo entre dossiers corresponde à autoridade existente, sem alargar o acesso a fontes de outras organizações. Continuam pendentes outros consumidores/formulários e a parametrização transversal de limites/formatos/mensagens, camadas de obrigações/registo/licenciamento por fonte/âmbito, conferência visual/login real e disponibilização no destino. Não é parametrização integral, homologação ou aceitação real. Próxima acção: conferir outros consumidores documentais e remover reintroduções nos respectivos percursos, sobre cadastros e permissões existentes; continuar os restantes critérios p481/p161 sem repetir capacidades concluídas. Modelos societários e traduções nacionais mantêm as respostas do proprietário já registadas, sem novo pedido genérico de autorização.
+
+
+### 03/11/2026 — AUD-DESK-01/02: completar comprovativos no mesmo registo de pagamento
+
+[DESK-PAYMENT-EVIDENCE-20261103] A declaração manual já existia e permitia comprovativo pendente, mas faltava juntá-lo posteriormente sem repetir a referência. Agora o titular/representante com escrita acrescenta ou corrige o suporte do mesmo pagamento pending/internal_issue por vínculo seleccionado, versão, motivo e consentimento. Referência, montante, moeda e fonte do valor são conservados; a nova associação fica pending, sem confirmação bancária. Registo internal_verified não pode ser substituído pelo titular; eventual problema continua a ser registado pelo revisor independente no percurso existente. Proveniência documental, exemplar, versão/hash registados e validade declarada ficam nos eventos cifrados, sem segunda tabela/migração ou cópia física. Conferência valida o original comum e a correspondência ao exemplar associado; legado sem captura continua desconhecido, sem reconstituição retroactiva. Pesquisa/reutilização anterior preservada. Dossier encerrado mantém leitura dos pagamentos, sem novas operações manuais. 53 Feature/721 asserções e 47 frontend, PHPStan/Pint/tipos/lint/build aprovados; 18 tabelas QA vazias/owner/RLS/índices. Dois processos sobrepostos 0.392022s, em pedidos diferentes com a mesma referência, conservaram 1 declaração/evento; segundo com conflito 409 e pedidos principais intactos. Recibo desk_payment_evidence_increment_20261103, sem escrita activa ou nova migração.
+
+Inventário/preservação: recibo desk_document_reuse_increment_20261103 e os registos anteriores confirmam que declaração, selecção de comprovativo, conferência interna e comunicação manual já funcionavam. A lacuna concreta era declarar sem documento e tentar completá-lo: repetir a referência com document_id diferente devolvia409 e não havia acção própria. Não se recriou o motor de pagamentos nem se confundiu a fonte do valor/finalidade com a proveniência do ficheiro. Fonte funcional: AUD-DESK-01/02, orientação de reutilização do AGENTS.md e segmentar processos v1.docx p474/p479/p481, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, original conferido. Estados/aprovações vigentes preservados; nenhuma taxa, responsável ou entidade externa inferida.
+
+A nova acção PUT comprovativo exige autenticação/verified/escrita actual no pedido, pagamento do mesmo pedido, dossier/pedido abertos, vínculo global ou desse pedido, versão corrente, motivo e consentimento. Ordem de locks: pedido, dossier, pagamento. Só suporta pending/internal_issue; internal_verified permanece protegido de substituição pelo titular. O revisor pode continuar a registar um problema no percurso existente, com fundamento e histórico. Correcção documental faz nova versão do pagamento e volta a pending, retirando apenas os indicadores actuais de conferência; revisões anteriores continuam nos eventos. Valores/ref/moeda/fonte não são reintroduzidos, editados ou novamente somados. Associar não cria novo ficheiro, scan ou pagamento.
+
+Documentos: o formulário de declaração e o de complemento escolhem o vínculo exacto por nome, versão e referência, em vez de aliases do mesmo original terem valores indistinguíveis. Backend aceita o document_id antigo, resolvendo um vínculo autorizado determinístico; IDs de outro pedido/caso ou origem de oportunidade sem acesso são recusados. A captura guarda nome, vínculo/original, versão/hash registados, categoria, etapa e validade declarada na associação, sob a cifra/auditoria existentes. Não é prova de integridade binária ou de dinheiro confirmado. Não copia montante/moeda/fonte do valor a partir do documento. Alterações futuras de referência/data não reescrevem a captura. Conferência positiva verifica binário/scan/autorização comuns e versão/hash face à captura, incluindo vínculos exactos; original substituído ou corrompido não é conferido como se fosse o anterior. Declarações antigas sem captura ficam legíveis e conferíveis pelas regras anteriores, com a ausência histórica explícita.
+
+Idempotência: operação documental identifica client_key/actor/pedido/pagamento/dados normalizados; repetição exacta confirma a operação anterior sem nova versão/evento. Alterar a operação com a mesma chave ou base obsoleta não sobrescreve. Mudanças deliberadas da selecção/motivo iniciam nova chave e renovam consentimento; falha conserva a escolha/motivo/chave para repetição. Versão de edição fica estável; actualização concorrente pede adopção explícita da nova base, conservando o texto e a selecção. A declaração de referência continua idempotente pelos factos já registados e serializa a referência no PostgreSQL, conservando a unicidade anterior em pedidos distintos com conflito tratado em vez de violação única500.
+
+Interface: entradas pendentes oferecem Juntar/Corrigir no próprio artigo; entradas conferidas e leitores não recebem essa acção. Declaração nova explica onde completar uma referência existente. Pagamentos e metadados congelados permanecem visíveis em pedidos/dossiers encerrados; criação, complemento, conferência e comunicação manual ficam bloqueados no servidor e respectivos formulários ocultos. As demais funcionalidades do pedido mantêm as próprias permissões. Não se declarou efectuado um envio de SMS/WhatsApp/email por registar manualmente uma comunicação.
+
+Provas: 53 Feature/721 na regressão de pagamentos/anexos/reutilização/orientação/recibos, incluindo 8 casos novos; 47 frontend, com 7 novos casos de complemento/idempotência/base concorrente/consulta histórica/ausência de reintrodução. PHPStan sem supressões, Pint, tipos, lint e build concluídos. Primeira ronda frontend43/46 e tipos detectaram uma referência a request no valor inicial de um parâmetro, antes de existir o nome local; corrigida para initialRequest e acrescentada regressão de props legadas/consulta sem edição. Provas falhadas e primeiro build preservados privados, sem apresentá-los como validação final. Nenhum bug pré-existente foi alegado para esse erro introduzido no incremento.
+
+Concorrência: dois processos PHP e conexões PG efectivamente sobrepostos 0.392022s invocaram o controlador de declaração, em pedidos/dossiers diferentes com a mesma referência sintética. Um guardou e outro409; 1 desk_payments/1 payment_declared, 25.50MZN pending, ambos os pedidos v1/cifras intactos. Actor autenticado sintético na fixture do controlador; não é prova de middleware/browser, cobertos separadamente pelos testes HTTP no âmbito demonstrado. Fixture desk_payment_race_20261103_test conservada. Este ensaio refere-se à declaração concorrente; versão/idempotência do complemento foram demonstradas por HTTP sequencial, sem alegar outro ensaio paralelo.
+
+QA funcional exclusiva desk_payment_evidence_20261103_test, loopback127.0.0.1:55441, DB_URL vazio e role investmoz_test; 18 tabelas vazias após rollback, owner/RLS/FORCE e índices existentes válidos conferidos. 59 recibos e 79 logs aceites preservados por hash; deltas do código anterior discriminados. Sem nova migração da funcionalidade, alteração de base activa, conta real, mensagem externa ou confirmação bancária. Avisos conhecidos de fontes/chunks/tempos de plugins conservados no build final com saída0.
+
+03/11/2026: comprovativo pendente ou corrigido pode completar a declaração existente sem repetir montante/moeda/fonte, com histórico e revisão independente. Restam outros consumidores e origens por formulário, atribuições/próxima acção/documentos por âmbito, parametrização transversal, conferência visual/login real e disponibilização no destino; integração bancária/entrega de mensagens não é declarada por estes registos manuais. Critérios gerais do Balcão/percurso não estão integralmente encerrados. A conferência visual continua pendente nas condições da ferramenta já documentadas; HTTP/componentes/SQL não são aceitação humana. Próxima acção: continuar os restantes consumidores/formatos/limites e percurso adaptativo sobre os motores e fontes existentes. Modelos societários/ACT-16 conservam as respostas anteriores, sem nova pergunta genérica.
+
+
+### 03/11/2026 — AUD-DESK-01/02 e AUD-CRM-01: coerência dos registos encerrados, cancelamento e fecho pelo dono
+
+[DESK-CLOSED-LIFECYCLE-20261103] Por decisão expressa do proprietário, o dono registado executa agora o encerramento/reabertura, com acesso efectivo, versão, motivo, operação idempotente e histórico. Gestores/outros representantes não recebem esse poder por inferência. Resumo das pendências antes da confirmação e manutenção dos estados/payloads/documentos/tarefas/pagamentos, sem aprovação em cascata. Dossier com closed_at já bloqueava rascunhos/anexos/pagamentos, mas permitia transições, etapas, atribuições, mensagens e actualizações de tarefas. Reproduzidos HTTP200 nesses percursos, incluindo atribuição com MFA válido. Agora a guarda de estado comum e lock do dossier protegem esses comandos, preservando leitura/histórico e as permissões anteriores. Tarefas com vínculo CRM/dossier respeitam o fecho também no CRM; CRM sem tarefas vinculadas não consulta nem exige o Balcão. Listas de triagem/filas excluem encerrados e a interface retira decisões/atribuições/mensagens/etapas/conferência/tarefas sem aplicação. Cancelamento de rascunho/devolvido, já autorizado pelo servidor ao titular com escrita, fica disponível por motivo e confirmação explícita, conservando dados/documentos/histórico e o dossier. Sucesso mostra a versão efectivamente guardada; falha conserva edições. Justificação de correcção só é perguntada num pedido devolvido. 77 Feature/1016 na regressão, 15/202 específicos finais (rondas sobrepostas, não somar),64 frontend e estática/Pint/tipos/lint/build aprovados;20 tabelas QA vazias/owner/RLS/índices. Recibo desk_closed_lifecycle_increment_20261103, sem nova migração/escrita activa.
+
+Inventário reconferido no recibo desk_payment_evidence_increment_20261103: rascunhos/checkpoints, anexos, reutilização, declaração/complemento de comprovativos e operações manuais preservados. No código, closed_at já suspendia criação/edição e várias operações; faltava coerência em cinco comandos. Não foram recriadas essas funcionalidades nem inferido um procedimento novo de fecho. Fonte: decisão expressa do proprietário em03/11 sobre fecho/reabertura pelo dono, registada no AGENTS.md; orientação adaptativa/reutilização/preservação do AGENTS.md e segmentar processos v1.docx p474/p479/p481, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5; estados/competências aprovados e configuração existentes prevalecem.
+
+Reprodução: primeira ronda7 casos teve1 aprovado e6 falhas. Transição, etapa, mensagem e tarefa aceitaram200 em dossier encerrado; o ensaio inicial de atribuição recebeu403 porque a fixture administrativa não tinha MFA. Corrigida só a fixture pelo helper sintético já aceite, a reprodução específica demonstrou atribuição200 em vez de409. A guarda MFA e os perfis da aplicação não foram enfraquecidos. O caso aberto também verifica autodecisão negada, atribuição e transição legítimas, mensagem e ausência de acesso de outra conta.
+
+Servidor: assertOpen é uma guarda de estado comum, separada da autenticação/autorização de case/request; não se bloqueiam consultas por tratar o parâmetro write de acesso como se fosse uma ordem de mutação. Transição, atribuição, mensagem e tarefa bloqueiam o dossier antes de decidir/gravar; pedido continua antes do dossier onde ambos são necessários. Etapa usa o lock que já tinha e verifica o estado. Não criam revisão, mensagem, evento ou notificação de negócio quando recusados. Leitura/auditoria de consulta, recibos, documentos e histórico continuam pelas ACL existentes. Listas administrativas e fila de acompanhamento deixam de oferecer pedidos de dossier encerrado como trabalho activo.
+
+CRM partilhado: tarefa já ligada a lead e dossier conserva a autoridade anterior do CRM, mas a alteração verifica/locka o estado do dossier antes da actualização. Não é transferida, duplicada ou cancelada por arrasto. A apresentação devolve can_update sem persistir esse atributo virtual. Tarefas comuns sem ligação mantêm o percurso normal e não executam consulta à tabela desk_cases; teste com tabela temporariamente indisponível em QA prova independência. Não se declarou nova interface para associar automaticamente lead e dossier. Próxima tarefa de lead activo, MFA, contas e scopes mantêm as regras anteriores.
+
+Interface: dossier encerrado tem explicação de consulta; etapas/conferência ficam ocultas. Orientação continua calculável/legível, com pressupostos e acções de tarefa sem edição. No pedido, decisões, atribuições e mensagens obedecem ao mesmo operationsEditable das operações documentais; mensagens anteriores e pagamentos permanecem visíveis. CRM mostra título/estado/prazo e retira a actualização da tarefa vinculada encerrada. Pesquisa de fontes e notificações pessoais não se tornam operações de negócio bloqueadas por omissão.
+
+Cancelamento: a API já permitia ao titular/representante com escrita cancelar draft/returned por motivo; não é novo estado nem novo direito. O formulário usa a mesma transição, versão e auditoria, bloqueia clique/envio enquanto há gravação/associação em curso e explica o efeito sobre a última versão guardada. Não pede dados financeiros, documentos ou motivo de correcção que não se aplicam. Justificação de correcção mantém-se nos devolvidos. Falha não apaga texto/edições; resposta de sucesso repõe no formulário o payload efectivamente devolvido pelo servidor e retira consentimento, evitando apresentar alterações não guardadas como dados do registo cancelado. Pedido submetido não recebe esse cancelamento pelo titular. Acesso ao cancelado e dossier/documentos/histórico conservados; nenhuma reabertura ou cancelamento em cascata.
+
+Provas: 77 Feature/1016 na regressão de ciclo/anexos/comprovativos/reutilização/orientação/CRM/checkpoints, seguida de15 casos/202 na versão final com independência do CRM sem vínculos e a decisão do dono implementada. Rondas sobrepostas, não somadas como testes únicos.64 frontend, incluindo12 novos casos de cancelamento, sincronização do payload de sucesso, espera de recovery, permissões/contextos fechados, pergunta aplicável e leitura de tarefas/contexto. PHPStan sem supressões, Pint, tipos, lint/build concluídos. O teste anterior de vigência/refresh de serviços exigiu actualizar os mocks de importação e hooks da fixture para os componentes de documentos e estado agora usados na página; os dois ensaios63/64 e os seus erros de harness ficam privados. A aplicação não foi enfraquecida para os contornar. Sem novo ensaio concorrente alegado: recusa de versões/estados exercitada por HTTP sequencial e locks conferidos no código; provas paralelas de incrementos anteriores preservadas no seu âmbito.
+
+QA exclusiva desk_closed_lifecycle_20261103_test, loopback127.0.0.1:56441, DB_URL vazio e role investmoz_test.20 tabelas sem dados retidos, owner/RLS/FORCE e índices de documentos válidos. A indisponibilidade de tabela da fixture foi revertida em finally e o schema final reconferido. 60 recibos e 92 logs aceites preservados por hash; deltas de código conhecidos discriminados. Sem nova migração, conta real, escrita activa ou mensagem externa. Avisos conhecidos do build mantidos; saída final0.
+
+03/11/2026: coerência do closed_at e cancelamento de rascunhos demonstrados nos percursos identificados, sem alterar regras/perfis ou encerrar dossiers automaticamente. A operação de encerrar/reabrir o dossier completo foi implementada conforme a resposta expressa do proprietário: o dono executa essa acção. Mantêm-se acesso efectivo, motivo, versão e histórico, sem impor que todas as pendências estejam concluídas nem alterar estados de outros processos. Restam restantes consumidores/parametrização/percurso adaptativo, conferência visual/login real e disponibilização no destino. Fecho/reabertura: o proprietário respondeu que o dossier tem um dono e esse deve executar a acção. PUT privado/verified reutiliza user_id do dossier e exige a autoridade efectiva actual, incluindo representação vigente em organização. Outro gestor/analista/representante não substitui esse dono. O dono vê contagens locais de pedidos/tarefas/comprovativos pendentes; desconhecido continua por confirmar, sem zero inventado. Decide por motivo e confirmação, sem exigir conclusão de todas as pendências. Lock/versionamento do dossier, client_key e eventos cifrados preservam antes/depois/actor/motivo/contagens. Repetir exactamente não cria outra decisão; operação antiga repetida após reabertura devolve o estado actual e não volta a encerrar. Não modifica payload/workflow/estados próprios de pedidos/tarefas/pagamentos. Reabertura não reabre pedidos cancelados/encerrados. Formulário adopta estado/versão do servidor só no sucesso, preserva motivo/chave na falha e exige adopção explícita se a base mudar. Depois de sucesso retira ficheiro local não associado/consentimento antigo para não os reutilizar invisivelmente após reabrir. Não é aprovação por silêncio, licença, conferência de dinheiro ou fecho em cascata. Conferência visual/login real continua pendente nas condições da ferramenta já registadas; componentes/HTTP/SQL não são aceitação humana. Prosseguir com os restantes consumidores autorizados e manter ACT-16/modelos societários nas respostas já registadas.
+
+### 03/11/2026 — AUD-CRM-01: edição concorrente sem sobrescrever alterações recentes
+
+[CRM-RECORD-VERSIONS-20261103] Investidor, contacto, qualificação/atribuição de lead e estado de tarefa passam a enviar automaticamente a revisão que foi apresentada. PortalAudit confere-a sob lock, devolve erro de versão e só incrementa a revisão numa alteração efectiva. As colunas version_no já existiam; o trigger existente apenas actualiza updated_at. Contactos partilhados mantêm uma revisão comum. A interface compara dados actuais com a edição, exige escolha nos campos em conflito e conserva alterações deliberadas, incluindo regressar ao valor inicial e editar durante a gravação. Preservados conversão idempotente, consentimento, não duplicação, responsáveis autorizados, próxima acção e fecho de dossiers pelo dono. 45 Feature/594 asserções, 75 frontend (10 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL com espera por lock comprovada: uma gravação, um conflito de versão, um evento; contacto sentinela preservado. 23 tabelas QA vazias, owner/RLS conferidos. Recibo crm_record_versions_increment_20261103; sem migração ou escrita activa. Visual/destino e restante cobertura do CRM continuam parciais.
+
+Origem e inventário: instruções permanentes de preservação e edição deliberada; segmentação bf26caeee043, parágrafos474/479/481. Reutilizados os registos investors/contacts/leads/tasks, a auditoria e os quatro formulários existentes. O inventário do incremento anterior conserva dossiers, encerramento/reabertura pelo dono, anexos, comprovativos, rascunhos, tarefas e permissões. Conferidos os hashes dos recibos/logs anteriores e o delta explícito do código, sem nova regra de competências.
+
+Uso: «Comparar com os dados actuais» recupera apenas os dados desta página e conserva o formulário. Campos alterados por ambas as operações exigem «Usar valor actual» ou «Manter minha alteração». A adopção é explícita; a gravação seguinte utiliza a revisão comparada, novamente sujeita a concorrência. Sucesso repõe os dados efectivamente devolvidos pelo servidor, preservando edições feitas durante a espera. O fundamento anterior do lead fica em consulta e não é reutilizado como fundamento de um evento novo. Nenhuma cópia de contactos é guardada em localStorage.
+
+Compatibilidade e limites: os quatro PATCH privados de edição exigem agora version, enviado pela interface sem pergunta adicional ao utilizador; cliente anterior sem esse metadado recebe422 e deve actualizar a página. Coordenar backend/frontend na entrega. Não se trata de nova versão de edição de documentos/fontes, nem de histórico integral dos textos pessoais na auditoria. A política de incremento restringe-se às quatro tabelas CRM em PortalAudit; restantes domínios conservam a política existente. A conservação da edição é em memória da página/recarga parcial/erros, sem promessa de recuperação após fechar o navegador. Os acessos existentes da gestão são preservados; esta correcção não acrescenta MFA ao CRM. Guia/tarefas mantém a sua verificação de versão já existente.
+
+Provas: servidor CrmRecordVersionsTest(8), CrmIntakeTest(6), DeskClosedLifecycleTest(9), DeskCaseStateTest(6), InvestorGuidanceTest(16),45/594 no total; frontend75 incluindo10 casos novos de comparação, reversão deliberada, actualização parcial, normalização de email, edição em voo, fundamento por evento, registo exacto e envio de revisão nos quatro formulários. O ensaio concorrente chama o serviço com duas ligações/processos reais numa segunda base sintética; não substitui os testes HTTP de autorização nem aceitação visual. Base principal crm_record_versions_20261103_test (55441/investmoz_test),23 tabelas sem linhas retidas após rollback; base concorrente crm_record_race_20261103_test mantém explicitamente a fixture sintética/sentinela para prova. Nenhuma base activa alterada, migração nova, mensagem externa ou instalação. Compilação aprovada com os avisos anteriores de fonte opcional/chunks/tempo de plugins.
+
+Próxima acção: continuar o inventário e implementação autorizados, mantendo AUD-CRM-01 parcial até conferir os percursos/filas por perfil e apresentação visual aplicáveis. Não repetir a decisão do dono, as conversões ou os resultados já demonstrados como novas lacunas. Línguas nacionais e sete minutas oficiais continuam dependentes das definições/exemplares que o proprietário ainda não possui.
+
+### 03/11/2026 — AUD-DASH-01 e AUD-CRM-01: acompanhamento pessoal no painel
+
+[DASHBOARD-WORK-QUEUE-20261103] O painel passa a reunir manifestações, pedidos do Balcão e tarefas CRM atribuídos à pessoa autenticada, usando as autoridades de consulta existentes. Colecções separadas, totais/prazos sobre o conjunto completo, ordenação por prazo/ID e cinco linhas por página com paginação independente. Ligações directas ensaiadas; tarefas apontam ao formulário existente do lead. Fecho do dossier suspende a presença dos pedidos/tarefas vinculados na fila activa, conservando estados/histórico. Auditor não recebe o resumo de gestão que os destinos já lhe negavam. Regressão final41 Feature/694,82 frontend (7 novos), estática/Pint/tipos/lint/build aprovados;26 tabelas QA vazias, owner/RLS conferidos após libertação do lock do processo de testes. Recibo dashboard_work_queue_increment_20261103; nenhuma migração nova/escrita activa. Restam outros acompanhamentos por perfil, visual e entrega.
+
+Origem e inventário: AUD-DASH-01 pede acções permitidas por perfil, indicadores e destinos reais; AUD-CRM-01 pede acompanhamento interno com responsável/próxima acção. A navegação e os painéis de domínio já existem, mas dashboard não reunia estas atribuições. Reutilizados interest_requests.assigned_to, desk_requests.analyst_id e tasks.assignee_user_id/lead_id, ScopedPortalAdministration, acesso directo do Balcão e o gate da gestão CRM, sem criar perfis, concessões, prazos ou outro workflow. O incremento anterior de edição concorrente foi reconferido antes da alteração; guardas, versões, contactos, documentos, operações de dossier e provas anteriores preservados, com delta explícito para a âncora do formulário de tarefa.
+
+Âmbito: fila pessoal, mesmo para gestor; as colecções não são somadas para não sugerir pessoas/processos únicos. Manifestações exigem a consulta efectiva existente, incluindo confirmação MFA válida; pedidos atribuídos usam a consulta já permitida ao analista; tarefas CRM usam o acesso de gestão já existente, sem concedê-lo por mera atribuição. Ausência de autoridade/módulo omite a colecção, sem zero inventado. Revogação, expiração MFA e condição de auditor são reavaliadas em cada pedido. O resumo global antigo deixa de ser enviado a um auditor que acumule o gate legado de gestão. Nenhuma alteração aos gates globais ou às decisões autorizadas.
+
+Prazos e estados: ausência de prazo aparece «Sem prazo definido»; instante igual ao da leitura não é atraso. Datas em Maputo e instante de actualização explícitos. Estados apresentados pelos dicionários já existentes da manifestação/tarefa e configuração do Balcão; aceitação interna não é mostrada como licença/aprovação externa. Concluídos/cancelados e exclusões lógicas pertinentes saem da fila activa. Pedidos e tarefas vinculados a dossier encerrado ficam em consulta/histórico, sem mudar estados nem reabrir por arrasto. CRM sem vínculo continua disponível quando o Balcão opcional está ausente.
+
+Navegação: cada colecção tem cinco registos por página, mantendo os parâmetros das outras páginas. Prazo seguido do ID dá ordenação estável; página antiga fora do novo total regressa a uma página existente após mudanças de atribuição/estado. A fila não reserva trabalho, não decide pedidos, não envia avisos nem executa tarefas. Leituras são dinâmicas e os destinos voltam a verificar acesso/versão/estado no momento da acção. As páginas anteriores do investidor, oportunidades e indicadores continuam acessíveis no âmbito já autorizado.
+
+Provas: regressão final41 casos: DashboardWorkQueueTest(11), DashboardOpportunityAccessTest(3), CrmRecordVersionsTest(8), DeskClosedLifecycleTest(9), DeskCaseStateTest(6) e InvestorPathTest(4). Os cenários novos cobrem visitante/não verificado/investidor, operador por atribuição, totais separados, destinos, ausência de escrita/auditoria, fecho/conclusão/exclusão, perda de atribuição, paginação sem duplicações, prazo nulo/igual ao instante, expiração MFA/auditor e CRM sem Balcão, além dos parâmetros inválidos. Sete casos frontend novos e os75 anteriores,82 no total: continuidade do investidor/gestão, dicionários de estados, ausência/zero, datas, paginação, texto escapado e âncora real. Base dashboard_work_queue_20261103_test,55441/investmoz_test;26 tabelas sem linhas retidas, RLS e proprietário conferidos depois de adquirir o lock que exclui testes vivos. Ficheiros de diagnóstico anteriores conservados. Build com os avisos já conhecidos de fonte opcional/chunks/tempos de plugins.
+
+Limites e próxima acção: não declara dashboard integral de todos os perfis, todos os contadores de domínio ou a matriz concluídos. Restam outros consumidores/filas, verificação visual/móvel/teclado no navegador e disponibilização no destino. Prosseguir com as lacunas autorizadas da matriz, sem repetir as aceitações existentes, sem nova aprovação organizacional para escolhas técnicas e sem instalar dados sintéticos ou migrar o activo.
+
+### 03/11/2026 — AUD-CRM-01 e AUD-DASH-01: próxima acção consistente no CRM e na orientação
+
+[CRM-NEXT-ACTION-20261103] Reproduzidas três falhas: uma tarefa futura em dossier encerrado permitia qualificar o lead e concluir a última tarefa disponível (HTTP302), e a orientação permitia concluir a última tarefa de lead activo sem substituta (HTTP200). Agora a disponibilidade de trabalho é partilhada por CrmTask/CrmNextAction, qualificação, conclusão pelos dois percursos, fila pessoal e indicadores factuais. A tarefa conserva estado/histórico, mas não serve de próxima acção enquanto o dossier está encerrado; reabertura pelo dono recupera a disponibilidade sem reescrever a tarefa. Os dois comandos serializam pelo mesmo lead antes de alterar tarefas. Regra de prazo futuro já existente preservada; interface explica a pendência e liga ao formulário existente. 75 Feature/915 asserções e foco final2/42 sobreposto,87 frontend (5 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real CRM/orientação: uma conclusão, uma recusa por falta de outra próxima acção, uma acção futura mantida e lead/dois dossiers preservados.29 tabelas QA vazias, owner/RLS/lock conferidos. Recibo crm_next_action_increment_20261103; nenhuma migração/escrita activa.
+
+Origem e inventário: AUD-CRM-01 já exige responsável autorizado e próxima tarefa antes de encerrar a última; a decisão expressa de03/11 mantém o fecho/reabertura do dossier exclusivamente no dono, sem alterar em cascata estados de tarefas. Código e recibo dashboard_work_queue_increment_20261103 reconferidos antes da alteração. O painel já retirava tarefas de dossiers encerrados, mas os testes de qualificação/conclusão do CRM contavam-nas; a resposta da orientação não reutilizava a guarda CRM quando uma tarefa possuía ambos os vínculos. As três falhas HTTP foram guardadas antes da correcção. Não se criou nova regra de competências nem uma condição para o dono encerrar o dossier.
+
+Execução: scope CrmTask.availableForWork reúne estado open/in_progress, ausência de exclusão lógica e dossier associado aberto, quando existe. CrmNextAction acrescenta o prazo futuro e o mesmo lead para as condições que já o exigiam. Tarefas de outro lead, sem prazo, vencidas ou eliminadas não substituem a próxima acção futura. A qualificação conserva as regras anteriores de responsável, motivo, versão e lead convertido; desqualificação continua sem exigir outra tarefa. Na conclusão de um lead new/qualified, CRM e orientação verificam a mesma substituta excluindo a tarefa em conclusão. Orientação sem lead e resposta associada a lead arquivado conservam o percurso autorizado anterior. A disponibilidade não inventa novas regras de vigência/perfil do responsável.
+
+Concorrência e autoridade: ordem de locks dossier, lead e tarefa nos dois comandos; a orientação recupera o lead associado e confirma novamente o vínculo da tarefa antes da decisão. Os comandos continuam sujeitos aos seus acessos e versões anteriores. O ensaio com dois processos PostgreSQL e dois intervenientes sintéticos comprovou espera real pelo lock do lead: CRM concluiu uma tarefa, a orientação reavaliou após essa decisão e recusou concluir a outra, que permaneceu aberta/versão1; somente uma revisão/evento de auditoria acrescentados. Os dois dossiers e o lead mantiveram os respectivos dados/estados. A ordem do fecho pelo dono é independente: o dono pode suspender um dossier mesmo que a sua tarefa fosse a próxima acção do lead. Não se bloqueia esse fecho nem se cria/reabre outra tarefa por arrasto; a falta posterior de próxima acção fica visível para acompanhamento.
+
+Consulta e formulários: fila pessoal reutiliza o scope do modelo; contagem de atrasos CRM e avisos determinísticos locais deixam de tratar tarefas suspensas como trabalho disponível. O aviso missing_next_action conserva a distinção anterior entre ter trabalho pendente disponível e ter prazo futuro; tarefa disponível vencida pode ter alerta de atraso sem ser tratada como inexistente. Filtros de classificação/privacidade dos indicadores opcionais não foram alargados, nem foram copiados dados privados para métricas. Os comandos normais funcionam com IA/SuiteCRM desligados. No lead, contagem informativa de tarefas futuras e ligação ao formulário de próxima acção, com singular/plural correctos; nenhuma pergunta adicional, estado automático ou bloqueio geral que impeça desqualificação. Histórico de tarefas suspensas e erro por versão permanecem visíveis.
+
+Provas e preservação: CrmNextActionTest(11), CrmIntakeTest(6), CrmRecordVersionsTest(8), DeskClosedLifecycleTest(9), DeskCaseStateTest(6), DashboardWorkQueueTest(11), InvestorGuidanceTest(16) e AiGatewayTest(8),75/915. Foco final2/42 sobreposto confirma a leitura/avisos após a consulta tipada e regras sem modelos externos; não somar rondas. Frontend87, incluindo5 casos novos sobre pendência, contagem/singular, histórico suspenso, resposta antiga sem metadado e lead desqualificado. Base crm_next_action_20261103_test,55441/investmoz_test;29 tabelas sem linhas retidas, dono/RLS conferidos e lock do processo de testes adquirido antes de contar. A segunda base crm_next_action_race_20261103_test conserva explicitamente fixtures sintéticas para prova. HTTP/factos determinísticos não substituem observação visual ou aceitação de utilizadores.
+
+Limites e próxima acção: observar a apresentação/recuperação dos erros no navegador, disponibilizar no destino no âmbito próprio e continuar os restantes percursos/filas da matriz. A regra não garante uma tarefa futura para sempre: prazos expiram e o dono pode suspender o dossier posteriormente. Não automatiza decisão/qualificação nem cria responsáveis ou tarefas. Não declara o CRM/dashboard ou a auditoria integralmente concluídos; fontes/modelos e decisões concretas ainda pendentes permanecem no inventário existente.
+
+### 03/11/2026 — AUD-PART-01: edição de parcerias sem perda de dados e recuperação comparada
+
+[PARTNERSHIP-EDITING-20261103] Corrigidas omissões destrutivas no editor/API: disponibilidade existente, organização, campos escalares, locais e origens não enviados são conservados; valores explicitamente vazios continuam a remover o dado. Disponibilidade opcional agora visível, distinta do prazo de recepção de interesses. Actualização da página conserva edições e compara divergências por campo/grupo antes da adopção explícita. Repetição de criação não confirmada reutiliza o comando/chave originais, exige representação actual e não volta a validar sector activo numa repetição já executada. Gravações novas conservam validação do sector, versões409 e estados autorizados, incluindo publicada→rascunho.19 Feature/148 asserções (10 novos),103 frontend (16 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 registo/1 evento/1 auditoria/1 notificação, mesma identidade/versão e disponibilidade conservada.45 tabelas QA vazias com owner/RLS/lock conferidos. Recibo partnership_editing_increment_20261103; sem migrações/escritas activas.
+
+Origem e inventário: AUD-PART-01 e orientação expressa de23/10 sobre reutilizar dados e preservar edições deliberadas, explicar divergências/impactos e aperfeiçoar componentes existentes. A referência segmentar processos v1.docx, parágrafos479/481, conserva a distinção entre estados, reabertura e recuperação/versionamento; este incremento não declara executadas todas as variantes. Recibo CRM anterior, código e provas aceites reconferidos antes de continuar. Reprodução inicial: quatro cenários expuseram três defeitos distintos: perda de disponibilidade em duas edições; repetição pelo criador sem representação actual devolvia200; repetição exacta após desactivação de sector devolvia422. O quarto cenário produziu erro de asserção por chave availability desaparecida, não HTTP500. Reproduções e diagnósticos anteriores foram conservados.
+
+Servidor e reutilização: actualização parcial conserva raízes, campos permitidos do payload e relações omitidos. Apenas campos explicitamente enviados são substituídos; null/texto vazio, false e listas vazias mantêm significado próprio. Relações omitidas não são apagadas/recriadas nem novamente resolvidas; indicar novas origens/locais continua sujeito às guardas existentes. Conservar a referência não concede acesso ao documento. Preservados autor original, hash de criação, chave, versão, relações e eventos anteriores. Não se inventou novo requisito de NUIT, organização, documentos ou MFA para o rascunho pessoal; teste de utilizador não verificado confirma o percurso. As opções de edição draft/returned/rejected/published e a passagem de published a draft continuam as existentes.
+
+Autoridade e repetição: o replay procura a criação anterior dentro do mesmo lock por actor/chave, verifica a autoridade efectiva actual e a correspondência ao hash original; sem nova escrita/evento/notificação. O criador que perdeu representação após transferência não recupera acesso por conhecer a chave. Validação de sector activo aplica-se depois do ramo de replay, conservando a verificação para escritas novas. Validação estrutural básica continua a anteceder o replay; não se promete compatibilidade com qualquer futura alteração de esquema. O ensaio final usa dois processos reais e espera demonstrada pelo lock, conservando um único efeito mesmo com o sector desactivado após o primeiro commit. A prova de serviço concorrente complementa, sem substituir, os19 testes HTTP. Retirar explicitamente uma organização pode terminar o acesso futuro do representante conforme a regra anterior do autor original; a interface explica esse efeito, sem criar novo dono/perfil.
+
+Editor e formulário: removida a remontagem pela versão; estado mantém-se durante actualização e na transição de criação para edição. Comparação usa valores normalizados e versões, apresenta dados actuais e locais e pede escolha explícita nos conflitos. Locais, origens e critérios são grupos comparados atomicamente; ordem de conjuntos não cria divergência falsa. Edições deliberadas que regressam ao valor inicial continuam reconhecidas. Escolhas independentes não desaparecem ao resolver outro campo. Alterações batched de payload e remoções por identidade usam o estado corrente. Respostas inválidas, de outra identidade, mais recentes ou readonly não apagam a edição nem autorizam gravação. Erro409 mantém o texto e pede actualização/comparação.
+
+Criação e resultado incerto: a tentativa conserva uma cópia do comando efectivamente enviado. Repetir usa essa mesma chave/conteúdo, preservando à parte edições feitas depois do envio. A confirmação identifica o registo e conserva essas edições para a próxima actualização; não cria outro registo. A confirmação de gravação usa os dados canónicos devolvidos, incluindo normalização de espaços, e não toma alterações concorrentes como suas. Há aviso ao sair com alterações e recuperação em memória durante o percurso; não existe novo localStorage nem garantia de autosave, recuperação após fechar/recarregar o navegador, regressar pelo histórico ou voltar a autenticar. Falha403 é apresentada como impossibilidade de confirmar com o acesso actual, pois um redireccionamento posterior pode falhar após escrita autorizada. A revisão de proposta publicada explica a volta a rascunho e o circuito existente; não afirma que uma proposta privada estava publicada no catálogo público.
+
+Provas e preservação: PartnershipEditingTest10 e PartnershipExchangeTest9,19/148; frontend103 com16 novos casos no componente/editor/helper efectivamente transpilados, modelo de hooks incluindo identidade/key e limpeza de efeitos. Não é ensaio visual num navegador. PHPStan sem supressões, Pint--test, tipos, lint sem avisos e build exit0; avisos de fontes/chunks/tempos já conhecidos não são falhas. Diagnósticos iniciais de fixture/harness/tipagem e de caminhos JSON foram retidos sem os confundir com falhas actuais. A fixture geográfica positiva usa identificador técnico sintético compatível com a guarda de referências; não representa lugar oficial importado, hierarquia validada ou divulgação real. Base principal partnership_editing_20261103_test,55441/investmoz_test,45 tabelas conferidas sem linhas e lock adquirido antes da contagem. As duas bases de concorrência retêm fixtures sintéticas identificadas; prova final v2 após a última alteração do servidor.
+
+Limites e próxima acção: histórico de eventos conservado não equivale a arquivo imutável do texto integral de cada versão. Não se acrescentaram migrações, permissões, publicações nem alterações no destino activo. Manter prova visual/entrega e restantes variantes de sala, partilha documental e formulários no inventário existente. Línguas nacionais e os sete modelos oficiais continuam dependentes das fontes/definições já pedidas; não se inventaram traduções ou minutas aprovadas. AUD-PART-01 permanece parcial.
+
+### 03/11/2026 — AUD-PART-01: responsáveis dos marcos ligados aos participantes efectivos
+
+[PARTNERSHIP-PARTICIPANTS-20261103] Selector de responsáveis dos marcos agora reutiliza a regra efectiva de representação das duas partes. Pessoas identificadas pelo nome e lado da parceria, sem introduzir IDs, e-mails ou novos papéis. Autores de participações pessoais mantidos; representantes actuais de organizações seleccionáveis; viewers, vínculos revogados e organizações eliminadas não são fontes de atribuição. Leitura conserva o responsável anterior e informa perda de representação; substituir exige escolha explícita e evento com IDs anterior/novo. Salas em negociação, encerradas ou apenas de consulta não oferecem edição de marcos.25 Feature/211 asserções (6 novos),1413 frontend em regressão ampla (6 novos), PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_participants_increment_20261103; sem migrações/escritas activas.
+
+Origem e inventário: AUD-PART-01 exige candidatura isolada, sala e marcos com papéis reais. A guarda de gravação já permitia qualquer participante actualmente autorizado, mas o selector continha apenas os dois autores originais; uma organização cujos autores perderam representação ficava sem opção válida no formulário, apesar de possuir representantes competentes. O resumo só mostrava ID do responsável. Reconciliados código, recibo partnership_editing_increment_20261103 e provas anteriores antes de continuar; nenhuma entrega anterior foi reclassificada como ausente.
+
+Reutilização de autoridade: representa() e o novo catálogo contextual partilham uma única query de vínculos/organização actuais, com os mesmos papéis de escrita admin/manager/officer e as mesmas exclusões anteriores. O catálogo só é calculado depois de validar o acesso à sala. Não há directório público nem novo endpoint para procurar pessoas fora das duas partes. A participação pessoal selecciona apenas o seu autor, independentemente de outras organizações a que pertença. A mesma pessoa que representa ambas as partes tem um ID e dois lados; pessoas não são fundidas por igualdade de nome. O catálogo devolve apenas id/name/parties; sem e-mail, credenciais, MFA ou lista de perfis. Contas apenas de consulta recebem lista de atribuições vazia. Estado do vínculo no momento da consulta não concede autoridade futura.
+
+Formulário e estado: novos marcos pedem selecção explícita de um participante autorizado. Em marcos existentes mantém-se o ID efectivamente atribuído; o nome é consultado no cadastro actual, não um nome congelado na data original. Perda de representação fica indicada, sem transferir responsabilidade por arrasto. A opção anterior permanece visível/desactivada até escolha explícita de substituto, conforme a validação que já existia no comando. Consulta não altera linha, versão ou evento. Botão/envio recusam escolha indisponível na lista actual; o servidor continua a reavaliar a autoridade, incluindo quando o vínculo é revogado/rebaixado depois de abrir a sala. Não se criaram novas competências ou responsabilidades automáticas. Editor de marcos aparece somente nos estados agreement_recorded/agreed/execution já aceites pelo servidor, conservando a consulta do histórico nos restantes. Não se alterou a regra das confirmações do acordo, nem os estados/fecho da conexão ou de outras candidaturas.
+
+Rastreabilidade: evento partnership_milestone.changed.v1 e envelope de auditoria acrescentam previous_responsible_id/responsible_id. A reatribuição é um comando versionado explícito; versões antigas, responsável de outra sala/organização ou participante sem representação actual continuam recusados. Não se reescrevem eventos anteriores e não se promete um arquivo integral de todas as versões do texto/evidência do marco. Exibir o nome actual do cadastro não transforma essa pessoa em representante actual nem concede acesso ao responsável histórico. A regra de consulta da sala e a regra de atribuição continuam distintas. A listagem é informativa; não se acrescentou garantia de serialização de revogações além das guardas/locks existentes.
+
+Provas: PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9,25/211 na ronda final. Casos novos cobrem representantes de ambos os lados, resposta mínima, revogação do autor e substituição expressa/evento, participações pessoais, deduplicação de representação dupla, consulta/encerramento, escolha desactualizada após downgrade, pessoa alheia, versão antiga e organização eliminada. Prova inicial da lacuna:3 falhas de asserção e1 erro do teste por propriedades ainda ausentes em respostas200; não quatro falhas HTTP. Primeira fixture sem tipo da parceria foi corrigida antes dessa reprodução e o diagnóstico conservado. Frontend1413 em todos os ficheiros *.test.mjs;6 casos novos exercitam os componentes transpilados, opções por nome/lado, escolha explícita, atribuição anterior, estados sem edição, lista alterada sem troca silenciosa e nome indisponível. Não é aceitação visual em navegador. PHPStan passou sem supressões antes da formatação, que alterou somente o estilo do teste; Pint--test final, tipos e build exit0. Avisos de fontes/chunks/tempos existentes mantidos.
+
+QA e limites: base partnership_participants_20261103_test em127.0.0.1:55441/investmoz_test,45 tabelas conferidas vazias depois do processo terminal, com lock adquirido, proprietário e RLS verificados. Sem nova migração, escrita activa, notificação externa ou importação de pessoas reais. Preservados65 recibos e143 provas aceites anteriores; deltas de código explicitados no novo recibo. A recuperação/comparação integral dos formulários de acordo, candidatura e marcos continua como saldo próprio: este incremento não remove o remontar da sala pela versão nem promete conservar todas as edições noutra actualização. Também não implementa novas notificações dirigidas aos representantes em substituição dos destinatários históricos. Próxima acção: continuar esses percursos e as variantes restantes da matriz, observar a apresentação no navegador e disponibilizar no destino no âmbito próprio. AUD-PART-01 permanece parcial.
+
+### 03/11/2026 — AUD-PART-01: recuperação dos formulários da sala e repetição sem efeitos duplicados
+
+[PARTNERSHIP-ROOM-RECOVERY-20261103] Sala deixa de remontar pela versão; acordo, marcos, mensagem e ficheiro preparados conservam-se durante actualizações. Alterações deliberadas exigem comparação por campo/contexto e escolha explícita nos conflitos; controlos intocados acompanham os dados actuais sem pedir comparação de um formulário vazio. Estado/acesso posteriores limitam novas gravações e conservam preparação; aviso único antes de sair. Novos marcos e documentos usam chave/conteúdo por actor/sala no histórico existente, com lock da sala; mensagens reutilizam a chave já existente. Repetição confirmada é leitura, mesmo após encerramento, sem novos marcos, bytes, partilhas, eventos ou scans.34 Feature/310 asserções (9 novos),foco final2/37 sobreposto para caixa UUID,1429 frontend em regressão ampla e22 focados finais sobrepostos (16 novos e6 adaptados), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 marco,1 documento/ficheiro,2 eventos/auditorias e1 pedido de scan; lock do marco demonstrado, seguido de replay documental.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_room_recovery_increment_20261103; sem migrações/escritas activas.
+
+Origem e inventário: orientação expressa de23/10 sobre reutilização, conservação de edições e explicação de divergências/impactos, e AUD-PART-01 (versões, sala, marcos e participantes). O incremento anterior identificara a remontagem de RoomPage pela versão e dos marcos pela versão, bem como o saldo de recuperação dos formulários. Confirmadas essas chaves no código e reconferido o recibo partnership_participants_increment_20261103 antes de alterar. A proposta funcional e os estados existentes foram preservados; não se criaram competências, etapas ou aprovações. Chaves/hashes de comandos são uma escolha técnica de repetição segura, sem nova pergunta de negócio ao utilizador.
+
+Editor e comparação: identidade da sala mantém-se durante actualizações preservadas pelo Inertia; navegação normal para outra sala continua a ter o ciclo próprio da página. Resposta de outra sala não reinicializa nem autoriza gravar no destino diferente; outra conta recebe editor próprio. Acordo e cada marco têm bases/versões independentes, estado/acesso corrente e geração das edições. Mudança remota não sobrescreve texto, inclusive retorno deliberado ao valor original, edição posterior ao envio e resolução de vários conflitos. Comparação apresenta valores guardados/locais e exige opção explícita por campo em conflito; adopção incorpora apenas actualizações compatíveis e conserva o que foi escolhido. Controlos sem qualquer edição ou comando incerto seguem o estado actual, evitando confirmação redundante num novo marco vazio. Erros409, falha de rede, resposta inválida ou inesperadamente mais recente conservam a preparação e suspendem a gravação até recuperação/comparação. Actualizar dados iguais à base pode resolver uma pendência transitória sem inventar uma versão nova.
+
+Estados e sentido da acção: fecho/perda de escrita mantém preparação visível/desactivada em memória, sem a transformar numa nova autorização. Marco que estava em edição não é desmontado quando a sala muda para negociação ou estado terminal; formulários limpos continuam omitidos nesses estados. Atribuição histórica conserva nome do cadastro actual e indicação correcta: lista de atribuição indisponível num estado não é, por si só, prova de perda de representação. Acções de acordo usam versão revista e motivo; só registar altera título/condições. Confirmar/iniciar/renovar/cancelar/concluir continuam a agir sobre o instrumento actualmente guardado, apresentado acima; a interface avisa quando existe instrumento local ainda por registar. A confirmação conserva edições locais não enviadas e não certifica assinatura jurídica. Não se mudou quem pode confirmar, a sequência de estados ou a regra dos marcos pendentes.
+
+Mensagem e ficheiro: cada tentativa conserva o comando originalmente enviado, incluindo File imutável e autorização de partilha. Repetir após incerteza usa esse comando/chave; texto, selecção de ficheiro ou consentimento preparados depois ficam para uma próxima operação e não são apagados pela confirmação anterior. Resposta válida exige a sala esperada e identificação do efeito nos dados devolvidos. O campo nativo do ficheiro só é limpo quando o envio correspondente foi confirmado, mantendo uma selecção posterior; identificação do ficheiro preparado permanece visível. Mensagens e marcos devolvem a chave apenas ao respectivo actor; documento é reconciliado pelo identificador devolvido em flash e pela ligação/autor na sala. Estas referências não dão acesso à contraparte, não substituem autorização de download e não activam o documento.
+
+Servidor/idempotência: PartnershipMilestones e PartnershipRoomUploads reutilizam a autorização do PartnershipExchange, os locks da sala, repositório privado e eventos/auditoria existentes. Novos marcos/documentos com chave UUID registam no evento a referência do comando e hash normalizado do conteúdo; sem nova tabela/migração nem ledger concorrente. A pesquisa actor/sala/tipo/chave e a gravação/evento são serializadas pelo mesmo lock. Caixa maiúscula/minúscula da UUID é normalizada na entrada HTTP. Repetir conteúdo diferente sob a mesma chave devolve409. Pedidos legados sem chave continuam compatíveis e não recebem por inferência garantia de idempotência. Actualizações de marco mantêm a versão e as regras de responsável/evidência anteriores. Não se adiciona um novo evento ou se reescreve o marco actual ao recuperar a criação, mesmo se o marco já tiver versão posterior.
+
+Recuperar após encerramento: a autoridade actual de escrita continua obrigatória; o replay exacto já executado é identificado antes de rejeitar novas escritas pelo estado terminal. Isso permite confirmar uma operação anterior, sem nova mensagem, ficheiro, marco ou alteração de estado. Se não existe operação anterior, permanece409 no estado terminal; conta de consulta ou representação revogada não recupera autoridade pela chave. Upload repetido não volta a autorizar partilha posteriormente revogada e não volta a pedir scan. Novos bytes continuam privados/quarentenados e sujeitos à análise/hash/ACL de download já existentes. Falha transaccional remove apenas o ficheiro recém-criado sob o prefixo autorizado, preservando originais anteriores. A confirmação de envio não prova execução do worker/scan, autenticidade ou vigência. Não se implementou novo mecanismo de reencaminhamento se a fila falhar após commit; esse acompanhamento operacional continua separado.
+
+Provas: PartnershipRoomRecoveryTest9, PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9:34/310. Foco final2/37 sobreposto confirma a normalização UUID após a ronda principal, sem somar casos/asserções de rondas. PHPUnit cobre efeito único, hash/conteúdo/ficheiro/consentimento, escopo por actor, compatibilidade legada, leitura após encerramento, versões antigas, revogação, privacidade de chaves, bytes/quarentena e rollback com original preservado. Frontend1429 em todos os *.test.mjs e22 focados finais sobrepostos depois da correcção do rótulo contextual de estado,16 casos novos de recuperação e6 casos anteriores do selector adaptados ao modelo que executa também os hooks reais. O harness respeita identidade/key, frames separados, efeitos/limpeza e respostas de Inertia, mas não é um navegador/ensaio visual. Os diagnósticos de tipagem, redundância de comparação, aviso do harness e resposta de sala errada foram conservados; corrigidos sem supressões. PHPStan/Pint--test/tipos/lint e build exit0; avisos conhecidos de fontes/chunks/tempos mantidos.
+
+Concorrência e QA: base principal partnership_room_recovery_20261103_test,127.0.0.1:55441/investmoz_test;45 tabelas conferidas vazias após o foco final terminal, com lock do processo adquirido e owner/RLS verificados. Disco fake dos testes não é o repositório activo. Base separada partnership_room_recovery_race_20261103_test conserva fixtures sintéticas e ficheiro original próprios. Dois processos e conexões PostgreSQL distintos; espera pelo lock da sala demonstrada na criação do marco. Primeiro processo criou marco e documento, o segundo recuperou ambos:1 marco,1 ligação/documento/ficheiro,2 eventos e2 auditorias acrescentados,2 notificações de marco e1 pedido fake de scan. Os bytes mantiveram o hash. O ensaio não forçou uma disputa independente entre dois uploads simultâneos; essa leitura documental seguiu a disputa do marco. Estados preparados directamente nessa fixture comprovam serialização do serviço; os34 testes HTTP exercitam separadamente o workflow/autoridade/validação. Sem envio externo ou pessoas reais.
+
+Preservação e saldo:66 recibos e152 provas anteriores conservados;11 fontes do incremento e deltas autorizados identificados no recibo. Este registo substitui apenas a pendência anterior da remontagem/recuperação dos formulários da sala, sem apagar a prova histórica. Preparação permanece em memória, com aviso único antes de sair; não há novo localStorage/autosave nem promessa de recuperação após fechar/recarregar o navegador, perder a página ou voltar a autenticar. Eventos não passam a guardar todo o texto de cada versão do marco. Continuam pendentes candidatura/avaliação por consumidor, apresentação visual, destinatários actuais das notificações, variantes documentais/sala e disponibilização no âmbito próprio. Línguas/modelos oficiais já pendentes não foram inventados. AUD-PART-01 e auditoria global permanecem parciais.
+
+Último delta de apresentação: pending de marco tem rótulo Pendente, distinto de pending legado da proposta. A fixture foi alinhada ao dicionário real e reproduziu1 falha entre16 casos;22 casos finais da sala/selector passaram após a correcção. A ronda ampla1429 e este foco22 sobrepõem-se e não devem ser somados. Build/tipos/lint finais correspondem a esse fonte.
+
+### 03/11/2026 — AUD-PART-01: candidaturas identificadas, recuperação e avaliação no contexto revisto
+
+[PARTNERSHIP-CANDIDACIES-20261103] Corrigidas quatro falhas reproduzidas: omissão apagava organização/declarações; actualizar outra candidatura podia atingir o registo errado; faltava autorização efectiva por candidatura na resposta; repetição de submissão já executada devolvia409. Agora identidade explícita, omissões conservadas e remoções explícitas, versões/consentimento/representação anteriores mantidos, snapshots privados de submissão/avaliação e repetição actor/parceria/tipo/chave sem nova decisão. Formulários mantêm preparação e comparam divergências; declaração e avaliação têm bases próprias, perda de acesso conserva apenas preparação local e não concede autoridade. Versão da parceria/hash de critérios conferidos no servidor para novos clientes, retirada independente da janela/requisitos. Ordem de locks parceria→candidatura partilhada.47 Feature/401 asserções (13 novos),1451 frontend (22 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real:1 ressubmissão/1 avaliação antiga recusada409,1 evento/auditoria,2 notificações locais e replay só de leitura.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_candidacies_increment_20261103; sem migrações/escritas activas.
+
+Origem e inventário: AUD-PART-01 exige consentimento, versões, candidatura isolada, retirada, sala e marcos com papéis reais; orientação expressa de23/10 exige reutilizar informação e conservar edições deliberadas, explicando divergências. Reconferidos código, recibo partnership_room_recovery_increment_20261103 e provas aceites antes de continuar. Candidacy remontava pela versão; actualização escolhia o primeiro registo por autor OU organização, substituía todo o payload e assumia organizaçãoNULL quando omitida. Reproduções: perda de organização (HTTP200), edição de candidatura organizacional retirada afectava a pessoal com a mesma versão (HTTP200 com ID errado), ausência de can_edit por candidatura e replay após avaliação devolvia409. Não se classificaram as quatro como erros500.
+
+Identidade, autoridade e dados: novos pedidos identificam a candidatura seleccionada; o servidor confirma parceria, acesso actual, versão e estado. Pedidos anteriores sem ID continuam pelo mesmo percurso quando existe um único candidato possível; ambiguidade é409, sem seleccionar por ordem nem alterar outra candidatura. A organização omitida e as declarações/classificações autorizadas omitidas são conservadas; null/vazio expressos continuam a remover informação. A proposta e o consentimento aceite mantêm as exigências anteriores; não se infere novo consentimento de dados antigos. Nenhuma condição de empresa, NUIT, documento, verificação de e-mail ou MFA foi acrescentada ao percurso pessoal. Autor original permanece; retirar explicitamente uma organização não transforma o representante em autor. O formulário explica que essa escolha pode terminar o seu acesso, de acordo com a regra pessoal já existente.
+
+Consulta e capacidades: resposta identifica can_edit de cada candidatura usando a mesma owns/representação do comando; viewers podem consultar no âmbito anterior mas deixam de ver acções de escrita/retirada. canStartInterest reflecte a unicidade anterior por autor/parceria, evitando oferecer nova candidatura a um autor cujo registo deixou de estar acessível por representação. Não se alteraram os predicados de visibilidade da parceria: numa proposta que deixou de estar disponível à conta, a página pode continuar indisponível mesmo quando a API reconhece uma operação anterior. Não se expuseram rascunhos ou novos detalhes privados para contornar isso. A lista de candidatos mantém o isolamento anterior e as chaves de comandos são devolvidas apenas ao actor que os emitiu.
+
+Submissões e auditoria: nova submissão continua a reiniciar a avaliação actual e a passar ao estado submitted, conforme o comportamento existente. A interface explica esse impacto. Antes de o fazer, o evento existente conserva snapshot da versão anterior: organização, proposta, declarações, avaliação, motivo, estado e versão; conserva também a versão submetida. Decisões conservam o snapshot anterior e o contexto realmente utilizado: versão da parceria, algoritmo/hash, pesos, obrigatoriedade, evidências e resultado de correspondência. Não se alteraram pesos, limiares ou o significado de desconhecido. Campos alheios ao contrato da avaliação deixam de ser persistidos; autoria/data da avaliação continuam a ser fixadas no servidor. Estes snapshots são privados, a partir deste incremento; não reconstituem versões antigas sem prova nem constituem ainda um leitor completo de revisões para todos os actores.
+
+Concorrência do conteúdo revisto: novos clientes enviam a versão da parceria e o hash dos pesos ao decidir; o servidor confere-os dentro do lock da parceria antes da escrita. A candidatura mantém o controlo próprio da versão. Mudança de declarações, requisitos ou pesos não autoriza aplicar silenciosamente uma avaliação velha. Legacy sem os novos tokens mantém o protocolo anterior; não se promete a mesma guarda adicional a pedidos que não os enviem. Retirada continua dependente da candidatura/representação actual e não da publicação/janela/pesos da parceria. Ordem de locks foi uniformizada em parceria, depois candidatura, eliminando a inversão entre ressubmissão e avaliação neste percurso. Não se criou aprovação por silêncio, nova competência ou passagem automática de desconhecido a incumprido.
+
+Recuperação e interface: componentes deixam de remontar por versão. Preparação é mantida por candidatura e por acção, com geração de alterações inclusive retorno deliberado ao valor inicial, eventos batched e escrita posterior ao envio. Comparação por campo conserva declarações compatíveis só após adopção explícita; estado/evidência do mesmo critério são uma unidade. Critérios retirados permanecem identificados em preparação local, sem integrar o pedido actual; descarte local é explícito e não apaga auditoria. Dados intocados acompanham actualizações, evitando confirmar formulários vazios. Após criação, o mesmo editor passa ao ID/versão do registo e conserva o texto preparado depois de enviar, sem duplicar formulários. Se a candidatura sai da lista por perda de acesso, só a preparação local permanece desactivada; outra conta tem editor próprio. Um único aviso de saída cobre as preparações independentes. Não há novo localStorage/autosave ou recuperação garantida depois de fechar/recarregar, sair da página ou autenticar novamente.
+
+Decisões e repetição: cada tentativa nova usa UUID e hash do conteúdo no histórico existente, sem tabela/migração paralela; busca e evento serializados pelo lock da parceria. UUID é normalizada na entrada. Recuperar repete o comando original, respeitando autoria/representação actuais, sem reiniciar avaliação, duplicar sala/evento/notificação ou reescrever decisões posteriores. Mesmo nonce com conteúdo diferente é409. Motivo ou avaliação preparados após o envio são conservados. Acções que não guardam avaliação enviam assessment vazio e usam a avaliação guardada, com aviso visível sobre edições ainda por guardar. Respostas de outra parceria, incompatíveis ou com dados posteriores não apagam preparação nem conferem autoridade. Ao comparar um contexto novo, o utilizador pode preparar uma nova tentativa explícita; não é uma repetição automática da acção anterior. Leitura por chave não reabre a janela de submissão nem a candidatura.
+
+Preservação e apresentação: comparação com o ecrã anterior detectou a necessidade de manter peso, obrigatoriedade, evidência e explicação de cada critério; esses elementos foram repostos e recebem teste específico. Intervalo indeterminado apresenta Por determinar, sem percentagem falsa, zero inventado ou aprovação. O restante detalhe público, origens/geografia, moderação e ligações à sala foram conservados. Hash comparativo normalizado por finais de linha confirma que PartnershipExchange fora de interest/decideInterest não mudou; os métodos públicos delegam numa única implementação de candidaturas. A hipótese de opções duplicadas por vários vínculos activos foi rejeitada pelo índice parcial imz_memberships_user_id_organization_id_uq, definido em2026_09_24_012000_investmoz_indexes.php. A fixture inválida foi corrigida, sem remover o índice nem manter uma alteração desnecessária da query; entidades diferentes com nome igual permanecem distintas.
+
+Provas: PartnershipCandidaciesTest13, PartnershipRoomRecoveryTest9, PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9,47/401 na ronda final. Casos incluem identidade exacta/ambígua/estrangeira, omissão/remoção, snapshots, consentimento, replay normalizado e posterior a decisões, perda de representação, critérios/versão antigos, retirada fora da janela e nomes iguais sem fusão. Frontend1451 em todos os *.test.mjs,22 novos casos com componentes/hooks efectivamente transpilados e dicionário de rótulos lido do fonte real. O modelo respeita frames, keys, efeitos, respostas e limpezas, mas não é prova visual num navegador. PHPStan sem supressões, Pint--test, tipos/lint e build exit0; avisos de fontes/chunks/tempos já conhecidos mantidos. Rondas anteriores e falhas de fixture/harness/comando foram retidas sem as declarar falhas actuais ou somar casos.
+
+Concorrência real e isolamento: base principal partnership_candidacies_20261103_test,127.0.0.1:55441/investmoz_test;45 tabelas conferidas sem linhas após o último processo terminal, com lock adquirido e owner/RLS verificados. Base separada partnership_candidacies_race_20261103_test retém actores e workflow sintéticos. Dois processos/conexões PostgreSQL: nova submissão detém o lock da parceria, avaliação antiga espera, submissão grava versão2 e a avaliação recusa409 sem deadlock nem sobrescrita.1 evento/1 auditoria/2 notificações acrescentados; snapshot anterior e declarações novas conservados, avaliação não reaplicada e replay da submissão sem escrita. O delta final acrescentou contexto de matching à auditoria; o ramo de conflito da prova concorrente continua anterior a essa escrita. Não há pessoas reais, comunicações externas, alterações no activo ou instalação de migracões.
+
+Saldo:67 recibos e165 provas anteriores conservados,10 fontes do incremento e deltas autorizados identificados. AUD-PART-01 e a auditoria integral continuam parciais. Ficam o leitor/variantes de história por actor, outras transições de papel, destinatários actuais das notificações, apresentação visual, recuperação além da página e disponibilização no âmbito próprio. O formulário de publicação/moderação da parceria é outro consumidor, não declarado recuperável por este incremento. Fontes/modelos/traduções já pendentes permanecem no inventário existente; nenhuma dependência genérica de aprovação foi criada para continuar o desenvolvimento.
+
+### 03/11/2026 — AUD-PART-01: consulta privada das versões e decisões das candidaturas
+
+[PARTNERSHIP-HISTORY-20261103] Leitor dos eventos existentes, sem recalcular ou reconstruir valores históricos com dados actuais. Acesso actual à candidatura/parceria e conferência adicional do âmbito guardado em cada versão para o candidato. Página privada com comparação antes/depois, avaliação e parâmetros realmente guardados, links no painel e candidatura; paginação estável por cursor cifrado vinculado à conta/candidatura. 57 Feature/488 asserções (10 novos),1460 frontend (9 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, identidade/owner/RLS/lock conferidos. Recibo partnership_history_increment_20261103;68 recibos e177 provas anteriores preservados. AUD-PART-01 permanece parcial, sem instalação/escritas no activo.
+
+Origem: requisito AUD-PART-01, documento segmentar processos v1.docx (parágrafos479/481: estados, reabertura, versões e histórico) e orientação de23/10 para conservar dados efectivamente utilizados. Reutilizados eventos/snapshots e autorização owns existentes, sem novo perfil, migração, concessão ou alteração de elegibilidade. Este incremento implementa a leitura que estava explicitamente pendente no recibo anterior; não declara todos os fluxos do módulo concluídos.
+
+Autoridade: o responsável actual pela parceria pode consultar as candidaturas do processo pelo predicado de leitura existente. Candidato exige acesso actual à candidatura e a cada snapshot pelo user_id imutável e organization_id efectivamente guardado. Outro candidato, moderador sem esse vínculo ou representante revogado não recebe consulta por inferência. Troca entre organizações A/B não transfere o texto de A para representantes de B. Versão sem âmbito histórico conhecido fica scope_unknown para o candidato; não é inventada participação pessoal. Lacunas antigas mantêm-se parciais para o responsável autorizado.
+
+Dados: a página apresenta estados, declarações, consentimento, avaliação e motivos realmente registados; campos ausentes distinguem-se de null/vazio expressos. Parâmetros congelados de matching, algoritmo/hash, pesos, obrigatoriedade, evidência e explicação provêm apenas do evento da decisão; não se aplica Matching.explain actual. Zero válido permanece zero; parâmetro malformado/ausente permanece desconhecido. Os nomes de pessoas/organizações e rótulos da lista de avaliação provêm do cadastro/catálogo actual e a interface declara essa origem; não são apresentados como nomes históricos congelados. Os rótulos do contexto de matching são os guardados nesse contexto.
+
+Privacidade e navegação: rota GET autenticada protegida pelo middleware privado existente, Cache-Control private/no-store e histórico Inertia cifrado. Não expõe nonces, hashes de comandos, IDs de eventos, contador global, título/offer/payload actual da parceria. Candidatura autorizada continua consultável após arquivo da parceria por um link próprio, sem alargar a visibilidade da página original. Link à parceria só é oferecido quando publicada ou acessível pelo responsável. Cursor cifrado vincula actor/candidatura, revalida acesso em cada pedido e pagina10 eventos por aggregate_version; inserções posteriores não duplicam versões ao avançar. Não há botões de restaurar, reaplicar ou decidir neste leitor.
+
+Provas:10 novos Feature cobrem contexto congelado após mudança de configuração, snapshots antes/depois, concorrentes/moderação/anonimato, viewer/revogação, mudança A/B, legado parcial,21 decisões e inserção entre páginas, cursor estrangeiro/inválido, arquivo sem rascunho exposto, resposta Inertia e consulta sem escrita, parâmetros malformados. A primeira ronda teve9/10: o pedido Inertia sem X-Inertia-Version recebeu409 de actualização de recursos. A fixture passou a enviar a versão real do middleware; nenhuma guarda da aplicação foi removida.9 casos frontend novos transpilam as páginas/componentes reais, verificam valores/conteúdo reservado, campos ausentes, escape de texto, navegação sem escrita e manutenção da preparação existente. Não equivalem a aceitação visual no navegador.
+
+Isolamento e saldo: base partnership_history_20261103_test em127.0.0.1:55441,role investmoz_test,45 tabelas conferidas sem linhas após processo terminal com lock,owner e RLS efectivos. Sem migrações novas, instalação no activo, pessoas reais ou comunicações externas. Preservados recibos e provas anteriores; a corrida PostgreSQL do incremento anterior mantém o seu âmbito e não foi apresentada como nova prova deste leitor. Mantêm-se outros consumidores de edição/publicação/moderação, variantes de papéis/representação, destinatários actuais de notificações, recuperação além da página e validação visual/entrega no âmbito próprio. As traduções e os sete modelos sem fonte permanecem pendentes já inventariados, sem nova pergunta repetida.
+
+[PARTNERSHIP-HISTORY-FOLLOWUP-20261103] Próxima acção concreta identificada na revisão: o dashboard anterior ainda selecciona p.title actual para uma candidatura, incluindo quando a parceria deixou de estar publicada, e as notificações são listadas pelo destinatário histórico sem voltar a conferir a representação. O novo leitor não devolve esse título privado; esta prova limita-se ao GET do histórico. Conferir/corrigir a projecção e os links do painel e os destinatários/visibilidade das notificações com provas próprias, reutilizando a autoridade existente. Não declarar a privacidade de todos os consumidores encerrada por este incremento.
+
+### 03/11/2026 — AUD-PART-01: painel e avisos pelo âmbito actual e histórico
+
+[PARTNERSHIP-DASHBOARD-20261103] Corrigidas três falhas reproduzidas: título privado após despublicação, organização eliminada ainda no painel e aviso de representante revogado. Painel projecta só título/link autorizados; representação usa o mesmo cadastro activo de owns. Avisos novos seguem participantes operacionais actuais e guardam contexto no evento existente; leitura e confirmação exigem destinatário, acesso actual e âmbito guardado. Links reconstruídos para candidatura/sala/parceria; primeira leitura preservada. 73 Feature/576 asserções (16 novos),1466 frontend (6 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.69 recibos e185 provas anteriores preservados. Recibo partnership_dashboard_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: continuação concreta PARTNERSHIP-HISTORY-FOLLOWUP-20261103 e AUD-PART-01. O leitor anterior não devolvia rascunho privado, mas a consulta do painel ainda seleccionava p.title actual e a lista de avisos filtrava apenas user_id; /ler também só conferia esse destinatário. Três reproduções anteriores à correcção falharam por conteúdo exposto/avisos acessíveis, sem as classificar como erros500. A consulta do painel passa a excluir organizações eliminadas pelo mesmo join e deleted_at já usados na representação efectiva, sem inventar novos perfis.
+
+Painel: candidaturas pessoais/organizacionais autorizadas conservam estado, motivo, sala e consulta do histórico. Título/link da parceria só são devolvidos quando a mesma conta pode abrir o detalhe existente: publicada, responsável com leitura ou moderador efectivo. Caso contrário title e partnership_href são null e a interface explica a indisponibilidade; não recebe título, oferta ou estado privado da nova proposta. O dono/representante actual e o moderador mantêm as consultas existentes. As permissões de edição/decisão não são ampliadas por ter um link ou ver o painel.
+
+Encaminhamento: apenas eventos que já pediam avisos continuam a produzi-los. A intenção anterior para uma ou ambas as partes é resolvida para as pessoas actuais, usando a mesma query de representantes e os mesmos papéis admin/manager/officer usados nos comandos e participantes operacionais. Parte pessoal mantém o seu titular; fundador revogado ou organização eliminada não são destinatários por arrasto. Viewer não recebe automaticamente nova distribuição operacional, mas pode ler o aviso individual que já recebeu enquanto conservar acesso de leitura ao âmbito actual e histórico. IDs sobrepostos são desduplicados por evento. Eventos antes sem aviso, incluindo acesso/documentos, continuam sem nova distribuição. Não há envio externo, calendário, assinatura ou concessão adicional.
+
+História e autoridade: o evento/auditoria existente conserva _notification_context versão1, referências do processo/candidatura/sala e user_id/organization_id das partes efectivas no momento. Não se reescrevem eventos ou destinatários anteriores, nem se redistribuem avisos antigos a um novo membro. O leitor exige o destinatário individual e, para pelo menos uma parte, tanto owns actual como owns no âmbito guardado. Passar de A para B não autoriza ler o aviso de A só por agora representar B; revogação, organização eliminada, destinatário estranho e contexto malformado são recusados na leitura e no POST/ler. Inconsistência de candidatura/sala/processo na preparação do evento aborta a transacção sem evento/auditoria/aviso cruzado.
+
+Legado: eventos de candidatura sem o novo contexto só reutilizam o organization_id efectivamente presente no snapshot submitted/previous, com user_id imutável da candidatura; isso pode justificar a leitura pelo candidato, nunca inventa o âmbito histórico do proponente. Avisos sem contexto demonstrável não expõem título/link nem permitem confirmar leitura; continuam intactos no registo e a interface explica a limitação. Contexto explícito inválido não é degradado para uma reconstrução legada. A correcção não promete recuperar informação que não foi registada.
+
+Consulta e confirmação: filtragem precede o limite de50 avisos visíveis e percorre lotes de100 por ID. Foram atravessadas105 notificações inacessíveis para alcançar um aviso autorizado mais antigo;55 autorizadas conservam as50 mais recentes por ordem, sem duplicações. Nunca é devolvido o href bruto antigo: destinos são construídos para o histórico da candidatura, a sala actual correspondente ou a parceria autorizada. Marcar como lido volta a conferir autoridade na transacção e preserva o primeiro read_at em repetições; não decide processos nem acrescenta eventos de negócio. Mensagem repetida conserva a distribuição original sem novos avisos.
+
+Validação:16 novos Feature mais57 existentes cobrem dados publicados/privados, organização eliminada, moderador, representação operacional/viewer, autor revogado, mudança A/B em candidatura e proponente, legado, contexto malformado/cruzado, paginação, leitura idempotente e mensagem/sala.6 casos frontend transpilam a página real e conferem links, explicação, escaping, navegação existente e comando de leitura só do aviso apresentado. PHPStan inicial identificou tipos de retorno sem garantia de lista; consultada documentação primária return.type e corrigida a construção dos arrays/validação da identidade, sem casts para ocultar erros, supressões ou alargamento de contrato. As rondas diagnósticas foram conservadas, sem as somar à regressão final.
+
+Isolamento e saldo: base partnership_dashboard_20261103_test em127.0.0.1:55441,role investmoz_test,45 tabelas vazias após execução terminal; lock,owner e RLS conferidos. Mantidos69 recibos e185 provas aceites e deltas apenas nos consumidores previstos. Sem nova migração, alteração de contas/pessoas reais, comunicação externa ou instalação no activo. Este incremento resolve a lacuna concreta apontada no leitor anterior; permanecem publicação/moderação e recuperação desse editor, variantes transversais de papéis/representação e apresentação visual/entrega. Alertas de prazo/inactividade, notificações externas e cobertura integral dos consumidores não são inferidos desta correcção.
+
+### 03/11/2026 — AUD-PART-01: recuperação da publicação e moderação da parceria
+
+[PARTNERSHIP-PUBLICATION-20261103] Publicação/moderação preserva motivo por proposta/conta e compara contexto antes de nova tentativa; replay por UUID/actor no evento, autoridade actual e estados existentes. Suspensão exposta pela capacidade real. Snapshot anterior/aplicado privado, metadados seguros no detalhe e um único aviso de saída com as candidaturas. 85 Feature/642 asserções (12 novos),1482 frontend (16 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.70 recibos e194 provas anteriores preservados. Recibo partnership_publication_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-PART-01, orientação de23/10 e saldo PARTNERSHIP-DASHBOARD-20261103. O editor de conteúdo já tinha comparação/preparação em parceria-edit; não foi declarado ausente nem substituído. A lacuna concreta estava em Publication: remontagem por record.version apagava o motivo, /estado não reconhecia repetição de uma decisão gravada e a UI omitia suspend, já permitido no servidor. Foram reproduzidas três falhas Feature e uma perda de motivo no componente real antes da correcção.
+
+Autoridade e estados: PartnershipExchange.transition conserva a assinatura anterior e delega no serviço central PartnershipPublication, com clientKey opcional. Reutiliza os estados e permissões anteriores: titular/representante com escrita para submit/archive/renew; manage-portal e exclusão de owns com escrita para publish/return/reject/suspend. A capacidade exposta à UI provém dessa mesma regra; não se introduziu outro requisito de empresa, NUIT, documentos, aprovação ou aprovação por silêncio. A autoridade actual é conferida antes da versão e do replay; um actor estranho já não recebe409 por uma versão antiga antes de lhe ser recusada a operação. Não se alterou a definição de independência para inferir papéis novos.
+
+Decisões: motivo obrigatório até2000 e requisitos anteriores de submissão mantidos. UUID normalizada e hash de version/action/reason guardados no evento existente, no lock da parceria. Repetir a tentativa exacta pelo mesmo actor é leitura, mesmo depois de outra transição, sem incrementar versão, repetir revisão, evento, auditoria ou aviso. Mesma chave com conteúdo diferente é409; outro actor/processo tem âmbito próprio e autoridade sempre conferida. Pedidos legados sem chave conservam o protocolo anterior, sem promessa de replay identificável. Não há nova tabela/migração nem novo motor de workflow.
+
+Auditoria: eventos novos conservam snapshot anterior e aplicado da proposta, incluindo estado/versão, organização, título, oferta/procura, declarações, origem/localizações e published_at realmente utilizados; _creation_hash não integra esses snapshots. Não se reconstituem versões antigas. A API do detalhe passa a projectar no histórico apenas os metadados já apresentados na UI (tipo, autor e data), mantendo o envelope privado no registo. Chaves de recuperação são projectadas apenas para o seu actor com competência actual, sem devolver hash, contexto de avisos ou snapshots completos de outras representações. Um leitor próprio das versões da publicação continua pendente; a captura privada não é esse leitor.
+
+Interface: componente deixa de remontar por versão e fica identificado por proposta/conta. Conserva motivo deliberado e gerações de edição durante comparação, falha, alteração de estado/acesso e resposta tardia. Uma resposta só confirma a tentativa se o ledger do actor trouxer chave/acção/versão compatíveis; alterações posteriores ficam por rever, em vez de serem adoptadas como se fossem o contexto decidido. Recuperação repete o comando congelado e conserva texto escrito depois de enviar. Conflito ou resposta ambígua exigem consulta efectiva antes de adoptar contexto para nova tentativa; a adopção é explícita e conserva o motivo. Viewer/perda de competência não recebe escrita, mas mantém preparação local visível na mesma conta. Outra conta tem estado separado e callbacks de componente desmontado são ignorados.
+
+Formulários e navegação: os comandos actuais, incluindo suspensão, são apresentados a partir da capacidade do servidor. O motivo só é pedido quando existe acção aplicável ou preparação local; são explicados os efeitos da submissão/renovação e da adopção após tentativa incerta. Comparação apresenta os campos alterados, contexto revisto e estado/versão actual. Publicação e candidaturas partilham um único aviso de saída e conservam as preparações independentes; não há novo localStorage, autosave ou garantia depois de fechar/recarregar a página/autenticar de novo. Acções da publicação não decidem candidaturas nem alteram salas/marcos em cascata.
+
+Provas:12 novos Feature e16 novos frontend, incluindo replay após outra transição, nonce alterada/normalizada, snapshots, representação revogada, independência, metadados por actor, requisitos legados, suspensão, escopo entre processos, preparação durante refresco, edição posterior ao envio, conflito, acknowledgement posterior/incompatível, perda de competência, mudança de actor, aviso único e payload API vazio. Os testes transpilam os componentes/hooks reais. O harness inicial recriava setters de estado em cada render e produziu Component state did not settle; passou a conservar essa identidade por frame. Essa falha de modelo não foi apresentada como uma falha demonstrada no navegador. Um teste usava o rótulo abreviado Motivo em vez do rótulo real; a fixture foi corrigida. Lint inicial identificou conversão de objectos para texto; dados da comparação passam por validação de escalares, sem ocultar avisos.
+
+Isolamento e saldo: base partnership_publication_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas conferidas sem linhas após processo terminal, com lock/owner/RLS efectivos. Mantidos70 recibos e194 provas anteriores. A prova de concorrência PostgreSQL de candidaturas continua com o seu âmbito; não é uma nova corrida de publicação. Não houve migração/instalação no activo, pessoas reais ou comunicação externa. AUD-PART-01 e auditoria integral continuam parciais. Próximas lacunas: confirmação incerta da edição pós-criação, leitor das versões da publicação pelo âmbito histórico e variantes de representação/consumidores; prova visual e disponibilização no âmbito próprio continuam pendentes.
+
+### 03/11/2026 — AUD-PART-01: leitura privada das versões da publicação
+
+[PARTNERSHIP-VERSIONS-20261103] Leitor privado do histórico da publicação, antes/depois, por acesso actual e âmbito histórico. Captura de novas criações/edições reutiliza o snapshot das transições, sem inventar o placeholder de criação ou conteúdo legado.10 eventos por página, cursor cifrado por conta/processo/propósito, sem dados actuais no lugar dos antigos. 97 Feature/739 asserções (12 novos),1490 frontend (8 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.71 recibos e204 provas anteriores preservados. Recibo partnership_versions_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-PART-01 e saldo PARTNERSHIP-PUBLICATION-20261103. A publicação já conservava snapshots nas transições, mas o detalhe só apresentava tipo/autor/data e as gravações do rascunho conservavam apenas estado anterior e referências. Implementada consulta dedicada dos eventos existentes e completada a captura das gravações futuras. Não se criou outra tabela de história, matriz, backlog ou migração; os registos e provas anteriores permanecem intactos.
+
+Captura: PartnershipPublication.snapshot é reutilizado por transições e save. Edição guarda anterior/aplicado com versão, estado, âmbito, título, oferta/procura, declarações, critérios, sector e referências da origem/localização efectivamente utilizados. Criação guarda aplicado e previous=null: a linha vazia temporária inserida dentro da transacção não é inventada como uma versão anterior. Replay da criação continua leitura, sem nova revisão nem reescrita do snapshot. O hash de criação, nonce, hashes de comandos e envelopes de distribuição não são projectados para o leitor.
+
+Autoridade: a rota é autenticada e exige owns com leitura no processo actual ou manage-portal efectivo, tal como a leitura privada existente da proposta. Publicação pública e candidatura não concedem consulta histórica. Para o responsável da organização, cada snapshot exige ainda o âmbito guardado na versão; representar B não autoriza ler A nem o rascunho pessoal de outro titular. Revogação e organização eliminada impedem o acesso actual, incluindo por cursor antigo. Moderação efectiva conserva a leitura global já existente das propostas; isso não concede competência para decidir a própria proposta nem substitui as verificações dos comandos.
+
+Legado e integridade: falta de âmbito/identidade fica scope_unknown para o responsável, sem assumir participação pessoal. O moderador pode ler metadados parciais guardados, mas não recebe conteúdo actual como se fosse antigo. Um snapshot com ID de outro processo não é apresentado nem ao moderador como versão deste processo. Quando existe o contexto de aviso efectivamente gravado, pode justificar a projecção parcial do estado posterior/reason, sem inventar o anterior. Acção ausente continua Alteração registada, em vez de se deduzir uma decisão a partir do tipo do evento. Referências malformadas ficam assinaladas como incompletas; não equivalem a listas vazias.
+
+Apresentação: página de leitura compara antes/depois, estado/versão, motivo, conteúdo, consentimento, obrigatoriedade e referências guardadas. Ausente distingue-se de null/vazio explícitos, falso e lista vazia; zero/ausência não são fabricados. Não se recalculam decisões, nomes de critérios ou conteúdo de fontes; nomes de pessoas/organizações usam o cadastro actual e isso é explicado. Referências da origem/localização são apresentadas sem resolver catálogos actuais ou gerar ligações que concedam acesso a essas fontes. Fonte declarada não é validação oficial da hierarquia territorial. Não há formulário de restauro, nova publicação, aprovação ou sobrescrita a partir da história.
+
+Navegação e privacidade: links no detalhe, propostas próprias e fila de moderação; candidato conserva o seu link próprio de histórico de candidatura, sem receber o da publicação por inferência. GET privado/no-store e histórico Inertia cifrado.10 eventos por página, ordem decrescente e cursor cifrado vinculado à conta/processo/propósito publication; não expõe IDs de evento ou contador global e não aceita cursor de candidatura. Inserção posterior não duplica versões ao avançar. Não entram eventos de candidatura, sala, documento ou marco no histórico da publicação. O aviso de saída existente conserva a preparação antes de navegar.
+
+Provas:12 novos Feature cobrem criação sem placeholder, edição/transição, candidato/anónimo, mudança A/B, viewer, revogação/organização eliminada, moderação, legado conhecido/desconhecido,21 versões e inserção entre páginas, cursor por actor/processo/propósito, consulta sem escrita/cache/encriptação, referências após mudanças de cadastro, limpeza explícita, formas malformadas e replay sem nova revisão.8 casos frontend transpilam a página real e os consumidores nativos: comparação, ausência/falso/listas incompletas, âmbito reservado, legado, cursor, escape de texto, links e preparação local conservada. Estes ensaios não substituem aceitação visual no navegador.
+
+Isolamento e saldo: base partnership_versions_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas vazias após processo terminal e lock/owner/RLS conferidos. Preservados71 recibos e204 provas anteriores; apenas deltas de fonte previstos no incremento. Sem nova migração, instalação/dados no activo, pessoas reais ou comunicação externa. AUD-PART-01 e auditoria integral permanecem parciais. Continuam confirmação incerta de edição pós-criação, variantes transversais de papéis/consumidores, síntese de metadados no detalhe, prova visual e entrega no âmbito próprio. Traduções e modelos sem fonte continuam nas pendências anteriores, sem perguntas repetidas.
+
+### 03/11/2026 — AUD-PART-01: recuperação de edições sem confirmação
+
+[PARTNERSHIP-DRAFT-RECOVERY-20261103] Edições identificadas por operation_key/actor/processo, com replay no evento existente antes de validar cadastros vivos, sem repetir versão ou efeitos. Editor conserva comando e alterações posteriores, revalida consulta antes de nova tentativa e separa contas. Critérios/tipos anteriores mantêm identificação e remoção explícita da preparação. 109 Feature/802 asserções (12 novos),1502 frontend (12 novos) e28 focados verificados sem somar repetições;PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.72 recibos e212 provas anteriores preservados. Recibo partnership_draft_recovery_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-PART-01, orientação de23/10 e saldo PARTNERSHIP-VERSIONS-20261103. A criação já reconhecia client_key, mas uma edição gravada sem resposta voltava a receber409 ou podia falhar422 por tipo/critério entretanto retirado. O hook só congelava a criação. Foram reproduzidos dois Feature antes da correcção e um caso real do componente/hook, no ficheiro completo. Uma tentativa inicial com filtro de nomes não seleccionou o caso e produziu apenas o resultado do ficheiro; ficou como diagnóstico, sem a apresentar como reprodução ou aceitação.
+
+Identidade da tentativa: operation_key UUID por edição, independente do client_key de criação que se mantém. O evento changed existente guarda chave normalizada, hash do conteúdo relevante e result_version; o hash distingue omissão de remoção explícita e exclui a chave de criação que não altera a edição. Sob o lock da parceria, a autoridade actual precede procura de replay, versão, estado e validação de referências vivas. Mesma tentativa do mesmo actor/processo devolve leitura com versão originalmente gravada e estado actual, sem novo snapshot, versão, evento, auditoria ou aviso. Mesmo nonce com conteúdo diferente é409. Outra pessoa ou processo tem âmbito próprio; isso não autoriza recuperar o processo alheio.
+
+Regras preservadas: comandos novos continuam sujeitos aos estados, representação, tipo/critério activos, sector e fontes autorizadas existentes. As validações de catálogo foram colocadas depois do reconhecimento de gravação já concluída, tal como a validação de sector já estava depois do replay de criação. Tipo/critério/sector retirados não bloqueiam a leitura de uma tentativa concluída nem autorizam nova escrita inválida. Pedidos anteriores sem operation_key conservam a guarda de versão e não recebem falso replay. Retirar organização ou mudar âmbito mantém os seus efeitos e a autoridade original; recuperações de representante revogado ou viewer são recusadas.
+
+Projecção e acesso: editor devolve editorActorId e apenas chaves/versões de gravações do actor com escrita efectiva. A consulta usa projecções JSONB sem transferir envelopes completos para extrair os identificadores. Não expõe operation_hash, _creation_hash ou contexto privado de avisos. O histórico privado conserva os snapshots originais; não é reescrito por replay. A resposta JSON distingue replay e saved_version do estado/versão correntes. A leitura dos metadados não concede competência adicional ou autoria a outro representante.
+
+Preparação: tentativa de edição fica congelada, inclusive perante cancelamento ou resposta perdida, e Recuperar a mesma gravação envia o comando original. Gerações conservam campos escritos depois do envio; acknowledgement exige proposta/actor/chave/versão compatíveis. Uma resposta sem a chave do actor não limpa a preparação. Se houver versão posterior, o formulário reconhece a gravação antiga, mas conserva o contexto intermédio e exige comparação para outra escrita. Um valor já confirmado antes da edição de outra pessoa não é automaticamente reaplicado; o texto efectivamente preparado depois de enviar permanece local. Recusa de acesso suspende recuperação até nova consulta autorizada; nova tentativa após falha exige consulta efectiva e adopção explícita, mantendo as escolhas e usando nova chave.
+
+Separação e formulários: editor é identificado por conta, conservando a passagem de criação a ID atribuído na mesma conta. Outra autenticação inicia preparação própria; callbacks desmontados ou de tentativa abandonada não recuperam texto antigo. Recuperação fica fora do fieldset de edição, permitindo reconhecer uma gravação mesmo quando o estado posterior só admite consulta, sem nova competência de escrita. Grupos/tipos/organização que saíram das listas mantêm opção anterior identificada. Critério retirado pode ser removido explicitamente da preparação sem ser apagado do histórico; não é retirado automaticamente nem confundido com não aplicável. O comando de recuperação conserva o valor original e a nova escolha permanece para a gravação seguinte. Aviso de saída inclui tentativas ainda sem confirmação, mesmo sem diferenças de campos.
+
+Provas:12 novos Feature cobrem replay após submissão posterior, tipo/critério/sector retirados, nonce alterada/normalizada, chaves distintas sem mudar criação, representação revogada/viewer, metadados por actor, entradas inválidas/stale não consumidas, omissão/remoção e clientes legados/processos distintos.12 casos frontend novos ampliam o ficheiro de16 para28; os16 anteriores permanecem, com a fixture a modelar os novos metadados. O caso de uma edição posterior de outra pessoa foi reforçado para provar que, após comparação, esse título actual é adoptado enquanto texto preparado durante o envio permanece conservado. Há ronda completa e nova ronda focada desse ficheiro após o reforço, sem somar casos repetidos. Testes usam componentes/hooks reais transpilados; não são aceitação visual num navegador.
+
+Isolamento e saldo: base partnership_draft_recovery_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas vazias após processo terminal, lock/owner/RLS efectivos. Preservados72 recibos e212 provas aceites. Sem migração nova, instalação/dados no activo, pessoas reais ou mensagens externas. A prova PostgreSQL concorrente anterior conserva o seu âmbito; este incremento não a apresenta como nova corrida de edição. AUD-PART-01 e auditoria integral continuam parciais. Restam variantes de representação/consumidores, apresentação visual/entrega e síntese do histórico no detalhe; preparação continua em memória, sem garantia depois de fechar/recarregar ou voltar a autenticar.
+
+### 03/11/2026 — AUD-PART-01: recuperação e revisão de contexto nos acordos
+
+[PARTNERSHIP-AGREEMENTS-20261103] Acordos com tentativa identificada por actor/sala, recuperação sem duplicar efeitos após estados terminais e revisão da versão da proposta/candidatura. Confirmação bilateral pelas partes efectivas, histórico completo anterior e preparado posterior conservado; assinatura jurídica continua não verificada. 121 Feature/905 asserções (12 novos),1514 frontend (12 novos),28 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;73 recibos e224 provas anteriores preservados. Recibo partnership_agreements_increment_20261103; parcial, sem entrega activa.
+
+Origem e reprodução: AUD-PART-01, orientação de 23/10 e saldo dos incrementos anteriores. Dois casos demonstraram que repetir um cancelamento já concluído recebia 409 e que uma confirmação podia avançar sobre proposta alterada sem mudança da versão da sala. Um caso do componente/hook demonstrou a falta de recuperação da acção sem resposta. As falhas originais foram conservadas. Diagnósticos intermédios, incluindo uma ligação inicial incompleta ao serviço e fixtures de confirmação entretanto corrigidas, não são apresentados como provas finais.
+
+Comandos: as seis acções existentes (registar, confirmar, iniciar, concluir, cancelar e renovar) aceitam client_key UUID normalizada por actor, parceria e sala, com hash do conteúdo relevante. Motivo continua obrigatório; título/condições só fazem parte do comando de registo. A ordem de bloqueio é parceria, candidatura e sala. A representação efectiva actual é verificada antes do reconhecimento da tentativa. Um replay devolve a versão originalmente gravada e o estado actual sem novo evento, versão, auditoria ou aviso, incluindo após encerramento/cancelamento. Chave com conteúdo diferente é 409; outro actor ou outra sala não reutiliza a autoridade dessa tentativa.
+
+Contexto revisto: novos comandos da interface transportam a versão da proposta e da candidatura, além da versão da sala. Se o contexto mudou, o servidor recusa antes da decisão e o formulário conserva a preparação para comparação explícita. Esses dois tokens são opcionais por compatibilidade com clientes antigos; estes conservam a sua guarda de versão da sala e não recebem por inferência a garantia de revisão do contexto completo. Não há migração ou segundo motor de estados.
+
+Partes e confirmação: conserva-se a precedência já existente de proponente quando a pessoa representa ambas as origens; não foi inventado selector de parte, nova alçada ou regra de pessoas distintas. A interface identifica a parte efectiva e distingue actualizar uma confirmação própria de confirmar pela primeira vez. Apenas entradas com as chaves proponent e candidate e actor positivo contam para a confirmação bilateral; uma chave desconhecida não constitui segunda parte. A representação actual é exigida para novas intervenções, sem invalidar retroactivamente decisões históricas de quem entretanto saiu. A assinatura jurídica permanece not_verified; a confirmação interna não prova assinatura ou validade legal.
+
+Histórico e integridade: cada comando guarda no evento existente o estado anterior e o aplicado, versão, motivo, parte e contexto real. Registar nova versão e renovar conservam o instrumento completo anterior, incluindo campos legados, sem inserir recursivamente a lista anterior dentro de cada entrada; confirmações são reiniciadas nos mesmos pontos do percurso. Estruturas legadas de histórico ou confirmações incompatíveis recebem 409 sem escrita, em vez de erro 500. Concluir mantém a exigência existente de marcos terminados. Estes snapshots não constituem ainda um leitor paginado de histórico de acordos.
+
+Preparação e recuperação: o comando fica congelado; Recuperar a mesma acção repete bytes e chave originais, conservando alterações feitas depois do envio. Confirmar não grava título/condições ainda não registados. Acknowledgement exige actor, sala, chave, acção e versão próprios; na versão exacta exige instrumento e carimbo de confirmação compatíveis. A ausência desses metadados não apaga a preparação. Uma decisão posterior ou alteração posterior da proposta/candidatura reconhece o comando antigo mas exige comparação antes de outra escrita. O contexto intermédio não reaplica automaticamente valores antigos sobre a decisão de outra pessoa.
+
+Acesso e separação: recibos da sala projectam apenas chave/acção/versão/estado/parte das tentativas do próprio actor com escrita efectiva, sem envelopes privados ou hashes. O DTO da proposta remove _creation_hash mantendo o tipo JSON string anterior. Recusa de acesso suspende recuperação até consulta autorizada; outra conta recebe editor próprio. Callbacks de tentativa abandonada ou editor desmontado não apagam preparação nova. Antes de abandonar uma tentativa incerta e criar outra, a consulta actual e a adopção explícita são exigidas. O aviso de saída continua único para os formulários da sala.
+
+Provas: 12 novos Feature cobrem replay terminal/sem efeitos, alteração de contexto, registo seguido de confirmação, nonce/conteúdo, partes forjadas, confirmação bilateral, versões completas e renovação, marcos, representação revogada/viewer, metadados por actor e salas distintas, entradas inválidas, estrutura legada e compatibilidade antiga. Há 12 casos novos de frontend, além dos 16 anteriores do formulário de sala, com 28 focados sem somar repetições; os dois casos antigos de sucesso passaram a modelar o recibo real de comando. Os testes executam componentes/hooks transpilados; não são aceitação visual num navegador. Não foi executada nova corrida PostgreSQL, e as provas concorrentes anteriores conservam o seu âmbito.
+
+Isolamento e saldo: base descartável partnership_agreements_20261103_test em 127.0.0.1:55441, role investmoz_test; 45 tabelas verificadas vazias após processo terminal, com aquisição do lock e conferência de owner/RLS. Preservados 73 recibos e 224 provas anteriores. AUD-PART-01 e auditoria integral continuam parciais. Continuam pendentes variantes de papéis/consumidores, leitura de instrumentos legados sem mapa de confirmações, leitor de histórico do acordo, síntese no detalhe, aceitação visual e disponibilização. A próxima verificação deve começar pela leitura legada, distinta da recusa de escritas malformadas já testada. Preparação mantém-se em memória, sem promessa de persistência após fechar/recarregar ou autenticar. Sem migrações novas, instalação/escrita no activo, pessoas reais ou mensagens externas.
+
+Diagnóstico de ambiente: uma primeira execução com filtro textual Partnership seleccionou 123 casos, incluindo anexos independentes fora dos 11 ficheiros da suite específica. Terminou com 122 casos passados e um erro de fixture por imagecreatetruecolor indisponível. Esse resultado foi conservado como diagnóstico, sem o apresentar como regressão limpa. A suite específica foi repetida pelos 11 caminhos explícitos (121 casos). O caso de anexos que falhou foi executado adicionalmente com a extensão GD já disponível carregada apenas nesse processo, sem alterar php.ini global, fabricar scan ou dispensar ClamD. O seu JUnit conserva o resultado e as asserções; não se soma esse caso antigo aos 12 novos Feature deste incremento. A verificação final das 45 tabelas ocorre depois de ambos os processos terminarem.
+
+### 03/11/2026 — AUD-PART-01: leitura legada e histórico privado dos acordos
+
+[PARTNERSHIP-AGREEMENT-HISTORY-20261103] Leitura de instrumentos antigos sem falha/confirmações inventadas e histórico privado ligado à sala, com snapshots antes/depois, âmbitos actuais/históricos separados e paginação cifrada por conta/relação/finalidade. 132 Feature/1009 asserções (11 novos),1525 frontend (11 novos),39 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;74 recibos e237 provas preservados. Recibo partnership_agreement_history_increment_20261103; parcial, sem entrega activa.
+
+Origem: AUD-PART-01, orientação de 23/10 e saldo PARTNERSHIP-AGREEMENTS-20261103. O incremento anterior capturou instrumentos antes/depois dos comandos mas não tinha leitor. Foi reproduzido GET404 no histórico e falha real do componente/hook ao abrir uma sala cujo instrumento antigo não tinha confirmations. Os diagnósticos são preservados. Um teste intermédio de HTML procurava uma barra não escapada no JSON Inertia; foi substituído por assertInertia sobre o componente e room_id efectivos, sem alterar o produto para satisfazer uma representação textual.
+
+Leitura actual: parser e componente partilhados tratam dados desconhecidos como desconhecidos. Mapa ausente/null não se torna Pendentes; mapa malformado mantém aviso e o registo original. O array vazio guardado pelo serviço equivale ao mapa vazio compatível; listas não vazias não são convertidas em confirmações. Carimbos com actor inválido são incompletos e não activam o rótulo de actualização de confirmação. Referências adicionais não substituem uma parte e são assinaladas. Títulos, condições, datas e motivos de tipos não reconhecidos não são inseridos como filhos React; valores vazios conhecidos distinguem-se de valores não registados. A leitura não limpa nem regrava esses dados.
+
+Percurso: ligação Consultar histórico do acordo na sala, GET privado JSON/Inertia em /parcerias/salas/{id}/historico e página agreement-history. O percurso usa autenticação, instalação, resposta privada/no-store e histórico Inertia cifrado existentes. A página é só de consulta, mostra antes/depois, acção, motivo, autor e data, parte que confirmou e versões guardadas da proposta/candidatura. Os nomes de pessoas provêm do cadastro actual e são identificados como tal. Não volta a executar comandos, não recalcula, não envia avisos e não certifica assinatura jurídica.
+
+Acesso actual e histórico: a entrada exige o mesmo acesso efectivo de leitura da sala, incluindo viewer de organização, sem excepção de moderação. Os eventos são filtrados por parceria, tipo exacto e sala. O contexto privado de aviso já capturado identifica as duas origens, sala e versão do contrato de contexto; IDs e âmbitos têm de ser consistentes. Os responsáveis actuais não herdam por essa condição uma representação antiga. Sem contexto conhecido, o evento é reservado e não devolve actor, motivo ou conteúdo. Contexto conhecido mas sem representação actual da origem histórica também é reservado. Mantém-se a possibilidade de ler o âmbito de qualquer das duas partes autorizadas; não foi inventada competência funcional nova.
+
+Instrumentos: cada snapshot exige a sala correcta, versão positiva e estado identificado. O instrumento tem ainda âmbito próprio em recorded_context; proposta/candidatura e origens guardadas têm de ser reconhecidas. Um representante novo pode ler a decisão produzida na sua organização actual e continuar sem acesso ao instrumento de outra representação anterior. A contraparte com autoridade histórica conserva a sua leitura. Instrumentos legados sem origem registada são marcados scope_unknown; snapshots antigos inexistentes são not_recorded. Não se reconstitui conteúdo a partir do acordo actual ou de previous_versions, nem se atribui uma origem retrospectiva. Ausência de dados não é uma decisão de invalidade jurídica.
+
+Projecção: apenas título, condições, estado de assinatura e confirmações nomeadas saem do instrumento. IDs positivos de autores recebem o nome actual; motivo/data são valores efectivamente guardados quando têm tipo reconhecido. Campos adicionais, listas recursivas de versões, envelopes, hashes e nonces não são devolvidos. Referências desconhecidas são representadas por um indicador sem copiar chaves ou valores privados. O âmbito usado para autorizar não é exposto como um novo cadastro. Snapshots de outra sala são ocultados mesmo dentro de um evento de uma sala autorizada.
+
+Paginação: máximo de10 entradas, com consulta de11 para reconhecer continuação. A ordem usa a sequência estável do evento. O cursor é cifrado e vinculado à finalidade acordo, conta, sala, candidatura e parceria, com fronteira inteira positiva; referências de outro percurso/actor/relação ou malformadas são422. A autoridade é conferida em cada página antes de descifrar o cursor. Inserir um evento mais recente não repete os eventos da página anterior. Páginas antigas e retorno às mais recentes têm navegação explícita.
+
+Provas:11 novos Feature exercitam leitura sem escrita/avisos, ambas as partes após cancelamento, página Inertia, recusa de terceiro/moderador, snapshots congelados e projecção, paginação com inserção, cursor adulterado, viewer e mudança de organizações/revogação, contexto desconhecido/inconsistente, eventos legados, IDs de snapshot alheio, confirmação malformada e isolamento entre salas.11 casos novos frontend exercitam a falha antiga, array vazio, tipos inválidos, partes incompletas, leitura antes/depois, reservas/ausência, paginação, lista vazia, escape HTML e ligação com o aviso de saída existente.39 focados incluem os28 anteriores; não se somam casos repetidos. Componentes/hooks transpilados e React SSR são provas de comportamento, sem os apresentar como aceitação visual em navegador.
+
+Isolamento e saldo: base descartável partnership_agreement_history_20261103_test em127.0.0.1:55441, role investmoz_test,45 tabelas vazias verificadas depois do processo terminal e com aquisição do lock/owner/RLS. Sem nova migração, escrita ou instalação no activo, pessoas reais ou mensagens externas. Preservados74 recibos e237 provas aceites, incluindo o caso adicional de scan com GD do incremento anterior, sem o repetir ou aumentar o âmbito dessa prova. Sem nova corrida concorrente. AUD-PART-01 e auditoria integral continuam parciais. Restam variantes de papéis/consumidores, síntese do histórico no detalhe, aceitação visual e disponibilização; conteúdo antigo que não foi capturado não é fabricado. Preparação mantém-se em memória e não tem por este incremento garantia após fechar/recarregar ou autenticar.
+
+Próxima verificação concreta: confrontar os restantes consumidores com esta projecção, começando pelo DTO actual da sala, que ainda descodifica o instrumento completo e pode transportar previous_versions e recorded_context. O leitor novo filtra esses dados, mas esta prova não demonstra filtragem transversal dos outros endpoints. Reproduzir o caso com mudança de organização e preservar o instrumento actual e o histórico no servidor ao corrigir a exposição de versões anteriores. Esta pendência não requer inventar uma transferência automática de autoridade.
+
+### 03/11/2026 — AUD-PART-01: histórico do acordo fora da resposta corrente da sala
+
+[PARTNERSHIP-AGREEMENT-PROJECTION-20261103] Sala corrente projecta título, condições, assinatura guardada e confirmações reconhecidas; versões anteriores e metadados privados ficam no servidor e no leitor histórico autorizado. 141 Feature/1146 asserções (9 novos),39 frontend focados;PHPStan/Pint aprovados e QA45 vazias/owner/RLS/lock conferidos. Frontend1525/tipos/lint/build anteriores reutilizados com fontes cliente e artefactos conferidos.75 recibos e248 provas anteriores preservados. Recibo partnership_agreement_projection_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-PART-01 e pendência concreta PARTNERSHIP-AGREEMENT-HISTORY-20261103. Reproduzida a leitura por viewer da nova organização depois de uma mudança A→B e de registar novo instrumento: o GET corrente ainda devolvia previous_versions com o instrumento da origem anterior. O primeiro teste falhou na ausência esperada desse campo. A falha original foi preservada. A primeira ronda alargada corrigiu dois problemas de fixture (alias Assert removido quando ainda não era usado e expectativa de um instrumento reservado dentro de um evento inteiramente reservado), sem alterar o produto para tornar essas expectativas verdadeiras.
+
+Inventário de consumidores: pesquisa por partnership_rooms nos controladores e serviços encontrou PartnershipExchangeController, PartnershipExchange, PartnershipAgreements, PartnershipCandidacies, PartnershipMilestones, PartnershipRoomUploads e PartnershipNotifications. No controlador, painel e detalhe usam apenas referência/ligação à sala; o método room era a saída do agregado completo. O leitor PartnershipAgreementHistory é a saída dedicada de snapshots. As operações internas continuam a trabalhar sobre o agregado guardado e não recebem a projecção de leitura como fonte de escrita. Não se apresenta esta pesquisa literal como auditoria de todos os módulos do portal.
+
+Correcção: PartnershipAgreementProjection fornece uma única formatação para os campos reconhecidos, usada depois da autorização pelos dois leitores. A sala corrente conserva título, condições, estado de assinatura e confirmações nomeadas com actor positivo/data/motivo quando reconhecidos. Não devolve previous_versions, recorded_context, extensões privadas, nomes não autorizados de chaves adicionais ou actor_name introduzido num instrumento legado. No histórico autorizado, os nomes continuam a provir do cadastro actual, através das referências efectivamente guardadas. Cada leitor conserva a sua verificação de autoridade: actual da sala para o instrumento corrente; actual e histórica para snapshots. A formatação não é uma concessão de acesso.
+
+Legado e conservação: omissão e null de confirmações mantêm-se distintos do mapa vazio conhecido; array vazio compatível é representado por objecto vazio. Estruturas não reconhecidas recebem marcador e não ecoam o seu conteúdo opaco. Carimbos incompletos continuam identificados, e chaves adicionais produzem só indicador. Nenhum GET limpa a base, elimina versões ou altera decisões. Acordo actual continua acessível aos participantes actuais pelo percurso já existente; não se inventa transferência de autoridade histórica, nova alçada ou bloqueio de escrita. O histórico completo, contextos e campos legados permanecem nos agregados e nos snapshots de auditoria.
+
+Operações e recuperação: registo novo e replay mantêm as regras, versões, nonces e efeitos existentes. A projecção não é enviada de volta para substituir o agregado; os formulários já enviam campos próprios do comando. Os testes conferem preservação do conteúdo privado em previous_versions e nos snapshots previous/applied após registar, ler e repetir. Repetir o comando não acrescenta evento, auditoria ou aviso. O estado de assinatura continua not_verified. A consulta de versões anteriores usa /parcerias/salas/{id}/historico e as guardas já implementadas.
+
+Provas:9 novos Feature cobrem mudança de organização e contraparte histórica, campos correntes e confirmações das duas partes, metadados próprios, JSON e Inertia/private-no-store, formas legadas/marcadores, referências incompletas e privadas, preservação do agregado/auditoria e replay, viewer/representação revogada/terceiro/moderação e os consumidores painel/detalhe. Os39 casos frontend focados foram executados sem novos testes cliente. Como não houve alteração em código cliente ou rotas, reutilizam-se as1525 provas frontend e tipos/lint/build do incremento anterior; as fontes cliente das bases anteriores são conferidas e o manifesto, entradas compiladas e dependências da sala/histórico têm hashes preservados. Não se declara nova ronda integral frontend, nova compilação, aceitação visual ou corrida concorrente.
+
+Isolamento e saldo: base partnership_agreement_projection_20261103_test em127.0.0.1:55441/role investmoz_test,45 tabelas vazias depois do processo terminal com lock/owner/RLS conferidos.75 recibos e248 provas anteriores preservados. Sem migração, escrita/instalação no activo, pessoas reais ou mensagens externas. AUD-PART-01 e auditoria integral continuam parciais; restam variantes dos outros percursos/consumidores, síntese no detalhe, visual e disponibilização. A exposição de versões anteriores no DTO corrente registada no incremento anterior fica reconciliada por esta prova; o registo anterior não é apagado. Preparação mantém-se em memória; conteúdo histórico não capturado não é fabricado.
+
+Próxima acção concreta: o detalhe da parceria ainda devolve history com event_type, actor_id e occurred_at sem limite, e detail.tsx apresenta esses códigos/IDs no bloco Histórico e decisões. Reutilizar o leitor de publicação para uma síntese limitada, com as mesmas guardas históricas e linguagem do processo, mantendo o acesso ao histórico completo. Conferir as variantes de dono, nova representação, moderação e consulta pública; não trocar a síntese por uma nova concessão de leitura.
+
+### 03/11/2026 — AUD-PART-01: síntese do histórico no detalhe da parceria
+
+[PARTNERSHIP-PUBLICATION-SUMMARY-20261103] Síntese de até cinco alterações recentes no detalhe, com autoridade do leitor histórico, metadados reservados ocultos e linguagem partilhada com o histórico completo. 149 Feature/1247 asserções (8 novos),1533 frontend (8 novos),55 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;76 recibos e254 provas anteriores preservados. Recibo partnership_publication_summary_increment_20261103; parcial, sem entrega activa.
+
+Origem: AUD-PART-01, orientação de23/10 e próxima acção PARTNERSHIP-AGREEMENT-PROJECTION-20261103. O detalhe devolvia todos os metadados de eventos de publicação sem limite, com actor_id/event_type/occurred_at, e a interface mostrava IDs/códigos técnicos. Um Feature reproduziu a presença do campo bruto history e um caso do componente/hook reproduziu a falta de linguagem do processo. Esses resultados originais foram preservados. A nova propriedade historySummary substitui a lista bruta; não se mantém uma segunda cópia do histórico no detalhe.
+
+Servidor: summary reutiliza context, events e entry do leitor PartnershipPublicationHistory. Há uma só autoridade de leitura actual e histórica e uma só interpretação dos snapshots; não se deduzem decisões de um código de evento. A consulta é limitada a seis eventos para apresentar no máximo cinco e saber se existem anteriores, na ordem da sequência estável. A página completa conserva dez entradas e cursor cifrado por finalidade/conta/publicação. O endereço do histórico é derivado no servidor. Cinco é uma escolha técnica de apresentação, não uma regra organizacional ou nova alçada.
+
+Projecção: saem apenas versão, reserva do conteúdo, acção reconhecida, nome actual do actor, data, motivo e estados antes/depois quando o respectivo snapshot está disponível. Não saem actor_id, event_type, envelopes, snapshots, origem privada, hashes ou nonces. Se um dos snapshots está reservado, o seu estado não é copiado para a síntese. Um evento inteiramente reservado não expõe actor/data/motivo/acção. Uma nova representação não recebe metadados antigos por ser responsável actual. A moderação mantém exactamente a leitura histórica que o leitor já lhe concedia; não ganha por este incremento acesso a salas privadas.
+
+Percurso e linguagem: detalhe apresenta secção de até cinco alterações, com nomes, motivos, estados e rótulos do processo. Os rótulos das acções são partilhados com a página completa. O texto identifica nomes como cadastro actual e os dados como valores guardados. Registos vazios, metadados ausentes, estados/acções desconhecidos e conteúdo reservado têm indicação própria, sem inventar aprovação, data ou autor. Há uma única ligação para o histórico completo e indicação de alterações anteriores. A secção não cria formulários, decisões ou nova tramitação. Permanece oculta em consultas públicas/candidatas sem a autoridade correspondente, mesmo se a interface receber uma síntese desactualizada.
+
+Preparação: actualizações da síntese não adoptam versões da proposta nem apagam um motivo preparado para publicação. O percurso mantém o aviso de saída já partilhado com candidaturas; consultar histórico não acrescenta um segundo aviso nem envia comandos. Motivos e nomes são escapados como texto pelo React. Identificadores técnicos não são usados como texto de substituição quando falta informação. A leitura não altera versões, eventos, notificações, auditoria ou estado comercial.
+
+Contrato de lista: a primeira análise estática identificou que Collection::values()->all() não comprovava o contrato list no tipo devolvido. Após consultar https://phpstan.org/error-identifiers/return.type, a construção foi tornada explícita com array_values, assegurando os índices sequenciais do JSON. Não se alargou o tipo, não se acrescentaram casts para esconder o erro nem supressões/baselines. A análise final passou com o contrato de lista preservado.
+
+Provas:8 novos Feature exercitam limite/ordem e ligação ao histórico completo, equivalência de metadados com o leitor autorizado, nova organização/viewer/revogação, moderação, consulta pública/candidata, âmbito antigo desconhecido, ausência de eventos de publicação e HTTP/Inertia sem efeitos.8 novos frontend exercitam linguagem, reserva dos dados, ausência para público, lista vazia/limite/uma só ligação, valores desconhecidos, preparação/aviso de saída, escape React e perda de contexto de leitura.55 focados incluem os47 anteriores, sem somar repetições. A ronda integral frontend, tipos/lint e compilação são novas neste incremento; testes de componentes/hooks e React SSR não são apresentados como aceitação visual num navegador. Não foi executada nova corrida concorrente.
+
+Continuidade dos artefactos: a compilação nova substitui o manifesto e os bundles que o incremento anterior apenas reutilizava. O recibo anterior e os seus hashes permanecem preservados como inventário histórico; o recibo actual identifica o estado dos treze artefactos anteriores após a compilação, sem fingir que hashes antigos de bundles continuam a ser a versão corrente. As provas anteriores de testes não são reescritas. As páginas concluídas continuam conferidas no manifesto actual.
+
+Isolamento e saldo: base partnership_publication_summary_20261103_test em127.0.0.1:55441/role investmoz_test,45 tabelas vazias verificadas depois do processo terminal, com lock/owner/RLS.76 recibos e254 provas anteriores preservados. Sem migração nova, instalação/escrita no activo, pessoas reais ou mensagens externas. AUD-PART-01 e auditoria integral continuam parciais: faltam variantes dos outros percursos, aceitação visual e disponibilização. Preparação continua em memória e não se fabrica conteúdo histórico ausente. A pendência do detalhe identificada no incremento anterior fica reconciliada por esta implementação, sem apagar a prova anterior.
+
+Próxima acção transversal: confrontar AUD-CRM-01, AUD-DESK-01/02 e os restantes eixos da matriz com os recibos e código actuais, antes de escolher o próximo desenvolvimento. A leitura inicial da matriz ainda apresenta lacunas históricas sobre encerramento de dossier e estado Implementado com falha no CRM; conferir o saldo actual e as decisões do dono, sem repetir provas aceites nem declarar um módulo concluído pela mera existência de testes. A auditoria permanece com o âmbito integral do portal.
+
+Reconciliação do teste existente: a primeira ronda integral terminou com148 casos passados e um erro no teste de privacidade que ainda procurava history.0. O teste passou a exigir ausência do campo bruto, ausência de payload/event_type/actor_id/command_hash na síntese e síntese null para o leitor público, conservando as verificações de chaves privadas por actor. Trata-se da actualização do contrato testado, não de uma nova concessão no produto. Esse caso anterior não é contado entre os8 novos Feature. A ronda integral foi repetida; a falha intermédia e o ajuste de formatação ficam como diagnóstico, sem os apresentar como resultado final.
+
+Actualizações parciais: a verificação final encontrou que Comparar a proposta e Comparar a candidatura ainda não pediam historySummary. O teste passou a executar os dois hooks reais, em vez de apenas fornecer metadados numa renderização; reproduziu falha antes da correcção. Os dois pedidos incluem agora a síntese, e a comparação de candidatura inclui os indicadores/capacidades de publicação actuais para não conservar autoridade visual desactualizada. A preparação do motivo e o único aviso de saída permanecem. A ronda frontend integral/tipos/lint/build foi repetida após esta alteração cliente; a primeira ronda é diagnóstico, sem somar casos repetidos nem alterar a prova149 Feature do servidor, cujo código não mudou.
+
+### 03/11/2026 — AUD-CRM-01: recuperação da criação de tarefas e conservação da preparação
+
+[CRM-TASK-CREATION-20261103] Recuperação da criação de tarefas CRM sem duplicar a tarefa/eventos de negócio e sem apagar edições feitas durante o envio. 77 Feature/877 asserções (10 novos), confirmação final sobreposta10/79;1545 frontend (12 novos),41 focados. PHPStan/Pint/tipos/formato/lint/build aprovados. QA45 vazias com owner/RLS/lock conferidos; índice único novo somente em QA. 77 recibos/266 provas anteriores preservados. Recibo crm_task_creation_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-CRM-01, regras existentes de responsável/próxima acção e orientação de23/10 sobre conservar alterações deliberadas. Um Feature reproduziu duas tarefas após repetir o mesmo envio; um caso do componente real reproduziu o apagamento do título alterado enquanto o pedido estava em curso. As provas originais permanecem. A correcção não muda a regra de conversão, consentimento, qualificação ou titularidade do dossier.
+
+Servidor: CrmTaskCreation usa a autorização efectiva de gestão existente, valida o identificador da tentativa e o conteúdo canónico, bloqueia o lead antes de gravar e preserva PortalAudit. O recibo imutável adicional reutiliza audit_events com origem própria e não guarda título/prazo/texto livre: apenas lead, chave, resumo criptográfico e versão. Repetir a mesma tentativa pela mesma conta/lead confirma o resultado antes de reavaliar prazo/assignee transitórios; dados diferentes com a mesma chave dão409. Outra conta/lead tem âmbito próprio. O índice parcial único reforça a identidade; não foi instalado no activo. Chamadores antigos sem chave conservam o contrato anterior e não recebem por inferência garantia de recuperação.
+
+A leitura devolve apenas recibos da conta e lead actuais, sem hashes ou envelopes de auditoria. Uma tarefa concluída, alterada ou removida não é restaurada nem recriada pelo reenvio. A autorização HTTP/MFA e a autorização de gestão continuam aplicáveis; perder acesso não permite confirmar por uma chave antiga. A auditoria normal de acesso permanece: a primeira asserção intermédia confundia esse evento com nova gravação de negócio, foi delimitada aos eventos das tarefas e o diagnóstico foi preservado.
+
+Formulário: congela os dados enviados e o identificador, converte o prazo local para UTC uma vez e recupera exactamente esse pedido após falha de rede/500/interrupção. Os campos continuam a aceitar edições posteriores, conservadas por geração ao confirmar o resultado. A confirmação é conferida por conta/lead/chave/versão/tarefa; uma leitura sem confirmação mantém a tentativa e não dispara nova criação. Uma leitura confirmada evita outro POST. Validação permite corrigir os campos sem consumir a tentativa. Atribuição não editada acompanha o dono actualizado; uma escolha deliberada permanece, incluindo opção anterior indisponível. Um aviso de saída cobre a preparação e a tentativa incerta. O resumo da recuperação mostra os dados enviados, prazo em Maputo e nome do responsável quando disponível.
+
+Actualização parcial: o novo formulário e o editor de lead/tarefa pedem lead, owners, taskCreation e nextAction juntos. As fixtures dos testes de fila/dossier que importam apenas TaskRow passaram a reconhecer o novo componente sem alterar as verificações de suspensão/âncora. A primeira ronda integral ainda usou essas fixtures antigas e permanece como diagnóstico; a ronda final é a prova corrente. Correcções de formatação e o acesso explícito ao atributo version_no foram verificados sem supressões de análise estática.
+
+Validação:77 Feature/877 cobrem CRM, conversão, próxima acção, versões, fila, dossiers e orientação;10/79 posteriores à última correcção de servidor estão sobrepostos, não somados como novos. 1545 casos frontend integrais e41 focados, incluindo12 novos, tipos/formato/lint/build.45 tabelas de QA vazias após término dos processos e obtenção do lock, com identidade, owner e RLS/FORCE conferidos. A migração nova é apenas índice e foi conferida em QA. As provas anteriores de concorrência são preservadas; este incremento não declara uma nova prova multiprocesso de criação.
+
+Estado: reconciliado AUD-CRM-01 de «Implementado com falha» para «Implementado parcialmente», conservando o estado anterior nesta explicação e todas as provas. As falhas concretas de próximas acções/versões/fila já corrigidas não são repetidas como trabalho inexistente; continuam os outros consumidores/perfis, recuperação durável após fecho/reautenticação, apresentação visual e disponibilização. A preparação actual permanece em memória, isolada por lead/conta; não se afirma persistência após fechar a página. Os bundles anteriores são fingerprints históricos substituídos pela compilação corrente. A auditoria integral do portal mantém-se em curso.
+
+### 03/11/2026 — AUD-CRM-01: preparação recuperável de nova tarefa, por conta e lead
+
+[CRM-TASK-PREPARATION-20261103] Preparação de nova tarefa CRM cifrada, por conta/lead, com gravação automática, comparação antes de adoptar e retoma do envio original sem duplicar. 48 Feature/369 asserções antes da última normalização;14/123 específicos finais sobrepostos em13 casos (14 novos no total).57 frontend actuais (16 novos,41 sobrepostos com a ronda integral anterior1545, que não foi repetida). PHPStan/Pint/tipos/formato/lint/build aprovados. QA46 vazias/owner/RLS/lock;1 tabela nova somente em QA.78 recibos/278 provas anteriores preservados. Recibo crm_task_preparation_increment_20261103; parcial, sem instalação/escritas no activo.
+
+Origem: AUD-CRM-01, saldo CRM-TASK-CREATION-20261103 e orientação de23/10 para conservar escolhas ao actualizar/autenticar. A limitação comprovada era a preparação exclusivamente em memória. A continuidade agora acrescentada aplica-se ao formulário de nova tarefa CRM; não é declarada nos restantes editores CRM, parcerias ou em todos os formulários do portal. Não se altera a regra de qualificação, prazo futuro, responsável, conversão ou titularidade do dossier.
+
+Persistência: a nova tabela crm_task_preparations guarda uma preparação por conta/lead, versão, identificador/resumo da gravação e snapshot cifrado com Crypt. Segue as convenções dos checkpoints do Balcão e das declarações de formação; as respectivas tabelas têm vínculos/kinds próprios e não foram reutilizadas para dados de CRM. A gravação usa o mesmo bloqueio do lead dos outros comandos, recusa versões ultrapassadas, repete a mesma operação sem outra escrita e mantém auditoria mínima (versão, sem texto privado). O downgrade recusa eliminar preparações existentes. O texto parcial e os campos vazios são preservados antes da normalização HTTP; a criação da tarefa conserva a validação de negócio existente.
+
+Âmbito efectivo: o endpoint está no grupo administrativo existente com autenticação, email verificado, administração no âmbito e protecções globais de sessão/perfil; a recuperação consulta apenas a conta e o lead actuais. A mudança de revisão de acesso invalida a sessão antiga sem substituir a preparação. Os ensaios usam contas sintéticas com MFA, mas isso não constitui prova de uma obrigação universal adicional de MFA no CRM. Nenhum perfil, alçada ou canal novo foi criado. A preparação não é criação/aprovação de tarefa nem alteração de lead, documento ou dossier.
+
+Interface: alterações são guardadas após800ms e a tentativa congelada é confirmada no servidor antes de enviar a criação. Uma gravação sem confirmação conserva o mesmo identificador para repetição. O envio de negócio continua a usar a chave idempotente já implementada. A recuperação mostra valores desta página/guardados e exige adopção explícita, conserva alterações posteriores e solicita nova escolha se o utilizador alterou um campo depois de escolher o guardado. Um envio local distinto já enviado tem de ser confirmado antes de adoptar outro; a recuperação não dispara criação. Um recibo de criação já existente confirma o resultado e limpa apenas campos não alterados entretanto, mantendo a próxima preparação.
+
+Continuidade e falhas: alterações durante o envio também podem ser guardadas com o comando original; callbacks de outra conta/página não enviam tarefas. Preparação totalmente confirmada deixa de repetir o aviso de saída; alterações ainda sem confirmação mantêm o único aviso. Falha de gravação/autenticação é explicada e conserva a página. Sem a tabela, a criação manual anterior permanece; dados cifrados ilegíveis são sinalizados e preservados, com continuação explícita apenas nesta página. Não se promete recuperar alterações ainda não confirmadas no servidor após perda da página, nem acesso a dados de outra conta. Não se usa armazenamento local com dados de outros actores.
+
+Correcções delimitadas pelos testes: o servidor aceitava contadores inteiros escritos como texto e UUIDs em maiúsculas, mas a projecção podia impedir a retoma; um Feature reproduziu o caso e a normalização devolve números/chaves canónicas sem mudar o texto do utilizador. Outro caso reproduziu alteração do instante na retoma noutro fuso com hora local repetida, incluindo perda de segundos. O formulário mantém agora o instante UTC recuperado até o prazo ser deliberadamente editado; a comparação identifica a hora de Maputo. Ambos os resultados originais permanecem como provas.
+
+Validação:48 Feature/369 antes da última normalização;14/123 finais exercitam todos os14 novos casos, com13 sobrepostos, sem somar rondas como casos novos.57 testes frontend actuais cobrem os16 novos e os41 anteriores dos consumidores CRM/fila/dossier afectados. A ronda integral anterior1545 permanece histórica e não é apresentada como uma execução integral nova. O novo módulo só é importado pelo formulário CRM e pelo detalhe correspondente; tipos globais e compilação foram repetidos. PHPStan nível7 sem supressões, Pint e formato/lint aprovados;46 tabelas QA vazias após terminação e lock, owner/RLS/FORCE conferidos. Nenhuma migração ou escrita no activo, mensagem externa, aceitação visual ou nova prova multiprocesso é inferida.
+
+Preparação vazia: um checkpoint já concluído e coincidente com os valores da página não volta a exigir comparação apenas por contadores técnicos. O caso actual é exercitado nos16 novos testes frontend; escolhas de responsável já guardadas continuam identificadas sem modificar dados de negócio.
+
+Saldo: o formulário de nova tarefa tem agora retoma confirmada por conta/lead e comparação; não o repetir como exclusivamente em memória. Continuam pendentes os restantes formulários/consumidores, variantes por perfil, apresentação visual e disponibilização com a migração no destino. O núcleo manual não depende da nova instalação. AUD-CRM-01 e a auditoria integral permanecem parciais. As provas anteriores e fingerprints compilados ficam preservados como históricos, substituídos pela compilação corrente quando aplicável.
+
+### 03/11/2026 — AUD-EDU-01/03: acompanhamento interno e revisão contextual de declarações
+
+[EDUCATION-WORK-QUEUE-20261103] Painel interno dos gestores com acompanhamento próprio, revisão independente e detalhe contextual. Revisão fixa a versão analisada, exige comparação se mudou, conserva edições posteriores e repete a mesma tentativa sem nova decisão. Fundamentos anteriores/novos preservados em snapshot cifrado e consulta privada paginada. 30 Feature/629 asserções (16 novos,14 anteriores);22 frontend (17 novos,cinco anteriores). PHPStan/Pint/tipos/formato/lint/build aprovados;54 tabelas QA vazias, owner/RLS/lock conferidos.79 recibos/289 provas anteriores preservados. Recibo education_work_queue_increment_20261103. Parcial local, sem migração/escritas no activo.
+
+Origem: AUD-EDU-01/03, D-EDU-02/D-EDU-06/D-EDU-08 e as competências internas já existentes em docs/investmoz/education/decisions.md. Os rascunhos privados e os dez cenários de concorrência já aceites em02/11 não foram reimplementados. A orientação de23/10 exige preservar contexto e apresentar a próxima acção aplicável. O proprietário respondeu «nao existe» à pergunta sobre um cadastro/documento aprovado de representação e consentimento para estudantes, instituições formadoras e empregadores. Esta resposta é uma ausência de fonte, não uma autorização para inventar mandatos, consentimento, perfis externos ou dados individuais de estudantes. Esses três percursos continuam pendentes; o gestor interno já autorizado prossegue.
+
+Painel: acrescentados filtros Todos, Submetidas por mim e Disponíveis para revisão independente, com indicadores pessoais de declarações por tipo/estado/expiração e rascunhos próprios ainda abertos. Quantidades de trabalhadores e vagas formativas não são somadas como declarações. Rascunhos submetidos deixam de contar como abertos, sem duplicar a declaração derivada. As declarações anteriores aos rascunhos também entram no acompanhamento. O âmbito pessoal não reduz as fontes territoriais dos catálogos. Indicadores gerais e percursos de cadastro, procura/oferta, propostas e rascunhos mantidos. A lista disponível para revisão é consulta; não cria atribuições, tarefas, prazos ou concessões.
+
+Detalhe privado: nova rota /management/education/{demands|capacities}/{id}, com filtros/páginas no regresso, fonte, período, validade, unidades, empregador aplicável e referências do cadastro actual. Nomes actuais não são apresentados como snapshots históricos. Cache no-store e histórico Inertia cifrado; mesmo acesso administrativo interno, verificação de email e exclusão do auditor. O autor não recebe formulário de auto-revisão; fontes expiradas continuam consultáveis. O servidor conserva recusa de auto-revisão, expiração e versão obsoleta.
+
+Causa reproduzida: dois testes de componente falharam no formulário anterior — o autor recebia a acção e uma decisão preparada podia enviar a versão nova dos props sem comparação. A prova original mostra comportamento do componente; não demonstra uma decisão indevida aceite pelo servidor ou aceitação visual. O novo formulário fixa a versão e valores analisados, compara campos/referências e só adopta a versão actual por acção explícita. Uma tentativa incerta conserva chave, decisão, motivo e versão originais; callbacks tardios de outra página/conta não apagam a preparação. Confirmação limpa apenas os valores enviados que não foram editados depois. Um único aviso de saída protege a preparação em memória.
+
+Repetição e autoridade: bloqueio do registo e recibo append-only por actor/tipo/registo/chave, com resumo canónico. Mesma tentativa confirmada devolve o resultado sem outra revisão/versão; chave reutilizada com outro conteúdo e nova tentativa obsoleta são recusadas. O acesso actual é sempre exigido. A consulta devolve somente chaves/versões do actor actual para confirmar resultado; não expõe resumos ou o envelope cifrado. Repetir recibo antigo após decisão posterior ou expiração não reescreve o estado nem prolonga a validade. O contrato antigo sem chave continua sujeito a conflito de versão e também preserva o fundamento.
+
+Preservação: cada nova revisão acrescenta evento restrito com snapshot Crypt do objecto revisto, estado/motivo/revisor imediatamente anteriores e novos. A consulta privada mostra fundamentos disponíveis, versão, data e nome actual do revisor, com paginação estável por versão. Fundamentos anteriores à implementação que nunca foram armazenados não são reconstruídos. Envelope ilegível conserva metadados/original e explica indisponibilidade. A auditoria permanece append-only; um primeiro ensaio que tentou alterar um evento foi recusado pela guarda existente. O teste foi corrigido para inserir uma amostra sintética separada, sem desactivar a guarda.
+
+Validação: 30 Feature/629 asserções finais no conjunto Educação afectado (16 novos e14 anteriores).22 frontend actuais (13 de revisão,quatro de painel e os cinco de rascunhos existentes). A ronda integral1545 anterior permanece histórica, sem ser apresentada como execução actual. PHPStan nível7 sem supressões, Pint, tipos globais, formato/lint de sete fontes e build aprovados. O contrato do serviço de histórico passou a devolver dados paginados serializáveis, evitando expor um paginator mutável com parametrização incompatível.54 tabelas vazias verificadas após fim dos processos e aquisição do lock, proprietário e RLS/FORCE conferidos. Sem migrações novas, dados activos, mensagens externas ou nova prova multiprocesso deste comando. O build conserva os avisos já existentes sobre fontes e dimensão de bundles, sem falha.
+
+Saldo: AUD-EDU-03 passa de não implementado a implementado parcialmente pelo percurso interno do gestor. Restam jornadas de estudantes, instituições e empregadores, definição concreta de representação/consentimento e respectivo isolamento, apresentação visual e entrega no destino. AUD-EDU-01 continua parcial; AUD-EDU-02 mantém a cobertura e saldo próprios já reconciliados. O motivo de revisão ainda não confirmado permanece na página; não se declara recuperação durável dessa preparação após perda da página. O registo de revisão é decisão interna, não acredita instituição/curso nem substitui mandato institucional. A auditoria integral do portal continua em curso.
+
+### 03/11/2026 — AUD-PROFILE-20: incidentes técnicos e perfil próprio de suporte
+
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Registo automático de falhas técnicas de submissão/publicação, referência correlacionada, consulta própria e perfil próprio de Suporte técnico com fila por organização/tipo. Reutiliza auditoria append-only e atribuições existentes, sem aprovação ou acesso documental adicional.15 Feature/264 asserções (oito novos,sete anteriores);12 frontend (seis novos,seis anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Base final QA com59 tabelas vazias, owner/RLS/lock conferidos; primeira execução mista acompanhada separadamente.80 recibos/298 provas anteriores preservados. Recibo opportunity_technical_incidents_increment_20261103. Parcial local; migração do papel somente em QA, sem alterações no activo.
+
+Origem: Gestao de perfis investeMOZ v1.docx SHA256f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38, §3.5/p283 e tratamento de falhas p289–293, segregação/atribuição p33/339–346; segmentação bf26caee §8.4/p860. Matriz e código confirmavam que falhas técnicas de submissão/publicação não produziam incidente de negócio consultável. Não se confunde isto com C132, diagnósticos de autenticação, suporte fundiário ou registos de scan/worker existentes. A ronda anterior de Educação foi verificada antes do delta. O proprietário respondeu «Perfil próprio de Suporte técnico» à escolha do destinatário: essa decisão autoriza o papel e a fila; não cria pessoas reais, prazos/SLA, canais externos ou competências de aprovação.
+
+Registo: OpportunityWorkflowExecution envolve o motor existente, sem alterar as regras das transições. Para submissão/publicação efectivamente disponíveis ao actor, uma excepção técnica após a transacção gera evento restrito separado. Validação, versão ultrapassada, autenticação, permissão e 404 não são convertidos em incidentes. O registo conserva referência UUID útil para acompanhamento/correlação, operação, versão e revisão observadas antes da tentativa, etag tentado, estado, organização/tipo e código técnico genérico. Não copia motivo, contrato, anexos, SQL, mensagem ou trace da excepção. Cada pedido que falha é uma tentativa observada distinta; não se afirma deduplicação de um incidente lógico entre várias falhas.
+
+Resultado incerto: HTTP503 no-store explica a referência e exige consultar o estado antes de repetir. Não há repetição automática, aprovação, publicação ou inversão de estado pelo incidente. O evento de falha é gravado só depois de a transacção de negócio terminar; os testes provocam falha real na inserção da auditoria final, após alterações de estado/tarefas, e conferem reversão de todos esses dados. Uma perda de ligação no commit pode deixar resultado incerto: a mensagem não promete reversão universal. Se também falha o registo do incidente, devolve incident_recorded=false e a referência, sem alegar persistência; log de fallback contém apenas referência/código. Uma subtransacção protege a ligação quando existe uma transacção envolvente.
+
+Consulta e encaminhamento: o autor consulta até dez tentativas próprias no detalhe autorizado da oportunidade. A fila /suporte-tecnico/incidentes apresenta20 metadados por página e apenas os âmbitos actuais atribuídos a technical_support. Organização/tipo capturados também têm de coincidir com o registo actual; contexto desconhecido ou posteriormente mudado não é inferido. A fila não expõe título/contrato, documento, identidade do promotor, etag, JSON bruto ou link para um processo reservado. Auditor prevalece como restrição; revogação/expiração são reavaliadas. A fila é o encaminhamento interno por perfil, não prova de uma mensagem entregue ou de um tratamento concluído.
+
+Papel: acrescentado ao mecanismo existente de atribuição independente por Superutilizador/MFA, com tipo, organização, motivo, vigência, revogação e auditoria. Nova versão profiles-technical-support-20261103 para essas atribuições; restantes papéis conservam a versão anterior. A interface apresenta Suporte técnico e o link apenas pela capacidade do servidor. O novo papel não integra hasOperationalReadScope, Promotor, Validador, Publicador ou administração legada; não recebe aprovações, concessões, acesso a anexos ou alçada por inferência. Pode coexistir com papéis legítimos anteriores nos limites da política existente. Não foi criada uma obrigação universal adicional de MFA para este perfil; a outorga continua a exigir a competência administrativa e MFA já vigentes.
+
+Instalação: a migração080000 amplia somente a restrição de nomes de papéis. Segue a guarda existente de instalação autenticada dos perfis fora de testing e exige QA isolada nos testes. O downgrade recusa remover a compatibilidade se existirem atribuições, mesmo históricas. Não altera atribuições antigas nem concede o novo papel automaticamente. Preparada e aplicada apenas na base descartável; integração desta actualização no instalador e disponibilização no destino ainda por concluir.
+
+Validação:15 Feature/264 finais no código actual (oito novos e sete de PortalProfileAccess).12 frontend exercitam leitor próprio, navegação por capacidade, fila vazia/metadados e transporte de erro sem repetir escrita, mais seis casos anteriores de profileJson. Tipos globais, PHPStan nível7 sem supressões, Pint, sete fontes formato/lint e build aprovados. A suite integral1545 anterior permanece histórica. A primeira execução mista de incidentes/canónico/perfis tem resultado separado running_observed; não é declarada suite global aprovada. A primeira fixture de incidentes omitia a gravação do contrato completo e o servidor recusou correctamente a submissão422; foi corrigida a fixture, conservando as validações. Corrigida também a expectativa do contrato de atribuição201, sem mudar a API. Provas falhadas preservadas como diagnóstico. Duas bases QA distintas foram usadas enquanto a primeira execução ainda estava confirmadamente activa; não se reiniciou por falta de output. A execução final de15 casos terminou;59 tabelas vazias na base technical_support, owner/RLS/FORCE e lock conferidos. A primeira execução mista permanece separada: se ainda activa, o seu log mutável e a limpeza dessa base não são incluídos nas provas aceites; continuar a acompanhar o mesmo processo e conferir rollback quando terminar. Sem escritas/migrações activas, contas reais, mensagens externas ou prova visual.
+
+Saldo: AUD-PROFILE-20 passa a implementado parcialmente. O registo, preservação delimitada e encaminhamento por fila/perfil estão agora implementados; continuam tratamento do incidente (assunção, notas, resolução/reabertura e histórico), alertas próprios/painel de saúde, outros pontos de falha/upload/worker/integrações, escalonamentos e parâmetros operacionais conforme definição aplicável, instalador e entrega, variantes e apresentação visual. A decisão sobre o perfil está resolvida e não deve ser pedida de novo. Próxima acção: acrescentar o tratamento auditado à fila usando este mesmo papel e a referência, sem tocar na decisão da oportunidade. A auditoria integral permanece em curso.
+
+### 03/11/2026 — AUD-PROFILE-20: tratamento auditado e recuperação do envio de suporte
+
+[TECHNICAL-INCIDENT-HANDLING-20261103] Tratamento de incidentes pelo perfil existente: assunção/substituição explícita, notas cifradas, devolução à fila, resolução e reabertura, histórico privado paginado e filtros pelo estado actual. Versão e tentativa identificada preservam notas e impedem repetição de efeitos.18 Feature/339 asserções (dez novos,oito anteriores);28 frontend (16 novos,12 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Um cenário com dois processos e espera real no incidente:200/409, replay só de leitura, investimento e raiz intactos. QA final59 tabelas vazias; prova concorrente retém só amostras sintéticas declaradas.81 recibos/306 provas anteriores preservados. Recibo technical_incident_handling_increment_20261103. Parcial local, zero novas migrações/escritas activas.
+
+Origem e âmbito: continuação do incremento OPPORTUNITY-TECHNICAL-INCIDENTS-20261103 e da decisão expressa do proprietário «Perfil próprio de Suporte técnico». Reutilizados o mesmo papel technical_support, âmbitos/validade/revogação e os incidentes já registados. O tratamento é técnico e não decide investimentos. Não foram criadas competências de Promotor, Validador, Publicador, administrador, SLA, calendários ou pessoas reais; a regra do dono para encerrar/reabrir dossiers permanece intacta.
+
+Percurso: nova ficha /suporte-tecnico/incidentes/{reference}, ligada à fila e ao contexto de página/estado. Permite assumir tratamento, substituir explicitamente o responsável actual por si, acrescentar nota, devolver à fila, resolver e reabrir. A equipa autorizada no âmbito partilha o tratamento; não se introduziu uma autoridade exclusiva do responsável que não tinha sido definida pela Tempo. Cada acção exige nota e a versão analisada. Resolver um incidente não submete, publica, aprova ou reverte a oportunidade. Notas de incidente resolvido não reabrem implicitamente. Fila Todos/Na fila/Em tratamento/Resolvido consulta o estado mais recente, com paginação normal e regresso ao mesmo contexto.
+
+Uma fonte de histórico: cada tratamento acrescenta evento restrito à auditoria append-only existente, correlacionado à raiz; nenhum evento anterior é actualizado/eliminado. Preservados estado, responsável, versão e datas anteriores/aplicados; nota cifrada com Crypt. A nota não é copiada para o incidente original ou para o investimento. A ficha mostra autores pelo nome actual da conta, com10 eventos por página; não inventa nomes históricos. Envelope ilegível é assinalado e preservado. Estado actual inválido não volta silenciosamente a Na fila e recusa nova escrita. A projecção opcional na fila e no editor mostra indisponibilidade; o estado técnico ilegível não bloqueia a leitura/edição normal do investimento, demonstrada por HTTP.
+
+Autoridade e isolamento: raiz lida pelo mesmo filtro de organização/tipo capturados e actuais, mais atribuição efectiva de suporte, validade e restrição Auditor. No comando, reavaliado sob bloqueio FOR UPDATE OF event apenas na raiz do incidente. Não se bloqueia/edita o investimento como forma de obter autoridade. Notas internas ficam no detalhe autorizado; o autor da tentativa recebe somente estado/versão/data técnica na consulta própria, sem notas, chaves ou responsável interno. Assumir ignora um destinatário injectado pelo cliente e usa a conta autenticada. A atribuição não se amplia por igualdade de nome, perfil acumulado ou mera posse da referência.
+
+Repetição segura: operation_key UUID normalizado, resumo canónico de versão/acção/nota e actor, dentro da raiz bloqueada. Mesmo comando confirma o resultado anterior sem outra nota/versão ou mudança de responsável. Outra nota com a mesma chave e uma nova chave sobre versão obsoleta são recusadas. Recibo antigo após uma resolução posterior não a desfaz. Falha na inserção final reverte o tratamento; a tentativa original pode ser repetida explicitamente. A operação não dispara outro incidente em cascata nem repete automaticamente comandos do investimento.
+
+Formulário: congela comando, versão, nota e chave antes do POST; guarda a preparação na memória da página. Resposta incerta conserva o envio original e a nota editada depois. Confirmação limpa apenas texto não alterado entretanto. Consulta autorizada pode confirmar o recibo sem novo POST; mudança da equipa exige comparação e confirmação explícita. Uma preparação obsoleta só é abandonada após leitura de versão superior que impede o envio antigo e acção explícita do utilizador. Consulta na mesma versão não descarta uma tentativa incerta. Callbacks antigos/de outra conta não apagam a nota nem desbloqueiam o envio seguinte. Um único aviso protege saída/recarregamento; não se afirma recuperação durável da nota ainda não confirmada depois da perda da página. O próprio perfil e a consulta do recibo não concedem acesso adicional.
+
+Validação:18 Feature/339 no código final, dez casos novos e os oito de incidentes/perfis anteriores.28 frontend actuais,15 do novo formulário mais um novo caso de ligação/contexto e os12 consumidores/transportes anteriores. Tipos globais, PHPStan nível7 sem supressões, Pint e nove fontes de formato/lint passaram; build com avisos de fontes opcionais/tamanho já conhecidos. Ronda integral1545 anterior continua histórica. Um ensaio sintético real com dois processos observou o primeiro bloqueado numa barreira QA após adquirir a raiz e o segundo à espera dessa mesma transacção. Após libertar, o primeiro recebeu200 e o segundo409; resolução posterior e repetição antiga conservaram versão2/resolvido, oportunidade, raiz e zero tarefas. Não é teste de carga ou de todas as intercalações.
+
+Conservação QA: incident_handling_20261103_test terminou e ficou com59 tabelas vazias; lock, identidade, owner/RLS/FORCE conferidos. O clone descartável incident_handling_concurrency_20261103b_test retém4 contas sintéticas,uma organização,uma oportunidade,duas atribuições,três eventos e zero tarefas, com visibilidade conferida. A nova execução nesse clone foi recusada com exit1 por dados existentes, sem os redefinir. O primeiro ensaio concorrente tinha comparação de atributos antes de recarregar os defaults de PostgreSQL; corrigida a fixture de comparação e repetido noutro clone, preservando o primeiro e o seu diagnóstico. A guarda CLI passou a devolver exit1 explicitamente numa excepção, em vez de depender do handler da aplicação. Nenhuma tabela nova, migração ou operação activa decorre deste tratamento.
+
+Execução mista anterior encerrada: o processo53686 terminou com45 casos,41 aprovados,quatro falhados e1004 asserções, com um aviso de teste arriscado. As quatro falhas pertencem à fixture antiga de incidentes sem contrato gravado, não à validação canónica/perfis; a expectativa de logging não chamada originou o aviso. Os40 casos anteriores do canónico/perfis passaram naquela execução; não se reclassifica a execução completa como aprovada ou candidata imutável. Os casos de incidentes corrigidos passaram depois nos15 casos do incremento anterior e voltam a passar nos18 actuais. A base opportunity_incidents_20261103_test também ficou vazia nas59 tabelas, com lock/owner/RLS/identidade conferidos. O registo anterior running_observed fica preservado como observação histórica e está agora superado por este resultado terminal.
+
+Saldo: registo, fila, perfil e tratamento técnico com histórico/recuperação delimitada implementados e verificados localmente. Restam alertas/notificações próprias, saúde e outros pontos de falha/upload/worker/integrações, regras operacionais/escalonamentos quando definidas, integração no instalador e disponibilização, apresentação visual e retoma durável da preparação não confirmada. Não voltar a pedir a escolha do perfil nem a tratar o ciclo agora implementado como inexistente. AUD-PROFILE-20 e o objectivo transversal continuam parciais; próxima acção é integrar a actualização no instalador existente e continuar os alertas autorizados por âmbito, sem novos canais externos por inferência.
+
+### 03/11/2026 — AUD-PROFILE-20: actualização de Suporte técnico pelo instalador existente
+
+[SUPPORT-PROFILE-INSTALLATION-20261103] Actualização do perfil de Suporte técnico integrada no instalador autenticado existente: prévia, MFA, provas do destino/código, confirmação e recibo idempotente. Schema e ledger partilham a mesma verificação no servidor e na disponibilidade do perfil.18 Feature finais/230 asserções (dez novos,oito do instalador anterior); regressão inicial36/569;30 frontend (15 novos,15 do tratamento anterior),PHPStan/Pint/tipos/formato/lint/build aprovados. Backup PostgreSQL e arquivo de candidato/original privado sintético efectivamente restaurados em QA: 190 tabelas,30 sequências,1567 ficheiros e três envelopes MFA legíveis. Actualização e repetição conservaram todas as tabelas salvo uma entrada de migração e um recibo; zero atribuições de suporte inferidas. QA de testes62 tabelas vazias.82 recibos/318 provas anteriores preservados. Recibo support_profile_installation_increment_20261103. Parcial local, sem instalação/escrita activa.
+
+Origem: continuação da decisão expressa do proprietário «Perfil próprio de Suporte técnico» e do tratamento já demonstrado. O instalador da base de perfis permanece a autoridade existente. Nova prévia/aplicação em /management/profile-install/technical-support, acessível pela instalação de perfis; exige identidade verificada e autoridade actual de instalação, incluindo precedência da restrição Auditor. Escrita e replay exigem MFA recente da sessão. Não altera as condições de acesso quotidiano do suporte nem escolhe pessoas, SLA, canais ou responsáveis por inferência.
+
+Instalação delimitada: migra exclusivamente 2026_11_03_080000_add_technical_support_profile, já existente no incremento anterior, sob a transacção/lock e recibo do instalador. Reavalia dependências, destino, código, prova e estrutura analisada antes de executar. Atribuições, contas, dupla administrativa, dados de negócio e flags não são criados/redefinidos pela actualização. A atribuição do papel continua a operação explícita e auditada na Gestão de perfis. O replay devolve o recibo anterior sem repetir DDL; motivo diferente com a mesma chave é recusado. Falha na auditoria final reverte constraint e ledger.
+
+Uma interpretação de estrutura para runtime e instalador: TechnicalSupportProfileSchema verifica a CHECK validada e exacta portal_role_name e o registo da migração. O ledger isolado deixa de anunciar o perfil disponível. Reconhece a versão anterior de quatro papéis e a nova de cinco. Se a migração está registada mas a CHECK validada ainda é exactamente a anterior, oferece reposição delimitada com as mesmas provas e autenticação, preservando o registo da migração. CHECK ausente, enfraquecida, desconhecida ou cinco papéis sem ledger não são sobrescritos/adoptados implicitamente. Downgrade conserva a recusa perante atribuições de suporte, incluindo revogadas.
+
+Prova técnica existente fortalecida: mantém a janela de24 horas e backup/restauro, ficheiros, compatibilidade e QA já exigidos. Flags devem ser booleanos true; texto «false», metadados de outro tipo, data futura/expirada, destino/código diferente e ficheiro adulterado não confirmam preparação. O hash dos bytes da prova participa no plano: outra prova válida exige nova análise. Não se acrescentou uma aprovação humana, uma fonte organizacional ou um calendário. No-op de actualização já instalada segue o padrão anterior, sem repetir migração ou conceder privilégios.
+
+Formulário: motivo e confirmação próprios desta operação; congela plano, motivo e chave antes do POST. Resultado incerto permite apenas repetição explícita do original ou consulta autorizada do recibo próprio. Ausência do recibo não descarta a tentativa; mudança do plano exige comparação e nova confirmação. Resposta de outra conta/destino/chave/código não confirma. MFA expirada impede retry até nova confirmação de sessão. Callbacks antigos não alteram outra preparação. Confirmação limpa só o motivo ainda inalterado; edições posteriores permanecem. Consulta antiga sem o recibo conhecido não desbloqueia outra operação. Corrigida mensagem antiga de erro que persistia depois de consulta recuperada. Preparação continua em memória, sem promessa de retoma durável após perda da página.
+
+Protecção da preparação: um único guard comum protege saída/recarregamento. A página anterior de instalação também protege motivo e IDs dos dois titulares. Depois de resposta de escrita conhecida, campos efectivamente enviados deixam de gerar aviso falso, mesmo se a consulta seguinte falhar; alterações posteriores e campos não enviados continuam protegidos. Os percursos de inicialização separada e confirmação pelo segundo titular não foram substituídos.
+
+Verificações:36 Feature/569 na primeira regressão de instalação, incidentes e tratamento; depois da correcção/normalização final do formulário,18 Feature/230 focados nos dez novos casos e oito do instalador anterior.30 frontend finais incluem15 novos e15 do tratamento prévio. PHPStan nível7 nos quatro serviços/controlador alterados sem supressões; Pint nas cinco fontes PHP; tipos globais e seis fontes de formato/lint passaram; build concluído com os avisos já conhecidos. Erros iniciais de frontend foram reproduzidos e corrigidos. Cache de Pint devolvia resultado desactualizado na reparação; cache específica nova aplicou a formatação e o teste final passou. Não se repete nem se reclassifica como actual a ronda integral1545 histórica. Testes de componentes/HTTP não equivalem a aceitação visual em browser.
+
+Ensaio operacional distinto das fixtures: SupportProfileInstallationTest usa ficheiros sintéticos para testar o contrato de readiness e declara-o expressamente. A prova operacional adicional criou dois destinos novos em127.0.0.1:55441 como investmoz_test: support_profile_installation_operational_20261103c_test e support_profile_installation_restore_20261103c_test. Template conferido antes da cópia: sem dados de negócio e com os seeds existentes de spatial_ref_sys(8500),questionnaire_versions(2) e ai_controls(7) preservados. A primeira guarda recusou essas tabelas de referência antes de criar qualquer clone; a condição foi corrigida para conferir as contagens exactas, sem apagar os seeds. Nenhuma base existente redefinida. Snapshot read-only/repeatable-read exportado para pg_dump e restaurado por pg_restore; comparadas todas as tabelas por bytes ordenados e sequências, owner/RLS/FORCE, mais legibilidade dos três envelopes MFA sintéticos. O primeiro ensaio restaurou tabelas e sequências, mas a sua guarda rejeitou RLS existente por esperar incorrectamente todas as tabelas sem RLS. A comparação confirmou16 tabelas com RLS/FORCE idênticos na origem/restauro. Preservado esse clone/diagnóstico, corrigida a guarda para exigir equivalência de owner/RLS e visibilidade efectiva da identidade QA, e repetido em dois destinos novos de sufixo b. Nenhuma política ou permissão foi desligada/alterada para o ensaio. No clone b, a actualização e o replay ocorreram, mas a asserção PHP do ensaio comparava identidade de objecto stdClass com o array do recibo JSON. Corrigida a comparação para valores canónicos tipados, preservado também esse clone e repetida a prova integral no sufixo c. O resultado falhado do ensaio b não é convertido numa aprovação global. Arquivo de código/build e um original privado sintético extraído com guarda de caminhos e hashes conferidos. Não arquiva .env nem documentos de clientes e não afirma restauro de um destino activo.
+
+Após essa prova real, o serviço autenticado do instalador com actor sintético e MFA aplicou a actualização e confirmou o mesmo recibo no replay. De todas as tabelas, só migrations e audit_events mudaram, com exactamente uma linha adicional em cada; contas, dupla, atribuições anteriores, oportunidade e restantes tabelas conservaram o hash. Nenhum perfil de suporte concedido. O clone operacional e o restauro anterior são retidos como provas sintéticas; nova execução nesse destino é recusada com exit1 antes de qualquer reset. O ensaio não é aceitação de cliente, instalação activa nem instalação no SGF/SGC. QA de testes terminou com62 tabelas vazias, lock/owner/RLS/identidade conferidos, incluindo dupla, pedidos de perfis e aprovações de segurança.
+
+Saldo: integração da actualização de suporte no instalador implementada e demonstrada localmente; a disponibilização/instalação no destino continua a acção autenticada própria com provas desse destino. Restam alertas próprios por âmbito, saúde/outros limites de falha, parametrização/escalonamentos aplicáveis quando definidos, retoma durável da preparação e aceitação visual. AUD-PROFILE-20 e o objectivo transversal permanecem parciais. Conservar decisões já recebidas sobre suporte, dono do dossier, línguas/modelos e Educação; não voltar a pedir essas definições nem inventar fontes ausentes. Próxima acção: continuar avisos internos de incidentes aos suportes efectivos, reutilizando mecanismos existentes e preservando autorização actual.
+
+### 03/11/2026 — AUD-PROFILE-20: avisos internos de incidentes por consultar
+
+[SUPPORT-INCIDENT-NOTICES-20261103] Avisos internos de incidentes por consultar para o Suporte técnico efectivo, com contador próprio na navegação, filtro antes da paginação e marca explícita de consulta por actor/raiz. A consulta não é tratamento, resolução, aprovação ou acesso documental.25 Feature finais/376 asserções (sete novos,18 de instalação anteriores);31 frontend (nove novos,22 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. QA62 tabelas vazias e identidade/owner/RLS/FORCE conferidos.83 recibos/330 provas anteriores preservados. Recibo support_incident_notices_increment_20261103. Parcial local, sem migração ou escrita activa.
+
+Origem e recorte: desenvolvimento autorizado a partir da decisão do proprietário «Perfil próprio de Suporte técnico». Aviso interno ao papel e âmbito efectivos, reutilizando a fila e o histórico existentes. Escolha técnica de apresentação: contador no link de Suporte técnico da navegação dos perfis, filtro Por consultar/Todos os avisos e acção explícita de consulta em cada incidente, na fila e no detalhe. Não se inventam destinatarios nominativos, email/SMS/outros canais, SLA ou escalonamentos. Nenhuma mensagem externa foi enviada.
+
+Autoridade unica: contador, filtro, detalhe e marca usam a mesma query de incidentes autorizados: papel vigente e verificação de Auditor, organização/tipo capturados e actuais e oportunidade existente. Sobreposicao de atribuições não duplica o incidente. Revogacao, expiração, falta de verificação de identidade e mudanca de contexto retiram a visibilidade; ser gestor legado ou autor da tentativa não concede suporte. Sem dados de processos, documentos ou notas no aviso da navegação. Outros actores não recebem o estado de consulta de um colega.
+
+Estado próprio: Por consultar significa ausência da marca explícita deste actor para esta raiz. Abrir uma página GET não escreve a marca. Marcar aviso como consultado regista um evento restrito append-only em audit_events, fonte portal-opportunity-support-notices e acção incident_consulted. A raiz é reautorizada sob o mesmo bloqueio de linha antes da consulta/inserção. A repetição devolve a primeira data/confirmação sem duplicar eventos. O actor provem da sessão e não de um destinatario injectado no corpo. A marca não altera a raiz original, a versão de tratamento, responsável, notas, oportunidade, tarefas ou atribuições. Incidente resolvido pode ter aviso por consultar; consulta não equivale a resolução. Cada novo incidente tem uma raiz própria e um novo aviso; alteracoes posteriores de tratamento não são novos avisos neste recorte.
+
+Filtros e continuidade: a exclusão de avisos ja consultados ocorre no SQL autorizado antes do limite/paginação, pelo que incidentes antigos por consultar não são ocultados por muitos recentes consultados. Estado técnico e Por consultar combinam-se; os links dos filtros e detalhe preservam ambos, página de origem e regresso. Metadados de tratamento invalidos continuam assinalados como indisponiveis na fila, sem impedir consulta do aviso. O histórico de tratamento ignora os eventos de consulta e continua a mostrar apenas as suas próprias acções.
+
+Formulário sem dados reintroduzidos: a consulta e um comando com corpo vazio para a raiz e conta actuais, sem outro motivo ou confirmação de decisão. Bloqueia duplo clique enquanto aguarda. Confere actor/referencia/read da resposta e, em perda de resposta, oferece repetição explícita da mesma acção comutativa. Não repete HTTP automaticamente. Previa autorizada com a marca própria confirma o estado e prevalece sobre resposta falhada tardia; props antigas não voltam a colocar um aviso confirmado como não consultado. Callback de outra conta/raiz ou apos desmontar não actualiza a página nova. A actualização parcial preserva estado/scroll e notas em preparação; usa o guard ja existente do tratamento, sem outro aviso de saida.
+
+Falhas: inserção final recusada reverte a marca e permite nova tentativa explícita. O contador é uma projecao opcional: uma falha SQL devolve indisponibilidade sem zero inventado e usa transacção/savepoint para não deixar a transacção do chamador abortada. Teste PostgreSQL concreto de coluna temporariamente indisponivel demonstrou a falha, continuacao da leitura de users e recuperação da contagem depois de reposta a coluna, exclusivamente dentro da base descartavel. Nenhuma guarda RLS/owner/isolamento foi desligada para esse ensaio.
+
+Verificação:25 Feature finais/376 no código final, sete casos novos mais18 de ambos os instaladores. A execução inicial de43 casos terminou com41 aprovados,uma falha e um erro,664 asserções. Os36 casos anteriores passaram; a falha nova era a ordem normalizada do cabeçalho Cache-Control e o erro era uma fixture com expires_at anterior ao starts_at, recusada pela constraint portal_role_period. Corrigidos ambos os dados do ensaio, preservado o diagnóstico e repetidos os25 casos finais. A opção preserveScroll na chamada de reload foi removida porque o Inertia instalado preserva scroll/estado automaticamente e os seus tipos recusam essa opção nessa chamada.31 frontend finais, sete casos de confirmação/recuperação/contexto e dois de contador/filtros, com22 anteriores. PHPStan nivel7 nos quatro serviços/controlador alterados, sem supressões; Pint em cinco fontes PHP, tipos globais, oito fontes de formato/lint e build passaram. A ronda integral1545 continua prova histórica. QA support_incident_notices_20261103_test terminou com62 tabelas vazias, incluindo identidades, atribuições, dupla, pedidos, aprovações e auditoria, conferidas sob lock, owner/RLS/FORCE e identidade investmoz_test em55441. Sem novas tabelas ou migrações; não se afirma um novo ensaio concorrente nem aceitação visual.
+
+Conservação e saldo:83 recibos/330 provas anteriores preservados. O ensaio efectivo de backup/restauro do incremento de instalação continua histórico para o candidato ali arquivado; não é reclassificado como prova de instalação deste novo fingerprint. O instalador inclui também o novo componente na impressão do candidato e exige prova actual do destino/código para alterar schema. Mantém-se disponibilização autenticada no destino e aceitação visual, saúde e outros pontos de falha/upload/worker/integrações, avisos de actualizações posteriores de tratamento, regras/escalonamentos aplicaveis e retoma durável da preparação não confirmada. Alertas de novos incidentes por consultar deixam de ser lacuna de implementação neste recorte; AUD-PROFILE-20 e o objectivo transversal continuam parciais. Próxima acção: continuar limites técnicos de upload/integração e saúde operativa com as fontes existentes, sem inventar política organizacional.
+
+### 03/11/2026 — AUD-PROFILE-20: incidentes de uploads e preservação de originais em falhas
+
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Incidentes de upload de documentos/imagens e preparação WebP integrados no mesmo suporte, avisos e tratamento por âmbito. Limpeza conservadora conserva originais referenciados e bytes de resultado incerto; falhas na limpeza não escondem o erro original.23 Feature/285 asserções (oito novos,cinco de recursos e dez do instalador); um caso adicional sem GD/duas asserções;37 frontend (seis novos,31 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. GD/WebP carregado apenas no processo CLI de QA; configuração normal sem alteração. QA64 tabelas vazias, com identidade/owner/RLS/FORCE conferidos.84 recibos/339 provas anteriores preservados. Recibo resource_technical_incidents_increment_20261103. Parcial local, sem migração ou escrita activa.
+
+Origem e âmbito: continuação da decisão do proprietário «Perfil próprio de Suporte técnico» e do saldo de falhas de upload no requisito existente. Aproveitados o papel, âmbitos, fila, avisos individuais e tratamento já implementados. Acrescentados os pontos síncronos de carregamento de documentos/imagens e preparação de derivadas. Não foram criados destinatários, canais externos, SLA, perfis adicionais ou competências de decisão. Outros limites técnicos continuam no saldo; não se declara cobertura de todas as falhas do portal.
+
+Uma classificação comum de falhas: OpportunityTechnicalExecution é reutilizado pelo adaptador de submissão/publicação e pelos pontos de upload/preparação. A chamada já tem acesso efectivo de edição conferido; o incidente só é capturado depois de a transacção de negócio terminar/desfazer. Validação, autenticação, autorização, ausência de registo e respostas esperadas inferiores a500 são preservadas, incluindo o HttpResponseException409 usado nos recursos. Não repetem HTTP, gravação ou decisão automaticamente. Nos uploads, a fronteira inclui também a construção da confirmação e leitura do ETag posterior à gravação: uma falha posterior não pode ser apresentada como sucesso confirmado nem pressupor rollback do que já foi gravado.
+
+Resposta e privacidade: preservada a excepção de compatibilidade, com resposta JSON503 própria, referência UUID e incident_recorded verdadeiro/falso. Falha a guardar o próprio incidente continua assinalada honestamente. A resposta e a raiz não incluem SQL, texto da excepção, bytes, nome do ficheiro, título, motivo ou payload do recurso. A raiz conserva somente a conta, oportunidade/organização/tipo, operação e versões/estado técnicos já usados pelo mecanismo. O autor consulta os seus últimos dez incidentes também na página de recursos, com acesso actual, no-store e histórico cifrado. O suporte continua restrito ao âmbito actual/capturado e não ganha acesso ao recurso original ou ao investimento; HTTP demonstrou a fila disponível e o editor de recursos403 para o mesmo suporte.
+
+Operações identificáveis: upload_document, upload_image e prepare_image juntam-se a submit/publish. Cartão do autor, fila e ficha partilham os nomes Carregamento de documento/Carregamento de imagem/Preparação de imagens WebP. Operação desconhecida deixa de ser apresentada por defeito como Publicação. A mensagem genérica da fila foi ajustada para a operação. O catálogo de leitura do servidor reconhece apenas estas operações no recorte. Avisos por consultar e tratamento usam a mesma raiz e mantêm-se independentes da operação de investimento e da análise de segurança.
+
+Originais e limpeza: corrigida a eliminação incondicional no catch do upload/processamento. OpportunityResourceFileCleanup considera somente chaves no prefixo privado previsto e não apaga qualquer chave ainda referida por documents, incluindo históricos/excluídos logicamente. Perda de ligação reconhecida pelo detector do próprio Laravel conserva os bytes sem usar uma leitura de ausência que poderia preceder um commit incerto. Falha na verificação da referência também conserva os bytes, com transacção/savepoint para não deixar o chamador abortado. Só se tenta retirar um novo ficheiro sem referência confirmada. Falha/false na eliminação produz aviso sanitizado e não substitui o erro original, nem expõe o caminho ao suporte. Não há purge automático de bytes retidos; essa reconciliação permanece necessária. O ramo de ligação incerta foi ensaiado por injecção de falha observável, não por corte real de rede ou todas as intercalações possíveis de commit.
+
+Visibilidade efectiva: a referência só é considerada ausente se row_security_active confirmar que a leitura não está sujeita a RLS. RLS activa ou visibilidade indeterminada conserva os bytes. Um caso PostgreSQL real activou RLS/FORCE apenas na tabela descartável e usou SET LOCAL ROLE pg_read_all_data, papel preexistente sem criar contas/grants. A mesma referência ficou oculta: contagem0 e row_security_active true. A limpeza conservou o ficheiro; depois de RESET ROLE para a identidade original de QA, a referência continuava a existir, contagem1, e current_user voltou a investmoz_test. A diferença de identidades está declarada e demonstra por que ausência numa leitura filtrada não prova ausência de referência. RLS/role e registos do ensaio foram revertidos na transacção de teste; a conferência final voltou a encontrar as64 tabelas vazias e a visibilidade normal. Não se desliga RLS no produto para decidir uma limpeza.
+
+Escritas parciais: o store inicial agora conhece a chave antes de tentar guardar e trata a falha parcial mesmo antes da transacção de negócio. Na preparação de derivadas, a chave nova é registada para limpeza antes do put, cobrindo drivers que escrevem parte e devolvem false. O ensaio actual gerou uma imagem sintética, verificou o original com CleanScannerFixture, injectou a falha de armazenamento durante a primeira derivada e demonstrou original cifrado intacto, versão/payload da imagem e oportunidade inalterados, uma única linha de documento original e ausência dos novos bytes sem referência. Esse scan sintético não prova segurança de um ficheiro real.
+
+Dependência GD explícita: a configuração normal deste PHP continua sem GD/WebP. A extensão já disponível foi carregada apenas com -d extension=gd no processo CLI isolado, permitindo executar realmente o percurso anterior e os cinco casos de recursos existentes. Metadados dos dois processos confirmam GD/WebP true/true e false/false, sem alterar php.ini ou activar capacidades no servidor acompanhado. Outro ensaio, no PHP normal, demonstrou423 e zero incidentes indevidos quando o processamento não está disponível. Não se considera o processamento operacionalmente disponível no destino por ter passado num processo de QA configurado para o ensaio.
+
+Formulário: os testes usam a página real de recursos e o transporte real do seu formulário. Depois de503, o título, motivo, objecto do ficheiro seleccionado, chave de criação e ETag enviados permanecem na preparação; apenas a repetição explícita volta a enviar. Ler o novo incidente no mesmo contexto não reinicializa os campos. A referência recebida é apresentada ao autor. Estes dois casos verificam memória da página e não prometem retoma durável após navegação, recarregamento, autenticação ou perda da página. Não foram acrescentados motivos repetidos, aprovações ou formulários de suporte ao upload.
+
+Validação:23 Feature/285 finais, com os oito casos novos,cinco de recursos e dez do instalador autenticado. A primeira execução teve27 casos,25 aprovados,uma falha e um erro,408 asserções. Os20 casos anteriores passaram naquela execução. A implementação funcional dos oito casos de incidentes/transições e sete de avisos não foi alterada depois; os cinco de recursos voltaram a passar na execução final. As duas falhas pertenciam às novas fixtures: UploadedFile fake reportava MIME de PDF pelo nome e não o MIME inválido pretendido; outro documento sintético não tinha o estado obrigatório. Corrigidos o MIME explícito e o estado/cifra/classificação da fixture, preservado o diagnóstico e repetidos os22 casos. A revisão da guarda de visibilidade acrescentou depois o oitavo caso novo e foi verificada nos23 casos finais,285 asserções. O ensaio sem GD passou um caso/duas asserções.37 frontend finais incluem três operações conhecidas, o fallback desconhecido e os dois casos de formulário, com31 anteriores. PHPStan nível7 em nove fontes de aplicação sem supressões, Pint em dez fontes PHP, tipos globais, nove fontes de formato/lint e build passaram. A última alteração visual foi apenas tornar genérica a descrição da falha na fila; os checks de interface/build abrangem essa redacção final. A ronda integral1545 continua histórica; não se afirma aceitação visual em browser ou por pessoas reais.
+
+Conservação e saldo: resource_incidents_20261103_test terminou com64 tabelas vazias, incluindo agora opportunity_images e opportunity_locations além das62 anteriores. Conferidos lock, identidade investmoz_test/55441 e visibilidade owner/RLS/FORCE. Nenhuma tabela/migração nova ou escrita activa. Preservados84 recibos/339 provas anteriores, fontes, dados, originais e percursos aceites. O instalador inclui os dois serviços novos no fingerprint, e os dez casos próprios passaram com essa integração. O backup/restauro real anterior continua a prova do candidato arquivado, não uma prova nova de instalação deste código. Restam despacho/execução de scans e falhas de workers/integrações, saúde operacional e outros limites de falha, reconciliação de bytes retidos, disponibilidade GD no destino, entrega/visual e retoma durável. Gravações de metadados sem ficheiro, localizações, ciclo de vida e reutilização da biblioteca mantêm os seus percursos anteriores; não foram declaradas novas fronteiras de incidentes neste recorte. AUD-PROFILE-20 e o objectivo transversal continuam parciais. Próxima acção: continuar os pontos de despacho/execução dos scans com os mecanismos e autoridade existentes.
+
+### 03/11/2026 — AUD-PROFILE-20: despacho, workers e resultados antigos da análise de documentos
+
+[SCAN-TECHNICAL-INCIDENTS-20261103] Falhas no despacho e execução da análise de documentos ligadas ao Suporte técnico por contexto capturado e acesso actual. Tentativas e callbacks identificados no histórico existente; resultados antigos não substituem resultados posteriores, e falha de confirmação da fila não reverte um documento já limpo.30 Feature/365 asserções finais (15 novos,cinco de recursos,dez do instalador), com42/574 anteriores sobrepostos;43 frontend (seis novos). PHPStan/Pint/tipos/formato/lint/build aprovados.67 tabelas QA vazias. Uma mensagem de fila real consumida por outro processo, com ClamD deliberadamente indisponível: inconclusivo, quarentena, original cifrado intacto,zero temporários e incidente próprio.85 recibos/351 provas preservados;14 provas novas. Recibo scan_technical_incidents_increment_20261103. Parcial local,zero escrita/migração activa.
+
+Origem e fronteira: continuação da decisão expressa «Perfil próprio de Suporte técnico» e do saldo de scans/workers já registado. Reutilizados papel, grants efectivos por organização/tipo, fila, avisos e tratamento existentes. Não foram atribuídos acessos adicionais a ficheiros, competência de aprovação, destinatários externos, SLA ou canais. A repetição de análises continua sujeita a DocumentManagementAccess e ao controlador existente; ser Suporte técnico não concede essa competência.
+
+Despacho após confirmação: OpportunityScanDispatch regista o callback afterCommit, incluindo quando existe uma transacção exterior. Rollback não envia trabalho. O contexto mínimo é capturado dentro da transacção autorizada que guarda o recurso/derivada e o novo estado da oportunidade. Falha de transporte ou confirmação tardia deixa o recurso já gravado disponível no seu percurso normal, com incidente separado; apenas documento ainda pending pode passar a failed/quarantined. Documento já clean, infected, scanning ou deleted não é sobrescrito pelo catch de envio. O caso síncrono que executa a análise e depois perde a confirmação da fila mantém clean/active e o histórico único. Não há repetição automática da operação de investimento.
+
+Autoria e privacidade: raízes de sistema usam actor_user_id null e reported_for_user_id para identificar a conta que iniciou o recurso, sem fazer o sistema passar por essa pessoa. Identificador de execução serve de referência idempotente; fases repetidas confirmam a primeira raiz compatível sem duplicar ou reescrever o primeiro facto. Registam-se apenas oportunidade, organização/tipo, versões/estado, operação e código técnico permitido. SQL, excepção, nomes, bytes, títulos e payloads não entram no incidente. O autor só lê incidentes atribuídos à sua conta com acesso actual e correspondência entre organização/tipo capturados e actuais. Transferir o contexto oculta a raiz antiga sem a apagar. Suporte mantém os mesmos limites. Contextos antigos sem proveniência suficiente continuam a analisar normalmente sem inventar destinatário de oportunidade.
+
+Tentativas sem migração: DocumentScanAttempts reutiliza audit_events e documents.malware_scan_attempts. A aquisição sob lock regista execução, entrega, contador e hash/tamanho efectivamente utilizados. A gravação final só pertence à mesma execução/entrega/contador ainda em scanning. Um callback antigo é registado como descartado e não altera o documento nem cria um resultado de malware enganador. O histórico guarda o descritor dos bytes tentados, mesmo se o cabeçalho entretanto mudou; mudança de hash produz inconclusivo em vez de libertar ficheiro. Resultado normal concluído impede repetir a mesma execução; falha terminal assinalada como repetível permite a repetição explícita prevista pelo motor. Não são inventadas aprovações nem alterados tries3, timeout150, uniqueFor600 e backoff15/60 existentes.
+
+Compatibilidade e falhas terminais: campos novos têm defaults para payloads serializados antes do incremento. Quando não existe executionId, o job usa o UUID da mensagem real. Conferido no Laravel instalado que o callback failed recebe a instância de fila numa nova desserialização; os testes usam payload antigo real e callback novo com UUID correspondente. Uma falha antiga não sobrepõe análise posterior, estado clean/infected ou descriptor actualizado. Falha genérica terminal usa scan_failed_after_retries/engine unknown; hash divergente antes da execução usa not_run. Não se atribui falsamente todo o erro ao ClamAV. Workers já em execução com código antigo precisam de drenagem/reinício na entrega; o código novo não actualiza processos antigos em memória.
+
+Temporários e bytes: escrita privada verifica permissões0600 e número de bytes escrito, elimina o temporário no finally e conserva o erro principal caso a limpeza também falhe. Aviso sanitizado distingue limpeza não confirmada. Inconclusivo mantém quarentena; infectado é resultado de segurança válido, sem incidente técnico por esse simples facto. Falha a guardar telemetria não liberta o documento. Originais cifrados e histórico permanecem preservados.
+
+Interface: operação comum «Análise de segurança de documento» e fases de envio, resultado inconclusivo, falha de worker e limpeza não confirmada aparecem nos cartões, fila e ficha pelos mesmos rótulos. Código desconhecido tem mensagem genérica e não é mostrado como texto técnico cru. O cartão esclarece que o recurso já foi registado e orienta a acompanhar o estado antes de pedir nova análise. A ficha mantém comandos, versões, chaves e protecção de preparações existentes. Não há envio automático de mensagens externas nem nova concessão de leitura do original.
+
+Prova operacional delimitada: scan_worker_operational_20261103_test foi clonada vazia na instância isolada55441/investmoz_test, com três contas sintéticas e fila exclusiva scan-worker-20261103-test. O serviço real de recursos gravou PDF cifrado e uma mensagem na tabela jobs. Outro processo PHP (worker6412, produtor29712) consumiu essa mensagem com queue:work --once e fornecedor ClamD real deliberadamente indisponível em127.0.0.1:1. Resultado único inconclusive/scanner_unavailable/ClamAV, documento em quarentena, tentativa1, uma raiz de sistema, original cifrado com mesmo hash,zero temporários, fila vazia e failed_jobs0. Consulta do autor e fila/aviso do suporte no âmbito foram confirmadas. A comparação das190 tabelas só encontrou diferenças em audit_events,document_malware_scans,documents,jobs. Owners e16 tabelas RLS existentes preservados; o snapshot declara explicitamente a identidade superuser/bypass de QA. O fingerprint do candidato é 6ec833fd7d1b56890fa55566c66bf63b203681e34aa44186efa021f600fdff78. A guarda recusou reinicializar esta base/prova existente. Isto demonstra um consumo real em processo separado com indisponibilidade controlada, não engine saudável, certificado clean, carga, corrida entre dois workers ou instalação activa.
+
+Validações:42 Feature/574 iniciais incluíram14 casos novos,cinco de recursos,oito de incidentes de recursos,oito de tratamento e sete de avisos. A ronda final30/365 acrescentou o15.º caso novo e verificou os15 novos,cinco de recursos e dez do instalador com fontes finais congeladas. São rondas sobrepostas, não72 casos distintos. Os43 frontend incluem seis novos e37 anteriores. PHPStan nível7 em sete fontes de aplicação sem supressões, Pint em oito fontes PHP, tipos globais, formato/lint em seis fontes e build passaram. Um erro inicial de carregamento da fixture por colisão com PHPUnit::result final foi corrigido renomeando o helper; o diagnóstico foi preservado e não contado como teste aprovado. GD foi carregado apenas no processo CLI de QA como no incremento anterior, sem mudar a configuração activa. As67 tabelas de ensaio terminaram vazias, com lock, owner, RLS/FORCE e identidade conferidos.85 recibos/351 provas anteriores preservados e14 novas provas arquivadas. Não se repetiu a ronda integral1545 histórica nem se declara aceitação visual/browser ou por utilizadores reais.
+
+Saldo e próxima acção: AUD-PROFILE-20 continua parcial. Não há outbox transaccional ou garantia de entrega exactamente uma vez; permanece a janela de crash entre commit e envio e o comportamento do lease de unicidade quando o transporte é incerto. A prova de um worker não demonstra saúde contínua da fila/engine, todos os módulos sem contexto, falhas de todas as integrações ou concorrência física. Reconciliação de bytes retidos, disponibilidade GD no destino, retoma durável de formulários, backup/restauro do candidato final, instalação autenticada e validação visual continuam no saldo. O restauro anterior pertence ao candidato arquivado. Nenhuma migração, escrita activa ou comunicação externa. Continuar a fiabilidade do despacho e saúde operacional pelos mecanismos e permissões existentes, sem atribuir poderes de nova análise ao suporte por inferência.
+
+### 03/11/2026 — AUD-PROFILE-20: repetição de análises e confirmação efectiva do envio
+
+[SCAN-RETRY-20261103] Repetição da análise distingue aceite, reserva existente, contexto alterado, envio não confirmado e envio diferido. Reserva existente não altera o documento nem duplica o pedido; falha tardia não sobrepõe clean/infected/scanning. Mesma autoridade documental, revalidada após commit, com auditoria da preparação e original preservado. Botão dos anexos de zonas usa resposta Inertia; avisos aparecem também na gestão documental.36 Feature/378 asserções (11 novos,15 de scans,dez do instalador),24/228 iniciais sobrepostos e47 frontend (quatro novos),PHPStan/Pint/tipos/formato/lint/build aprovados.69 tabelas QA vazias. Ensaio com reserva em cache PostgreSQL e fila reais: segundo pedido preservou190 tabelas; outro processo consumiu uma mensagem e libertou a reserva do seu dono. ClamD deliberadamente indisponível manteve quarentena, cifra e histórico,zero temporários.86 recibos/365 provas preservados;14 novas provas. Recibo scan_retry_increment_20261103. Parcial local,zero escrita/migração activa.
+
+Causa delimitada: DocumentMalwareController colocava pending antes de ScanDocumentForMalware::dispatch(...)->afterCommit e mostrava sempre «Nova análise colocada na fila». O Laravel instalado pode recusar esse dispatch por um lease ShouldBeUnique já existente; o PendingDispatch não devolve esse resultado ao controlador. Assim, um documento inconclusivo/falhado podia perder o seu estado apesar de nenhum novo pedido ser enviado. Além disso, o botão de repetição nos anexos de zonas usava api/fetch JSON contra um endpoint que devolvia redireccionamento. A shell de gestão documental só apresentava flash.success, ocultando avisos. São defeitos técnicos dos percursos existentes, sem nova decisão organizacional necessária.
+
+Reutilização do motor: DocumentScanDelivery usa o UniqueLock e Dispatcher do próprio Laravel, preservando o mesmo identificador por documento, owner do lease, TTL600, tries3, timeout150 e backoff15/60. O adapter torna observáveis accepted/duplicate/stale e limpa o contexto oculto da fila no finally, inclusive se o transporte lançar excepção. Só liberta o próprio lease quando nenhuma entrega foi tentada; uma falha de confirmação depois da chamada ao transporte conserva-o, pois a mensagem pode já ter sido aceite. O worker conserva a libertação pelo owner prevista no Laravel. Não se força desbloqueio para permitir um segundo envio e não se infere existência de job vivo/engine saudável a partir de uma reserva. OpportunityScanDispatch usa este mesmo adapter; incidentes de recursos, autor e Suporte continuam pelos mecanismos anteriores.
+
+Repetição autorizada: DocumentScanRetry valida inicialmente a autoridade DocumentManagementAccess e os estados pending/inconclusive/failed, mantendo404/403/422 usuais. Regista afterCommit; rollback exterior descarta o callback sem tocar no documento, auditar preparação ou enviar. No callback, só depois de adquirir o lease, volta a consultar a pessoa e o âmbito documental efectivo, bloqueia a linha e confere hash, estado de scan, contador e updated_at contra o exemplar autorizado. Mudança de acesso ou exemplar resulta stale, sem reset nem envio, libertando apenas o lease adquirido por esse callback. A mesma transacção guarda pending/quarantined e scan_retry_requested com actor, documento, referência UUID e estado anterior. Uma reserva já existente nem sequer executa esta preparação e conserva todos os campos e histórico.
+
+Falhas e resultados posteriores: a chamada ao transporte só ocorre depois de a preparação ser confirmada. Falha ou confirmação perdida devolve unconfirmed, com referência segura e aviso para consultar o estado antes de repetir. Só documento ainda pending, não excluído, com o mesmo hash e contador, pode ser marcado failed/quarantined pelo catch. Scan já clean/active, infected, scanning ou resultado posterior não é substituído. Os testes executam realmente um CleanScannerFixture no dispatch e depois injectam perda de confirmação: uma história clean, original cifrado intacto e estado active permanecem. Essa fixture sintética não certifica ficheiros reais. Se a própria persistência/verificação estiver incerta, conserva-se privacidade e aviso sanitizado; não se declara um resultado de malware que não foi obtido.
+
+Respostas e interface: HTML/Inertia usa success apenas para aceitação pelo serviço de envio, sem prometer execução. Duplicate explica «reserva de análise» e ausência de outro pedido; stale pede actualizar o estado; unconfirmed mostra referência; deferred descreve o envio após confirmação da gravação, sem inventar confirmação antecipada. A variante JSON responde com outcome/reference/message e no-store,503 só para envio não confirmado, sem redireccionamento ou texto da excepção. Gestão documental mostra warning como alerta preservando conteúdo e success como status. Nos anexos das zonas, o botão usa router.post, mantém scroll, controla busy e mostra erro de validação/revisão; o flash é apresentado pela Frame existente. A consulta pública não ganha botão de repetição. Não foram criadas perguntas, motivos redundantes ou novos formulários.
+
+Âmbito de autoridade: mantém-se a gestão documental já existente; o perfil Suporte técnico, mesmo atribuído, não ganha competência de pedir uma nova análise, ler ficheiros ou aprovar investimentos. O pedido manual é genérico por document_id e não presume uma oportunidade ou destinatário a partir de ligações possivelmente múltiplas/antigas. A auditoria tem a referência do pedido e o aviso técnico sanitizado; contexto de oportunidade não é inventado. A captura aprovada para recursos de oportunidades e os seus incidentes continua independente. Atribuir contexto e destinatário a outras origens só pode reutilizar referências/autorização efectivas desses percursos.
+
+Prova operacional actual: scan_retry_operational_20261103_test foi clonada vazia da QA isolada, com uma conta sintética de gestor e um PDF cifrado sintético. O serviço de repetição criou uma mensagem na fila exclusiva scan-retry-20261103-test e uma reserva real em cache_locks PostgreSQL; conferido uniqueLockOwner do payload igual ao owner guardado. O segundo pedido devolveu duplicate e conservou exactamente os snapshots de todas as190 tabelas. O processo worker25960, distinto do produtor25340, consumiu a mensagem real e removeu o lease do seu dono: jobs0,failed_jobs0,cache_locks0. O ClamD real deliberadamente indisponível em127.0.0.1:1 produziu um único inconclusive/scanner_unavailable/ClamAV e quarentena, com tentativa1, auditoria de pedido/início/fim, cifra original com mesmo hash e zero temporários. Sem contexto de oportunidade, nenhuma raiz de incidente de oportunidade foi inventada. Entre preparação e fim, só audit_events,cache_locks,document_malware_scans,documents,jobs mudaram. Conferidos owners e RLS/FORCE; snapshot declara a identidade superuser/bypass de QA e conserva16 tabelas RLS existentes. Candidato 4a8835aaa62c85224092faa7109f88ea67f9f860ba6d857fa13f838bb6b5e6f5. A guarda recusou reinicializar a base/prova já existente. A prova anterior de um worker fica histórica para o fingerprint anterior.
+
+Validação e preservação:36 Feature/378 finais incluem11 novos de repetição,15 de scans e dez do instalador autenticado com as fontes congeladas. Os24/228 iniciais abrangiam nove novos e os15 de scans; são rondas sobrepostas, não60 casos distintos. Os47 frontend incluem quatro novos de shell/transportes e43 anteriores. PHPStan nível7 em cinco fontes de aplicação sem supressões, Pint em seis fontes PHP, tipos globais, formato/lint em três fontes e build passaram. O fingerprint do instalador inclui os novos serviços, controlador e duas fontes de interface; os dez casos foram aprovados com essa cobertura. QA terminou com69 tabelas vazias, incluindo cache/cache_locks além das67 anteriores, sob lock e owner/RLS/FORCE conferidos. Preservados86 recibos/365 provas anteriores, fontes, originais e percursos,14 provas novas. Não se repetiu a ronda integral1545 histórica nem se declara aceitação visual/browser ou por utilizadores reais.
+
+Saldo e próxima acção: AUD-PROFILE-20 continua parcial. O lease existente não é prova de trabalho vivo e a sua conservação após transporte ambíguo pode impedir outro envio até execução ou expiração. Permanece a janela de crash entre commit e envio; este incremento não implementa outbox transaccional nem entrega exactamente uma vez. Um worker com engine indisponível e um lease em base partilhada não provam concorrência física, carga, engine saudável ou saúde contínua. Subsistem outras integrações/origens, reconciliação de bytes retidos, disponibilidade GD no destino, retoma durável, backup/restauro do candidato final, instalação autenticada e visual. Nenhuma migração, escrita activa ou mensagem externa. Continuar saúde operacional e fiabilidade do despacho, reutilizando os mecanismos e competências existentes.
+
+### 03/11/2026 — AUD-COUNTRY-01/02 e AUD-PROFILE-25: perfil e empresas sem duplicação por repetição
+
+[INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa.
+
+Lacunas verificadas no código: o novo formulário de empresa enviava version0 sem chave de operação; uma repetição após perda de resposta podia criar outra declaração com outro UUID. O perfil tinha verificação de versão mas não recibo repetível. O componente era remontado pela versão e o novo formulário pela quantidade de empresas, podendo apagar preparações por actualizações da página. Os erros apareciam junto ao campo e outra vez no resumo; respostas de até2000 caracteres usavam input de uma linha e alguns limites excediam os do servidor. O critério existente de gravação segura/erros e países permitia corrigir estes defeitos sem criar uma nova regra organizacional.
+
+Um comando por intenção: InvestmentProfileCommands usa a chave UUID opcional e o audit_events existente, no âmbito exclusivo da conta autenticada, sob o lock users já usado pelo controlador. O pedido normalizado identifica operação, alvo, versão de base e payload; fica cifrado no recibo restrito. A ordem das chaves do payload e a caixa do UUID não produzem outro comando. A mesma chave/conteúdo devolve exactamente o ID/versão originais, sem cifrar outra vez, incrementar versão, inserir outra empresa ou repetir o evento de negócio. Chave com conteúdo/alvo/operação diferentes produz409. O replay de uma criação/v1 depois de uma alteração/v2 devolve o recibo/v1 e conserva o registo actual/v2. Permissões e propriedade são conferidas pelo percurso existente; outra conta não consulta nem reutiliza o recibo privado. Declarações com mesmo nome em contas distintas continuam distintas; não se criam organizations ou memberships. A chave é opcional para conservar clientes legados, cujo comportamento anterior não se declara idempotente.
+
+Preparação e confirmação na interface: editor e hook comuns do perfil/declarações congelam a versão, os valores e a chave até confirmar o resultado. Falha de rede/503 ou resposta malformada conserva-os e permite só a repetição explícita do mesmo pedido, sem retry automático ou limpar campos. Repetição de criação recebe o mesmo UUID; só o formulário confirmado é limpo. Uma resposta antiga de outro actor ou componente já desmontado não confirma nem recarrega a sessão actual. Actor está identificado na resposta privada de consulta; API de consulta e página têm no-store/private, e o histórico Inertia da página é cifrado. Esta preparação é memória da página, não retoma durável após fecho/recarregamento/expiração.
+
+Concorrência de versões: chave de montagem passa a identificar conta/empresa, em vez de versão/quantidade. Uma resposta de actualização mantém as edições locais. Se existe versão mais recente, guardar fica suspenso até consulta e comparação explícitas; a leitura não escreve nem substitui valores. A comparação mostra campos divergentes, versão local e guardada, com escolha entre adoptar a versão mantendo a preparação ou carregar os valores guardados mediante confirmação da substituição. Ler um novo exemplar também bloqueia nova escrita até essa escolha, mesmo quando as props da página ainda são antigas. Ler durante um pedido sem resposta não o descarta nem autoriza outra intenção; a confirmação repetível vem primeiro. Depois de validação422, os valores permanecem editáveis e o pedido corrigido recebe nova chave. Sessão/acesso alterados conservam a preparação e exigem consulta no mesmo contexto antes de confirmar.
+
+Formulários e dados: continuam os campos já existentes de contacto, residência, sector, experiência e capacidade; nome/email continuam nas definições da conta. A declaração conserva nome, constituição, registo, sector, relação e descrição, sem assumir representação legal. A residência ISO, país de constituição, país histórico e origem da solicitação permanecem distintos. O histórico livre é transportado sem inferência. País de constituição requerido pelo percurso existente é indicado no selector e o erro legado payload.country fica associado a esse campo, uma só vez. Outros erros por campo também deixam de se repetir no resumo. Telefone30, registo100, sector/função150, experiência/descrição2000 e capacidade1000 correspondem à validação do servidor; textos longos são multilinha. Existe uma guarda de saída para as preparações do perfil/declarações e confirmação ao preparar manifestação por POST quando há dados por guardar, sem múltiplos avisos por formulário.
+
+Prova concorrente delimitada: a base workspace_profile_concurrency_20261103b_test foi clonada vazia na instância55441/investmoz_test, com uma conta sintética. Dois processos PHP distintos,21992 e1848, chamaram o controlador com o mesmo comando de criação. O primeiro adquiriu o lock da linha users; pg_stat_activity confirmou o segundo em espera real por Lock antes do commit. Ambos obtiveram o ID27ec073d-0bb3-4d51-a440-f020145f5424/v1. Comparadas190 tabelas: só audit_events e investment_company_declarations mudaram. Ficaram uma declaração cifrada,um company_declared e um recibo command_applied, sem organização/membership ou outras mutações. Owners e16 tabelas RLS existentes conservados; snapshot declara a identidade superuser/bypass de QA. Estes processos chamam o controlador directamente; o middleware HTTP foi verificado nos Feature, não neste ensaio. A guarda recusou reinicializar a base/prova existente. O ensaio anterior na base sem sufixob fica histórico: após afinar o bloqueio de escrita depois de consultar uma versão nova, repetiu-se a concorrência com as fontes finais congeladas. Os hashes das cinco fontes executáveis constam da prova final.
+
+Validação e diagnósticos:17 Feature/248 finais, com seis novos de comandos e11 existentes de workspace/país organizacional, preservando isolamento, snapshot de submissões e compatibilidade. A ronda inicial17/248 sobrepõe-se à final.60 frontend são13 novos da página real/hook/transporte e47 casos anteriores de suporte, recursos e avisos. Os nove primeiros casos frontend passaram inicialmente; ao acrescentar a confirmação POST, um diagnóstico de59 casos teve58 aprovados e um erro porque a fixture não montava window no evento de clique. Corrigida a fixture, preservado o diagnóstico e acrescentado o13.º caso de adopção explícita de nova versão;60 finais aprovados. PHPStan nível7 em duas fontes de aplicação sem supressões, Pint em três fontes PHP, tipos globais, cinco fontes de formato/lint e build aprovados. Os checks iniciais identificaram uma chamada header não pertencente ao tipo Response do Symfony e uma opção preserveScroll não existente em ReloadOptions do Inertia actual; corrigidas as APIs reais, sem casts/supressões. Documentação primária do identificador PHPStan consultada. Não se repetiu a ronda integral1545 histórica nem se afirma aceitação visual/browser ou por pessoas reais.
+
+Preservação e saldo: QA terminou com79 tabelas vazias, incluindo agora as colecções do workspace e eventos, com lock, identidade, owner/RLS/FORCE conferidos.87 recibos/379 provas anteriores mantidos e16 provas novas arquivadas. Nenhuma tabela/migração nova, escrita activa ou comunicação externa. AUD-COUNTRY-01/02 e AUD-PROFILE-25 continuam parciais: o editor do cadastro mestre de país organizacional mantém o seu percurso separado, cuja recuperação/repetição integral ainda deve ser tratada; as contas registadas não ganham uma pergunta de residência na autenticação simples. Persistem outros formulários/perfis/consumidores, retoma durável, expiração, visual/móvel/browser, país real autorizado da organização onde ainda não preenchido, backup/restauro do candidato e disponibilização autenticada. Preservam-se as fontes e provas anteriores, sem pedir novamente decisões/cadastros já confirmados. Próxima acção: continuar a recuperação do editor organizacional e os consumidores restantes, com a mesma fonte única e permissões existentes.
+
+### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: editor organizacional com confirmação e recuperação
+
+[ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa.
+
+Origem e lacuna: continuação do saldo do perfil/empresas anterior. O editor do país organizacional ainda era remontado pela versão e enviava PUT sem recibo de comando, não permitindo confirmar uma gravação após perder a resposta. A correcção reutiliza InvestmentProfileCommands e useInvestmentProfileEditor, CountryCatalogue/CountrySelect, a versão e o cadastro organizations existentes. Mantém-se o país de constituição distinto da residência, país histórico e origem da solicitação. Não se cria organização ou representação por nome, não se preenche o país real da Tempo por inferência e não se exige nova validação genérica das fontes já aceites.
+
+Servidor e recibo: OrganizationCountry aceita operation_key UUID opcional, mantendo clientes legados. Bloqueia a pessoa, os seus vínculos existentes e a organização; verifica novamente a autorização depois de adquirir o lock da organização, cobrindo uma exclusão lógica enquanto aguardava. Só a representação activa com a competência já existente e sem restrição de Auditor pode gravar ou obter confirmação repetida. O comando identifica operação organization_country, organização, versão, país e referência exactos. O mesmo conteúdo/chave devolve a versão/país originais, sem outra actualização, timestamp de proveniência ou evento de negócio. Mudança de país, referência, alvo ou operação com a chave usada dá409. Replay depois de uma alteração posterior conserva o registo actual, devolvendo apenas o recibo original. A mesma transacção mantém o histórico de antes/depois cifrado e o recibo cifrado no audit_events já existente; a chave não constitui nova autorização.
+
+Interface comum: o editor deixa de usar a versão como chave de montagem e mantém o país/referência enquanto compara novos dados. Perda de resposta ou confirmação inválida congela a intenção original e permite repetir explicitamente esse pedido. A resposta tem de corresponder à versão seguinte e ao país enviado para ser aceite. A consulta não escreve, não limpa a preparação nem cria outra intenção. Leituras rápidas partilham um pedido em curso; guardar/adoptar respeitam a leitura ainda activa. Depois de consultar uma versão diferente, é preciso adoptar explicitamente a versão mantendo a preparação ou carregar os dados guardados mediante confirmação de substituição. Campos e erros continuam identificados, com cada erro mostrado uma vez, referência entre5 e2000 caracteres e país ISO obrigatório conforme o servidor existente.
+
+Representação actual e recuperação: consulta sem competência de escrita mostra os valores com os campos desabilitados e sem comando de gravação. O método do hook também recusa submissão directa nesse estado. A leitura recente pode retirar a possibilidade de repetir um pedido ainda incerto se a representação foi revogada; os campos preparados permanecem na página. Se o vínculo é restabelecido e uma nova consulta no mesmo actor/organização confirma escrita, o editor permite voltar a confirmar/editar após a escolha adequada, mesmo que as props antigas da página ainda sejam de leitura. Essa permissão consultada só prevalece enquanto a base das props é a mesma; nova versão/permissão da página volta a ser considerada. Todas as escritas e replays continuam sujeitos à autorização do servidor. O editor integra a única guarda de saída da página, juntamente com perfil/declarações. Mudança de conta desmonta a preparação antiga; não se declara retoma durável após navegação, recarregamento ou expiração.
+
+Histórico e reutilização: conservados source_system, external_id, versão e proveniência da organização, a marca de declaração do representante e o histórico cifrado antes/depois. Os testes anteriores de país mestre e workspace continuam a provar que mudar o mestre não altera declarações/submissões anteriores ou a residência. A reutilização do país para uma declaração continua a ser uma operação explícita separada; o botão não passa a copiar alterações do mestre automaticamente. A recuperação/idempotência desse botão permanece no saldo próprio. Não houve instalação de extensão, migração nova, alteração de flags ou concessão de perfil neste incremento.
+
+Concorrência real delimitada: organization_country_editor_20261103_test foi clonada vazia na instância55441/investmoz_test, com duas contas e dois vínculos sintéticos de officer na mesma organização. Os processos 22568 e 28816 enviaram comandos distintos sobre a versão1. O primeiro reteve a linha de organização; pg_stat_activity confirmou o segundo em espera real por Lock. O primeiro guardou FR/v2 e a sua referência; o segundo recebeu409 ao adquirir o lock, sem substituir o país nem a proveniência. Na comparação de190 tabelas, só audit_events e organizations mudaram: uma organização,um evento de país e um recibo de comando cifrado. Decifrados e conferidos actor/alvo/versão/país/referência do comando, sem texto da referência na raiz do recibo. Owners e16 tabelas RLS existentes conservados; o snapshot declara a identidade superuser/bypass de QA. As cinco fontes executáveis estão ligadas por hash ao candidato final. A guarda recusou reinicializar a base/prova existente. Os processos chamam o controlador directamente; middleware HTTP e repetição do comando estão nos Feature. Este ensaio não prova todas as intercalações, carga ou aceitação por pessoas reais.
+
+Verificações e diagnóstico corrigido:23 Feature/295 finais, com seis novos de comandos organizacionais e17 existentes do país/workspace/perfil. A primeira ronda22/288 passou antes do sexto caso. Um ensaio posterior23/288 teve22 aprovados e um erro na nova fixture: tentou inserir dois vínculos activos da mesma conta/organização. O índice parcial imz_memberships_user_id_organization_id_uq já impede isso; a hipótese de defeito por primeiro vínculo foi retirada e a leitura de represented mantida como estava. O caso final muda o papel do vínculo único e verifica a mesma competência na consulta e na escrita. Não se alterou ou enfraqueceu o índice. Diagnóstico preservado.69 frontend finais incluem nove novos e60 anteriores;20 iniciais cobriam os sete primeiros novos e13 do perfil. Acrescentados o bloqueio de leituras simultâneas e a recuperação de permissão restabelecida. PHPStan nível7 em duas fontes sem supressões, Pint em duas fontes PHP, tipos globais, cinco fontes de formato/lint e build passaram. O primeiro build ficou arquivado antes do ajuste final da recuperação de permissão; a compilação final cobre esse ajuste. Não se repetiu a ronda integral1545 histórica nem se afirma aceitação visual/browser.
+
+Preservação e próxima acção:79 tabelas de QA terminaram vazias, com lock, identidade, owner/RLS/FORCE conferidos. Mantidos88 recibos/395 provas anteriores e arquivadas16 novas. Nenhuma migração/escrita activa ou comunicação externa. AUD-COUNTRY-02 e AUD-PROFILE-25 continuam parciais: restam o botão de reutilização do país, outros consumidores/perfis, retoma durável/expiração, visual/móvel, preenchimento real autorizado onde falta país, backup/restauro do candidato e disponibilização autenticada. Os pedidos legados sem chave conservam a semântica anterior e não são declarados idempotentes. Continuar a reutilização explícita e os consumidores restantes, preservando a fonte única e os limites de representação existentes.
+
+### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: reutilização de país com pré-visualização e confirmação repetível
+
+[ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa.
+
+Lacuna e origem: continuação do saldo explícito do editor organizacional. O botão anterior enviava directamente a reutilização, sem consulta actual, chave de operação ou recuperação de resposta perdida, e podia ser accionado enquanto havia edições privadas no mesmo formulário. A correcção reutiliza a operação, fonte, versões e propriedade já existentes; não acrescenta nome, NUIT, país, referência ou comprovativo para voltar a preencher. O país continua a ser lido da organização autorizada e copiado explicitamente, sem identificar ou fundir entidades por igualdade de nome.
+
+Servidor: o pedido opcionalmente identificado por UUID bloqueia a pessoa, a declaração privada e a fonte; readableSnapshot bloqueia a representação e a organização, conferindo novamente o acesso depois da espera. A leitura basta para reutilizar: viewer conserva a operação de leitura existente e não ganha edição do mestre. A propriedade da declaração e a representação actual são exigidas antes de devolver um recibo. O comando liga a operação organization_country_reuse, alvo, versão da declaração, organização e versão da fonte. Repetição da mesma intenção devolve a versão/país originais, sem alterar cifra, reused_at, proveniência, versão ou auditoria outra vez. Chave com outro alvo/fonte/versão/operação dá409. IDs da fonte e alvo são os UUIDs guardados, incluindo quando o cliente usou maiúsculas; nomes não participam na correspondência.
+
+Fonte e histórico: um replay autorizado continua a recuperar o país da primeira cópia mesmo que a fonte ou a declaração tenham sido alteradas depois, ou que o país actual da fonte esteja em falta. Isso confirma o pedido histórico e não volta a copiar o valor antigo sobre o registo actual. Nova reutilização exige as versões actuais e país informado. O antes/depois e a cópia identificada mantêm a informação utilizada; as manifestações anteriores conservam os valores e snapshots originais, e novas manifestações recebem a declaração efectivamente guardada. Residência, constituição, país histórico e origem permanecem separados. O país é obtido no servidor, sem aceitar um país ou snapshot fabricados no corpo do cliente.
+
+Privacidade e atomicidade: InvestmentProfileCommands conserva os recibos anteriores em result e suporta result_encrypted para o resultado que contém país. Intenção e resultado da reutilização ficam cifrados no recibo restrito, mantendo compatibilidade de leitura com os recibos antigos. O JSON de confirmação tem no-store/private. Injectada uma falha de persistência no recibo dentro da QA: o503 sanitizado não expôs SQLSTATE e reverteu em conjunto a actualização da declaração e o evento de negócio. A consulta final confirmou a ausência da constraint temporária e a manutenção do índice parcial imz_memberships_user_id_organization_id_uq. Nenhuma tabela/migração nova ou guarda funcional foi removida.
+
+Interface: um painel dentro do editor da declaração consulta a página privada actual e apresenta país da declaração, país a copiar, organização, versão e referência guardada. Só a confirmação explícita envia POST. Não se permite copiar sobre edições por guardar, leitura/gravação em curso, conflito ou outro pedido incerto da mesma declaração. O editor partilha um mutex com a reutilização e a guarda única de saída da página. Durante envio incerto, os campos ficam conservados e a repetição mantém exactamente a chave e as duas versões; fonte alterada entretanto não muda esse comando. Consultar o estado não confirma por semelhança de valores nem prepara outra cópia. Depois de confirmação válida, actualiza-se apenas o país na preparação previamente sem edições, conservando os outros campos e recarregando a cópia identificada. Uma resposta inválida ou de outra conta não limpa/confirma a preparação.
+
+Comparação e recuperação: uma fonte mais recente já conhecida na página bloqueia a pré-visualização antiga; fonte obtida numa consulta mais recente pode ser apresentada mesmo com props antigas, até se conhecer outra alteração. Mudança da declaração detectada durante consulta encaminha para a comparação do formulário, sem escrever.409/422 conservam os valores e exigem nova consulta/intenção; falha sem confirmação conserva o pedido. Falta de sessão/acesso impede repetição até consulta no mesmo actor e organização confirmar o contexto de leitura restabelecido. A preparação continua em memória da página, com aviso de saída, sem promessa de retoma durável após fechar/recarregar/autenticar-se.
+
+Prova concorrente real: organization_country_reuse_20261103_test foi clonada vazia na instância55441/investmoz_test. Uma conta sintética, com vínculo viewer, reutilizou a fonte FR/v3 para a sua declaração MZ/v1. Os processos 12544 e 1808 enviaram o mesmo comando; pg_stat_activity confirmou espera real pelo lock da pessoa. Ambos receberam version2/countryFR e no-store, mas ficou uma só alteração da declaração,um evento de reutilização e um recibo. O payload actual é exactamente a cifra do primeiro after_payload; a cópia conserva organização/v3, referência, actor e reused_at iniciais. Comando e resultado foram decifrados/conferidos na prova; não houve recifra ou outra cópia no replay. Entre190 tabelas, só audit_events e investment_company_declarations mudaram; fonte, vínculo e restantes dados ficaram iguais. Owners e16 tabelas RLS existentes preservados; o snapshot declara a identidade superuser/bypass da QA. Oito fontes executáveis estão ligadas por hash ao candidato. A guarda recusou reinicializar a base/prova. Os processos chamam o controlador; middleware HTTP é prova separada nos Feature, sem afirmar carga ou todas as intercalações.
+
+Validação e diagnósticos:29 Feature/364 finais, com seis novos de reutilização e23 anteriores de comandos organizacionais, país, perfil e workspace. A primeira ronda teve29 casos,27 aprovados,duas falhas e349 asserções. Uma repetição com UUIDs em maiúsculas encontrou intenção diferente porque a cópia ainda usava o argumento textual da organização: corrigido para o ID canónico do registo, sem reescrever snapshots históricos. O teste de falha esperava500, mas o tratamento existente devolve503 sanitizado; corrigida essa expectativa e verificados rollback e ausência de SQL na resposta. Diagnóstico preservado.79 frontend finais incluem dez novos e69 anteriores;32 iniciais cobriam os dez novos e22 do perfil/editor. PHPStan nível7 em três fontes sem supressões, Pint em quatro fontes PHP, tipos globais, sete fontes de formato/lint e build aprovados. A ronda integral1545 continua histórica, e não se afirma aceitação visual/browser ou por pessoas reais.
+
+Rastreabilidade dos executores: o recibo anterior organization_country_editor_increment_20261103 conservava na lista tooling_sha256 nomes de helpers da etapa workspace, por uma cópia de metadados. Mantêm-se esse recibo e todas as suas provas exactamente como estavam. Este incremento acrescenta prior_tooling_supplement_sha256 para os ficheiros efectivamente usados e retidos de check-organization-country-editor-qa, verify-organization-country-editor-concurrency e record-organization-country-editor, e liga os próprios executores actuais pelos caminhos correctos, incluindo este recorder. A suplementação de rastreabilidade não altera os resultados, fontes, observações de concorrência ou estado de instalação anteriores.
+
+Preservação e próxima acção:79 tabelas de teste vazias, lock/identidade/owner/RLS/FORCE conferidos e fixture de falha revertida.89 recibos/411 provas anteriores preservados e16 novas provas arquivadas. Nenhuma migração/escrita activa ou comunicação externa. AUD-COUNTRY-02 e AUD-PROFILE-25 continuam parciais: clientes legados sem chave mantêm semântica anterior; restam outros consumidores/perfis, retoma durável/expiração, visual/móvel/browser, preenchimento real autorizado onde falta país, backup/restauro do candidato e disponibilização autenticada. A fonte aprovada não volta a ser submetida a uma validação genérica nem se inventam representantes. Próxima acção: confrontar os consumidores restantes e a recuperação de preparações com a matriz, reutilizando os mecanismos agora comuns.
diff --git a/docs/investmoz/v2/auditoria-portal/backlog.md b/docs/investmoz/v2/auditoria-portal/backlog.md
index 532cabce..7ccebf60 100644
--- a/docs/investmoz/v2/auditoria-portal/backlog.md
+++ b/docs/investmoz/v2/auditoria-portal/backlog.md
@@ -1046,17 +1046,17 @@ A fonte única continua `matriz-requisitos.csv`; `backlog-priorizado.csv` tem os
### Incrementos novos não iniciados nesta auditoria
-- **AUD-EDU-02 — Rascunho incompleto privado de procura e capacidade**: Procura/capacidade não têm rascunho incompleto recuperável. Preparar implementação separada, sem acrescentar jornadas nesta auditoria. Reutilizar: Education Controller, Labour Demand, Training Capacity, atores existentes. 16–32 h de implementação/ensaio, após 2–4 h de definição dos campos; não inclui novas jornadas. Fonte/secção e aceitação completas na linha existente.
+- **AUD-EDU-02 — Rascunho incompleto privado de procura e capacidade**: Parcial local, já implementado nos incrementos de AUD-EDU-01: núcleo, interface/snapshot e concorrência. Reutilizadas 14 Feature/333 asserções, cinco frontend e dez cenários concorrentes, com hashes conferidos. Restam visual e disponibilização; jornadas/painéis restantes são AUD-EDU-03/01. Não criar outro motor ou contar este desenvolvimento como ausente; recibos existentes de Educação e reconciliação de02/11 no manual.
- **AUD-EDU-03 — Jornadas e painéis educativos por ator**: Painéis e jornadas educativos completos por ator não implementados. Reutilizar: Catálogo, entidades e políticas educativas existentes. 24–48 h após definição das jornadas; estimativa conjunta, não somar por parágrafo. Fonte/secção e aceitação completas na linha existente.
- **AUD-PROFILE-20 — Suporte técnico, incidentes e preservação da submissão**: Suporte/incidentes por perfil com recuperação e alertas próprios não implementado integralmente; falhas técnicas worker/upload anteriores são provas específicas, não o módulo de suporte. Reutilizar: Opportunity Management, Opportunity Canonical Contract/Response, Opportunity Review Materiality, PortalProfileAccess, Opportunity Resources. 2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa. Fonte/secção e aceitação completas na linha existente.
-- **AUD-MARKET-01 — Negócios similares por área, raio, sector e classificação, com fonte, data e cobertura**: Consulta de negócios similares por raio/classificação não implementada. Reutilizar: Existing Business, Investment Geography e taxonomias existentes. 24–40 h após dados georreferenciados e regras de distância definidos. Fonte/secção e aceitação completas na linha existente.
-- **AUD-ESTABLISHMENT-01 — Importar empresas licenciadas e empreendimentos turísticos com normalização, correspondências e rejeições, sem duplicações**: Importador reconciliado de empresas licenciadas/empreendimentos não implementado. Reutilizar: Importadores autenticados, organizations, cadastros existentes e hashes. 24–48 h por formato aprovado; acesso ao ficheiro e identificadores são pré-condições. Fonte/secção e aceitação completas na linha existente.
+- **AUD-MARKET-01 — Negócios similares por área, raio, sector e classificação, com fonte, data e cobertura**: Parcial local em02/11/2026: pesquisa e alimentação do ponto pelo mesmo formulário/revisão/publicação, com fonte e histórico (28 Feature/677 e 17 frontend). Restam cobertura real, visual e destino; recibo business_point_publication_increment_20261102. Competências e edição de anúncios publicados mantidas; orçamento histórico não é estimativa nova do saldo.
+- **AUD-ESTABLISHMENT-01 — Importar empresas licenciadas e empreendimentos turísticos com normalização, correspondências e rejeições, sem duplicações**: Parcial: lote privado específico já entregue em28/10 e provas preservadas; em02/11, consulta de fontes/linhas e pendências, sem consolidação automática. Nove Feature/138 asserções e seis frontend; recibo proactive_supply_review_increment_20261102. Restam reconciliação de entidades, outros formatos/lotes e visual/disponibilização do delta; não voltar a orçamentar o lote concluído como ausente.
- **AUD-FUND-01 — Catálogo de fundos nacionais e territoriais com elegibilidade explicada e atualização**: Catálogo de fundos com janelas e elegibilidade não implementado; ofertas experimentais não o substituem. Reutilizar: Biblioteca, taxonomias, fontes e filtros comuns. 16–32 h após inventário de fontes e campos; atualização operacional a definir pela Tempo. Fonte/secção e aceitação completas na linha existente.
-- **AUD-COMPANY-01 — Comparador de forma societária orientado por perguntas, com fundamento, alternativas e limites**: Comparador societário orientado por perguntas não implementado. Reutilizar: Roteiro societário, biblioteca e motor de regras existentes. 24–48 h, excluindo inventário legal ainda por associar; fontes oficiais já aceites. Fonte/secção e aceitação completas na linha existente.
-- **AUD-COMPANY-02 — Modelos versionados de estatutos e contratos sociais por forma jurídica, com finalidade e limitações**: Modelos societários específicos ainda sem exemplares/URLs recuperáveis identificados; não confundir biblioteca genérica com entrega destes modelos. Reutilizar: Biblioteca/versionamento/documentos originais. 8–16 h de reconciliação documental; estimar adaptação só depois de localizar os exemplares. Fonte/secção e aceitação completas na linha existente.
-- **AUD-CAPITAL-01 — Orientação sobre private equity e capitalização, preparação, riscos, documentos e percurso**: Guião estruturado de capitalização não implementado. Reutilizar: Biblioteca e passos existentes do percurso. 16–24 h após conteúdo/âmbito definidos; não inclui intermediação. Fonte/secção e aceitação completas na linha existente.
-- **AUD-CAPITAL-02 — Guião de admissão à Bolsa de Valores de Moçambique, distinguindo Bolsa, regulador e operadores**: Guião da Bolsa por segmento, intervenientes e requisitos não implementado. Reutilizar: Biblioteca, checklist e percurso existentes. 16–32 h após correspondências normativas; não preencher taxas/prazos ausentes. Fonte/secção e aceitação completas na linha existente.
-- **AUD-CHECKLIST-01 — Editor de checklists e formulários configuráveis, publicação de versões e preservação de submissões anteriores**: Checklists existem em configuração; editor/versionamento administrativo sem código e adaptação de submissões antigas não demonstrados. Reutilizar: Configurações existentes, schema, biblioteca e auditoria. 24–40 h após política de alteração; reaproveitar motor, sem catálogo paralelo. Fonte/secção e aceitação completas na linha existente.
+- **AUD-COMPANY-01 — Comparador de forma societária orientado por perguntas, com fundamento, alternativas e limites**: Parcial local: consulta pública e perguntas ligadas ao dossier, alternativas/fundamentos da edição legal citada, correcção, histórico cifrado e transporte de respostas; 14 Feature/385 e seis frontend. Recibo company_comparison_increment_20261102. Restam casos especiais/redacções adicionais, visual/login real e disponibilização; AUD-COMPANY-02 conserva os modelos. Não contar o comparador já desenvolvido como ausente.
+- **AUD-COMPANY-02 — Modelos versionados de estatutos e contratos sociais por forma jurídica, com finalidade e limitações**: Parcial local: formulário factual privado de sete secções, origens autorizadas, capital exacto, histórico cifrado e recuperação de conflitos; 18 Feature/343 e12 frontend. Recibo company_preparation_increment_20261102. Sete exemplares/URLs ainda não fornecidos, conforme resposta do proprietário; faltam biblioteca específica, derivadas contratuais, revisão/assinatura/submissão/registo, visual e destino. A ficha não é contrato e a entrega anterior do comparador mantém-se.
+- **AUD-CAPITAL-01 — Orientação sobre private equity e capitalização, preparação, riscos, documentos e percurso**: Parcial local: guia público de quatro instrumentos com riscos/documentos/elegibilidade por entidade, cinco fontes/edições/hash, escolha de dossier e referência privada cifrada com histórico. 21 Feature/524,13 frontend e estática/build aprovados; recibo capital_guidance_increment_20261102. Restam visual/login real e disponibilização; condições particulares/decisões são das contrapartes e AUD-CAPITAL-02 mantém o guião da Bolsa.
+- **AUD-CAPITAL-02 — Guião de admissão à Bolsa de Valores de Moçambique, distinguindo Bolsa, regulador e operadores**: Parcial local: cinco percursos, seis etapas, requisitos/documentos com fonte/artigo/página e referência recuperável no dossier. 14 Feature/474,18 frontend e verificações estáticas/build; recibo bvm_admission_increment_20261103. Restam montantes/encargos actuais, procedimentos CVM recentes completos, casos especiais/alterações posteriores, visual/login real e destino; não alegar admissão ou cálculo automático.
+- **AUD-CHECKLIST-01 — Editor de checklists e formulários configuráveis, publicação de versões e preservação de submissões anteriores**: Parcial local: editor/histórico do Balcão, perguntas condicionais, versões preservadas e entrada em vigor por data (21 Feature/314 e nove frontend no incremento temporal). Restam outros contextos, visual e destino. Recibo desk_effective_dates_increment_20261102; motor/competências reutilizados e orçamento histórico não contado como novo.
Continuidade 02/11/2026: primeiro editor de formularios do Balcao implementado localmente, reutilizando versoes imutaveis, validacao e ambito administrativo existentes. Conferencia anterior/nova e efeito sobre pedidos futuros; pedidos/submissoes v1 preservados apos v2. 18 Feature/325 assercoes iniciais e um teste frontend passaram. Provas finais e limites no manual; sem instalacao ou prova visual, restantes tipos/configuracao transversal parciais.
@@ -1593,7 +1593,7 @@ A/B internos concluídos em QA por provas anteriores mais demonstração dos cri
| AUD-SIM-01 | Rascunhos contextuais A/B guardados/recuperados noutra sessão e resultados no dossier correto já demonstrados; não repetir esse percurso. Restam variantes não contextuais/anónimas, expiração/purga e operações de outros consumidores/perfis, conforme versões existentes. Preservar o acesso direto e isolamento de projetos. |
| AUD-DESK-01 | A/B demonstram preparação DRAFT e recuperação. Restam submissão quando aplicável, 422 por campo, protocolo/recibo, mensagens, transições e operações documentais por tipo/perfil. DRAFT não equivale a submissão ou decisão externa. |
| AUD-DESK-02 | Reutilização contextual A/B concluída em QA; C88 preenchimento explícito da descrição vazia corrigido com fonte/revisão. Restam entidades empresariais, submissões e pedidos legados/representação organizacional por consumidor, conferência documental e demais critérios S01–S19; sem copiar dossier ou conta. |
-| AUD-CRM-01 | Tarefa S02 B concluída enquanto S10 permanecia à espera; gestor distinto e dados financeiros privados preservados. Restam conversão de manifestações sem duplicar investidor, responsável autorizado/próxima tarefa antes do fecho e filas/atribuições por perfil. Não depende de CRM externo. |
+| AUD-CRM-01 | Tarefa S02 B concluída enquanto S10 permanecia à espera; gestor distinto e dados financeiros privados preservados. Actualização03/11: conversão idempotente sem duplicação, consentimento e responsável/próxima tarefa conferidos em CrmIntakeTest; edição concorrente coberta pelo recibo crm_record_versions_increment_20261103. Fila pessoal do painel agora implementada/ensaiada no recibo dashboard_work_queue_increment_20261103; restam outras filas/atribuições por perfil e apresentação visual. Não depende de CRM externo. |
| AUD-UI-01 | A/B internos concluídos por composição das provas anteriores com os critérios restantes; seis varreduras móveis 320/390px sem overflow/violações automáticas. Restam rotas e ações de outros consumidores/perfis, dispositivos reais, leitor de ecrã, contraste/foco manual e editor especializado. C37 QA18 continua encerrado. |
| AUD-COUNTRY-01 | Residência PT QA18 guardada na prova anterior e recuperada noutra sessão neste lote. Não repetir esse critério. Restam cadastro inicial/outros perfis e variações de validação não demonstradas visualmente; disponibilidade ativa não confirmada por este ensaio QA. |
| AUD-COUNTRY-02 | Sem nova prova da constituição da entidade neste lote: país do representante no formulário público Empresa não prova país mestre de constituição. Demonstrar constituição distinta da residência, gravação/versão/recuperação e recusa de outra conta no consumidor empresarial existente. |
@@ -3177,3 +3177,232 @@ Continuidade 02/11/2026 — AUD-FUND-01: filtros sectoriais/territoriais e estad
Continuidade 02/11/2026 — AUD-FUND-01: referência FDEL oficial empacotada, prévia e preparação de rascunho pela gestão editorial. Reutiliza ficha existente, preserva edições, auditabilidade e datas; chamada municipal histórica distinta do programa. Sete testes/235 asserções, PHPStan e lint aprovados; tipos/compilação em acompanhamento. Vínculos sectorial/cartográfico, visual, concorrência, alertas e disponibilização pendentes. Fontes e provas no manual, sem publicação ou escrita no activo.
Continuidade 02/11/2026 — AUD-FUND-01: cinco cenários de concorrência com dois processos e bloqueios efectivamente observados. Reproduzido e corrigido deadlock 40P01 entre retirada e interesse da mesma pessoa, mantendo serialização e auditoria. Cinco cenários finais e sete Feature/235 asserções aprovados, PHPStan/Pint passaram. Bases e logs preservados; provas e limites no manual/recibo funding_concurrency_increment_20261102. Restam visual, vínculos da referência, alertas e disponibilização; nenhum acto no activo.
+
+Continuidade 02/11/2026 — ACT-11 / AUD-FUND-01: fundos/programas/incentivos publicados no catálogo integrados nos alertas existentes com escolha explícita, filtros aplicáveis, versão/fonte/estado e acesso próprio. Preferências antigas não alteradas. Trinta e seis testes/612 asserções e seis frontend aprovados; provas e limites no manual. Canais externos/outras fontes, concorrência específica do gerador, visual e disponibilização/agendador pendentes, sem acto no activo.
+
+Continuidade 02/11/2026 — ACT-11 / AUD-FUND-01: nove cenários concorrentes aprovados, incluindo geradores/repetição de preferências e ambas as precedências de cancelamento. Critérios do formulário limitados ao tipo/janela aplicável, com respostas locais preservadas e transporte limitado às aplicáveis; mudança de versão reinicia a conferência. Oito frontend, tipos e lint aprovados; compilação em acompanhamento. Provas/limites no manual. Visual, vínculos e disponibilização/agendador pendentes, sem alterações no activo.
+
+Continuidade 02/11/2026 — AUD-EDU-01: núcleo/API de rascunhos privados de procura/capacidade implementado, reutilizando as regras de submissão/revisão existentes. Dados cifrados, recuperação própria, versão/idempotência, snapshot e submissão única. Catorze testes/291 asserções, PHPStan e Pint aprovados; provas no manual. Interface, restantes painéis/perfis, concorrência e visual ainda pendentes. Estado parcial, sem alteração no activo.
+
+Continuidade 02/11/2026 — AUD-EDU-01: rascunhos ligados aos formulários, lista privada e recuperação por ID, submissão pela mesma identidade e leitura do snapshot. Edições mantidas em conflito e protecção de trabalho por guardar; dados privados com no-store/histórico cifrado. 14 testes/333 asserções, cinco frontend, PHPStan/tipos/lint/Pint/compilação aprovados. Concorrência, visual, restantes perfis/painéis e disponibilização pendentes; provas e limites no manual. Migração não aplicada no activo.
+
+Continuidade 02/11/2026 — AUD-EDU-01: dez cenários concorrentes de criação/edição/submissão aprovados, cinco por tipo, com dois processos e bloqueios observados. Repetições sem duplicação; precedência preservada e versão obsoleta recusada; seis rascunhos/quatro declarações e snapshots/auditoria conferidos. Revisão independente mantida. Provas e limites no manual; visual, restantes perfis/painéis e disponibilização pendentes. Sem alterações no activo.
+
+
+Continuidade 02/11/2026 — AUD-MARKET-01: raio geodésico implementado na API e interface, combinado com sector/modalidade/classificação e área, com fonte/data de registo/cobertura explícitas. Apenas pontos primários públicos exactos; precisão territorial protegida e filtros recuperáveis. Onze Feature/384 asserções e dez frontend, análise estática/tipos/lint/Pint/compilação aprovados, incluindo revalidação de plantio de algodao. Recibo business_proximity_increment_20261102; detalhes e limites no manual. Restam cobertura/alimentação de pontos públicos, origem documental, visual e disponibilização. Sem alterações no activo.
+
+
+Continuidade 02/11/2026 — AUD-MARKET-01: alimentação do ponto pelo formulário privado e publicação normal ligadas, com opt-in/território/fonte, histórico cifrado e preservação de UUID/locais secundários. 28 Feature/677 asserções e 17 frontend, análise estática em cache isolada/tipos/lint/Pint/build aprovados. Recibo business_point_publication_increment_20261102; provas e limites no manual. Cobertura real, visual e destino pendentes; migração só em QA sintético, sem novos papéis/rotas/reabertura de anúncios publicados.
+
+
+Continuidade 02/11/2026 — AUD-CHECKLIST-01: entrada em vigor por data implementada no editor e reutilizada pelo catálogo/dossier/percurso/criação. Versões futuras listadas na gestão; dados e edições anteriores preservados. Corrigida repetição da publicação inicial com JSONB; 21 Feature/314 asserções e nove frontend, PHPStan/tipos/lint/Pint/build aprovados. Recibo desk_effective_dates_increment_20261102; detalhes e escolhas técnicas no manual. Outros contextos, visual e destino pendentes; nenhuma migração ou pessoa real no activo.
+
+
+### 02/11/2026 — AUD-EDU-02: reconciliação com os rascunhos de Educação já demonstrados
+
+[EDUCATION-DRAFT-RECONCILIATION-20261102] AUD-EDU-02 é também coberto pelos incrementos já registados em AUD-EDU-01: rascunho incompleto privado de procura/capacidade, dono/tipo/versão, guarda/recuperação pela interface, conflitos, submissão única e revisão independente; sem zeros/datas fictícios ou inclusão nos agregados. Reutilizadas provas de 14 Feature/333 asserções, cinco frontend e dez cenários reais de concorrência em QA, com hashes das seis fontes UI/serviço/testes e sete logs conferidos em02/11. Recibos education_drafts_ui_increment_20261102 e education_drafts_concurrency_increment_20261102. Não é desenvolvimento novo ou instalação no activo. A indicação antiga de ausência na linha AUD-EDU-02 e nos planos anteriores é histórica e fica superada por estas provas, conservadas sem reexecução. A matriz/backlog foram corrigidos para parcial local. O saldo deste requisito é visual/disponibilização; AUD-EDU-03/01 conservam os restantes perfis e painéis. Nenhuma alteração no código, dados ou competências foi necessária para esta reconciliação.
+
+
+Continuidade02/11/2026 — AUD-ESTABLISHMENT-01: reconciliada entrega privada de28/10 (361464 observações, não empresas únicas); importador não foi recriado. Novo visor privado de fontes/linhas/pendências, sem fusão ou publicação, e correcção de respostas antigas no contexto territorial. Nove Feature/138 asserções, seis frontend e verificações estáticas/build aprovados; onze tabelas QA preservadas. Recibo proactive_supply_review_increment_20261102. Restam reconciliação de entidades, outros formatos e visual/destino do delta; provas históricas preservadas no manual/matriz.
+
+
+Continuidade 02/11/2026 — AUD-OP-05: corrigida publicação de etapa opcional explicitamente limpa, preservando desconhecido, versão do catálogo e histórico; omissão e seis valores legados conservados. 15 Feature/371 asserções e Pint/PHPStan aprovados em QA exclusiva. Recibo maturity_publication_increment_20261102; sem interface/migração/activo alterados. Restam adopção explícita de legados, variantes/categorias restantes e visual/destino; provas anteriores de pesquisa mantidas.
+
+
+Continuidade 02/11/2026 — AUD-COMPANY-01: comparador base público e ligado ao dossier implementado, perguntas aplicáveis, fontes/artigos e snapshots históricos cifrados; sem mudar a identidade ou concluir etapas. 14 Feature/385, seis frontend e verificações estáticas/build aprovados. Recibo company_comparison_increment_20261102. Modelos AUD-COMPANY-02, casos especiais, visual/login real e disponibilização permanecem separados.
+
+
+Continuidade 02/11/2026 — AUD-COMPANY-02: preparação factual privada em sete secções implementada no dossier, com reutilização de origens, capital exacto, histórico cifrado e recuperação de conflitos. 18 Feature/343 e 12 frontend, estática/build aprovados; recibo company_preparation_increment_20261102. Os sete exemplares não foram fornecidos (proprietário sem URL neste momento); minutas/derivadas/revisão formal e instalação mantêm-se pendentes. Não confundir ficha com contrato.
+
+
+Continuidade 02/11/2026 — AUD-CAPITAL-01: guia público de capitalização ligado ao dossier, quatro instrumentos/riscos/preparação, cinco fontes por edição/hash e referências cifradas com histórico/retirada/recuperação. 21 Feature/524 e 13 frontend, estática/build aprovados; recibo capital_guidance_increment_20261102. Visual/login real e destino pendentes. AUD-CAPITAL-02 conserva o guião bolsista por segmento; não confundir guia informativo com financiamento/admissão.
+
+
+Continuidade 03/11/2026 — AUD-CAPITAL-02: guião BVM público/dossier com cinco percursos, seis etapas/intervenientes, fontes/artigos/páginas, documentação partilhada/específica e histórico cifrado existente. 14 Feature/474,18 frontend e estática/build aprovados; recibo bvm_admission_increment_20261103. Mínimos anuais/encargos actuais, procedimentos CVM recentes completos, casos especiais, visual/login real e destino mantêm-se pendentes. Valores expirados de2024 não activam critérios de2026.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: indicadores operacionais, bases e cobertura
+
+[PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103.
+
+Saldo 03/11/2026: primeiro painel operacional local implementado; não equivale à cobertura integral de métricas de produto. Restam aquisição/activação, pesquisa e zero resultados, comparação pública, correspondência individual CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão do roteiro versionado, tempo projecto/submissão e etapas, abandono, satisfação/suporte, pós-investimento e registo de experiências controladas com hipótese/indicador/período/segmento/resultado/decisão. Não foram inventados pesos, baseline de pilotos, limiares, consentimentos ou eventos de visitantes. Visual/login real e disponibilização continuam pendentes.
+
+Os guiões/comparador/preparação, provas anteriores e estatísticas por origem não foram reabertos como desenvolvimento ausente. As línguas nacionais e os sete exemplares de minutas mantêm a pendência específica já respondida pela Tempo, sem repetir os pedidos.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: registo de experiências, planos e observações por versão
+
+[PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa.
+
+Saldo 03/11/2026: painel factual e registo manual versionado implementados/ensaiados localmente. Restam ligação transversal das alterações/editores ao registo, atribuição/execução de variantes e eventos por grupo com consentimento/âmbito definidos; aquisição/activação, pesquisa/zero resultados, comparação pública, CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte e pós-investimento. Pesos/pilotos de AUD-HUMAN-03 permanecem uma definição distinta; nenhum score inventado. Visual/login real e disponibilização/migração no destino continuam pendentes.
+
+As pendências concretas das línguas nacionais e dos sete modelos mantêm as respostas já recebidas da Tempo; não foram repetidas como pedidos de autorização nem preenchidas por conteúdo inventado.
+
+
+### 03/11/2026 — MASTER-e1169a77-0018: respostas de pesquisa, edições e recolha independente
+
+[PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa.
+
+Saldo 03/11/2026: painel factual, registo manual de experiências e contagens de pesquisa dos nove canais implementados/ensaiados localmente. A medição é de respostas HTTP registadas, não pessoas/pesquisas únicas, visitas ou utilização integral; recolha best effort e fontes não instrumentadas, incluindo fundos e correspondências internas, continuam identificadas. Restam aquisição/activação, comparação pública, correspondência CRM/qualificação/reuniões/diligência/propostas, investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte/pós-investimento; ligação transversal dos editores/alterações e execução/eventos de variantes. Pesos/pilotos de AUD-HUMAN-03 são definição distinta, sem score inventado. Visual/login real e disponibilização/migração no destino pendentes.
+
+A pesquisa rápida já entregue permanece demonstrada; não foi substituída por telemetria ou por alargamento silencioso dos resultados. As fontes de minutas e traduções mantêm as respostas/pendências específicas já registadas.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: selecção múltipla e declarações versionadas no Balcão
+
+[DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo.
+
+03/11/2026: editor, histórico, vigência, selecção múltipla e declarações de consentimento do Balcão implementados/ensaiados localmente. Restam outros consumidores/contextos de checklist, cobertura transversal dos tipos/regras/limites/anexos, autosave/recuperação nos contextos ainda não demonstrados, três camadas de obrigações/registo/licenciamento por fonte e âmbito, visual/login real e disponibilização. Não equivale a homologação, licença ou parametrização integral. Não repetir editor/vigência como trabalho ausente. Próxima acção: inventariar os consumidores e regras restantes p481/p161, com a mesma matriz/motor e fontes específicas. Textos/obrigatoriedade de consentimento reais dependem de publicação administrativa autorizada; não se publicaram declarações fictícias no activo.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: gravação automática, recuperação privada e conflitos
+
+[DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa.
+
+03/11/2026: Balcão tem editor/histórico/vigência/tipos múltiplos/declarações e gravação automática/recuperação privada demonstrados em QA. Restam outros consumidores/contextos de checklist e respectivos critérios p481, configuração transversal de limites/anexos/formatos/mensagens, camadas de obrigações gerais/registo/licenciamento por fonte e âmbito, observação visual/login real e disponibilização/migração no destino. Não é homologação nem parametrização integral. A cópia cifrada é buffer privado corrente, não histórico de cada tecla nem pedido submetido. Restantes consumidores mantêm os seus percursos existentes; não repetir autosave do Balcão como ausente. Próximo resultado: limites/regras de anexos/formatos e contextos ainda não demonstrados sobre o mesmo motor.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: perguntas de anexos, limites e reutilização documental
+
+[DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa.
+
+03/11/2026: Balcão tem editor/histórico/vigência, tipos múltiplos/declarações/anexos, recuperação automática e limites de ficheiro por pergunta demonstrados localmente. Restam outros consumidores/contextos p481, limites/formatos/mensagens parametrizados transversalmente, catálogo/selector legado geral e reutilização entre dossiers sem UUID manual, camadas de obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização/migração no destino. Os quatro MIME e tectos técnicos existentes (10MiB/100 ficheiros por dossier) não são parametrização integral da aplicação. Não é homologação, aprovação documental ou aceitação real. Nova pergunta reutiliza documentos de pedidos do mesmo dossier por selecção, preserva proveniência/datas e não duplica bytes. Não repetir editor/vigência/recuperação/anexos demonstrados como ausentes. Próxima acção: selector geral legado/entre dossiers com autorização completa e restantes regras por consumidor, sem ocultar capacidade anterior de reutilizar.
+
+
+### 03/11/2026 — AUD-CHECKLIST-01: pesquisa e selecção documental no âmbito autorizado
+
+[DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa.
+
+03/11/2026: selector geral do dossier, anexos por pergunta e suporte da etapa já não exigem UUID manual. Catálogo entre dossiers corresponde à autoridade existente, sem alargar o acesso a fontes de outras organizações. Continuam pendentes outros consumidores/formulários e a parametrização transversal de limites/formatos/mensagens, camadas de obrigações/registo/licenciamento por fonte/âmbito, conferência visual/login real e disponibilização no destino. Não é parametrização integral, homologação ou aceitação real. Reconciliado o saldo de UUID manual do formulário geral/entre dossiers no âmbito que o servidor já permitia. Não confundir esta cobertura com todos os formulários do portal, nem transformar a aceitação visual pendente em perda das capacidades demonstradas. Próxima acção: outros consumidores de documentos/cadastros e parametrização transversal.
+
+
+### 03/11/2026 — AUD-DESK-01/02: completar comprovativos no mesmo registo de pagamento
+
+[DESK-PAYMENT-EVIDENCE-20261103] A declaração manual já existia e permitia comprovativo pendente, mas faltava juntá-lo posteriormente sem repetir a referência. Agora o titular/representante com escrita acrescenta ou corrige o suporte do mesmo pagamento pending/internal_issue por vínculo seleccionado, versão, motivo e consentimento. Referência, montante, moeda e fonte do valor são conservados; a nova associação fica pending, sem confirmação bancária. Registo internal_verified não pode ser substituído pelo titular; eventual problema continua a ser registado pelo revisor independente no percurso existente. Proveniência documental, exemplar, versão/hash registados e validade declarada ficam nos eventos cifrados, sem segunda tabela/migração ou cópia física. Conferência valida o original comum e a correspondência ao exemplar associado; legado sem captura continua desconhecido, sem reconstituição retroactiva. Pesquisa/reutilização anterior preservada. Dossier encerrado mantém leitura dos pagamentos, sem novas operações manuais. 53 Feature/721 asserções e 47 frontend, PHPStan/Pint/tipos/lint/build aprovados; 18 tabelas QA vazias/owner/RLS/índices. Dois processos sobrepostos 0.392022s, em pedidos diferentes com a mesma referência, conservaram 1 declaração/evento; segundo com conflito 409 e pedidos principais intactos. Recibo desk_payment_evidence_increment_20261103, sem escrita activa ou nova migração.
+
+03/11/2026: comprovativo pendente ou corrigido pode completar a declaração existente sem repetir montante/moeda/fonte, com histórico e revisão independente. Restam outros consumidores e origens por formulário, atribuições/próxima acção/documentos por âmbito, parametrização transversal, conferência visual/login real e disponibilização no destino; integração bancária/entrega de mensagens não é declarada por estes registos manuais. Critérios gerais do Balcão/percurso não estão integralmente encerrados. Não repetir declaração/conferência/comunicação já demonstradas como ausentes. A correcção documental resolve o suporte pendente no registo existente; não amplia o âmbito para integração de bancos ou cobrança automática.
+
+
+### 03/11/2026 — AUD-DESK-01/02 e AUD-CRM-01: coerência dos registos encerrados, cancelamento e fecho pelo dono
+
+[DESK-CLOSED-LIFECYCLE-20261103] Por decisão expressa do proprietário, o dono registado executa agora o encerramento/reabertura, com acesso efectivo, versão, motivo, operação idempotente e histórico. Gestores/outros representantes não recebem esse poder por inferência. Resumo das pendências antes da confirmação e manutenção dos estados/payloads/documentos/tarefas/pagamentos, sem aprovação em cascata. Dossier com closed_at já bloqueava rascunhos/anexos/pagamentos, mas permitia transições, etapas, atribuições, mensagens e actualizações de tarefas. Reproduzidos HTTP200 nesses percursos, incluindo atribuição com MFA válido. Agora a guarda de estado comum e lock do dossier protegem esses comandos, preservando leitura/histórico e as permissões anteriores. Tarefas com vínculo CRM/dossier respeitam o fecho também no CRM; CRM sem tarefas vinculadas não consulta nem exige o Balcão. Listas de triagem/filas excluem encerrados e a interface retira decisões/atribuições/mensagens/etapas/conferência/tarefas sem aplicação. Cancelamento de rascunho/devolvido, já autorizado pelo servidor ao titular com escrita, fica disponível por motivo e confirmação explícita, conservando dados/documentos/histórico e o dossier. Sucesso mostra a versão efectivamente guardada; falha conserva edições. Justificação de correcção só é perguntada num pedido devolvido. 77 Feature/1016 na regressão, 15/202 específicos finais (rondas sobrepostas, não somar),64 frontend e estática/Pint/tipos/lint/build aprovados;20 tabelas QA vazias/owner/RLS/índices. Recibo desk_closed_lifecycle_increment_20261103, sem nova migração/escrita activa.
+
+03/11/2026: coerência do closed_at e cancelamento de rascunhos demonstrados nos percursos identificados, sem alterar regras/perfis ou encerrar dossiers automaticamente. A operação de encerrar/reabrir o dossier completo foi implementada conforme a resposta expressa do proprietário: o dono executa essa acção. Mantêm-se acesso efectivo, motivo, versão e histórico, sem impor que todas as pendências estejam concluídas nem alterar estados de outros processos. Restam restantes consumidores/parametrização/percurso adaptativo, conferência visual/login real e disponibilização no destino. Conservar as capacidades já demonstradas, separar estado de fecho de autoridade de leitura e não tratar a definição pendente do fecho integral como bloqueio dos restantes desenvolvimentos.
+
+### 03/11/2026 — AUD-CRM-01: edição concorrente sem sobrescrever alterações recentes
+
+[CRM-RECORD-VERSIONS-20261103] Investidor, contacto, qualificação/atribuição de lead e estado de tarefa passam a enviar automaticamente a revisão que foi apresentada. PortalAudit confere-a sob lock, devolve erro de versão e só incrementa a revisão numa alteração efectiva. As colunas version_no já existiam; o trigger existente apenas actualiza updated_at. Contactos partilhados mantêm uma revisão comum. A interface compara dados actuais com a edição, exige escolha nos campos em conflito e conserva alterações deliberadas, incluindo regressar ao valor inicial e editar durante a gravação. Preservados conversão idempotente, consentimento, não duplicação, responsáveis autorizados, próxima acção e fecho de dossiers pelo dono. 45 Feature/594 asserções, 75 frontend (10 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL com espera por lock comprovada: uma gravação, um conflito de versão, um evento; contacto sentinela preservado. 23 tabelas QA vazias, owner/RLS conferidos. Recibo crm_record_versions_increment_20261103; sem migração ou escrita activa. Visual/destino e restante cobertura do CRM continuam parciais.
+
+### 03/11/2026 — AUD-DASH-01 e AUD-CRM-01: acompanhamento pessoal no painel
+
+[DASHBOARD-WORK-QUEUE-20261103] O painel passa a reunir manifestações, pedidos do Balcão e tarefas CRM atribuídos à pessoa autenticada, usando as autoridades de consulta existentes. Colecções separadas, totais/prazos sobre o conjunto completo, ordenação por prazo/ID e cinco linhas por página com paginação independente. Ligações directas ensaiadas; tarefas apontam ao formulário existente do lead. Fecho do dossier suspende a presença dos pedidos/tarefas vinculados na fila activa, conservando estados/histórico. Auditor não recebe o resumo de gestão que os destinos já lhe negavam. Regressão final41 Feature/694,82 frontend (7 novos), estática/Pint/tipos/lint/build aprovados;26 tabelas QA vazias, owner/RLS conferidos após libertação do lock do processo de testes. Recibo dashboard_work_queue_increment_20261103; nenhuma migração nova/escrita activa. Restam outros acompanhamentos por perfil, visual e entrega.
+
+### 03/11/2026 — AUD-CRM-01 e AUD-DASH-01: próxima acção consistente no CRM e na orientação
+
+[CRM-NEXT-ACTION-20261103] Reproduzidas três falhas: uma tarefa futura em dossier encerrado permitia qualificar o lead e concluir a última tarefa disponível (HTTP302), e a orientação permitia concluir a última tarefa de lead activo sem substituta (HTTP200). Agora a disponibilidade de trabalho é partilhada por CrmTask/CrmNextAction, qualificação, conclusão pelos dois percursos, fila pessoal e indicadores factuais. A tarefa conserva estado/histórico, mas não serve de próxima acção enquanto o dossier está encerrado; reabertura pelo dono recupera a disponibilidade sem reescrever a tarefa. Os dois comandos serializam pelo mesmo lead antes de alterar tarefas. Regra de prazo futuro já existente preservada; interface explica a pendência e liga ao formulário existente. 75 Feature/915 asserções e foco final2/42 sobreposto,87 frontend (5 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real CRM/orientação: uma conclusão, uma recusa por falta de outra próxima acção, uma acção futura mantida e lead/dois dossiers preservados.29 tabelas QA vazias, owner/RLS/lock conferidos. Recibo crm_next_action_increment_20261103; nenhuma migração/escrita activa.
+
+### 03/11/2026 — AUD-PART-01: edição de parcerias sem perda de dados e recuperação comparada
+
+[PARTNERSHIP-EDITING-20261103] Corrigidas omissões destrutivas no editor/API: disponibilidade existente, organização, campos escalares, locais e origens não enviados são conservados; valores explicitamente vazios continuam a remover o dado. Disponibilidade opcional agora visível, distinta do prazo de recepção de interesses. Actualização da página conserva edições e compara divergências por campo/grupo antes da adopção explícita. Repetição de criação não confirmada reutiliza o comando/chave originais, exige representação actual e não volta a validar sector activo numa repetição já executada. Gravações novas conservam validação do sector, versões409 e estados autorizados, incluindo publicada→rascunho.19 Feature/148 asserções (10 novos),103 frontend (16 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 registo/1 evento/1 auditoria/1 notificação, mesma identidade/versão e disponibilidade conservada.45 tabelas QA vazias com owner/RLS/lock conferidos. Recibo partnership_editing_increment_20261103; sem migrações/escritas activas.
+
+### 03/11/2026 — AUD-PART-01: responsáveis dos marcos ligados aos participantes efectivos
+
+[PARTNERSHIP-PARTICIPANTS-20261103] Selector de responsáveis dos marcos agora reutiliza a regra efectiva de representação das duas partes. Pessoas identificadas pelo nome e lado da parceria, sem introduzir IDs, e-mails ou novos papéis. Autores de participações pessoais mantidos; representantes actuais de organizações seleccionáveis; viewers, vínculos revogados e organizações eliminadas não são fontes de atribuição. Leitura conserva o responsável anterior e informa perda de representação; substituir exige escolha explícita e evento com IDs anterior/novo. Salas em negociação, encerradas ou apenas de consulta não oferecem edição de marcos.25 Feature/211 asserções (6 novos),1413 frontend em regressão ampla (6 novos), PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_participants_increment_20261103; sem migrações/escritas activas.
+
+### 03/11/2026 — AUD-PART-01: recuperação dos formulários da sala e repetição sem efeitos duplicados
+
+[PARTNERSHIP-ROOM-RECOVERY-20261103] Sala deixa de remontar pela versão; acordo, marcos, mensagem e ficheiro preparados conservam-se durante actualizações. Alterações deliberadas exigem comparação por campo/contexto e escolha explícita nos conflitos; controlos intocados acompanham os dados actuais sem pedir comparação de um formulário vazio. Estado/acesso posteriores limitam novas gravações e conservam preparação; aviso único antes de sair. Novos marcos e documentos usam chave/conteúdo por actor/sala no histórico existente, com lock da sala; mensagens reutilizam a chave já existente. Repetição confirmada é leitura, mesmo após encerramento, sem novos marcos, bytes, partilhas, eventos ou scans.34 Feature/310 asserções (9 novos),foco final2/37 sobreposto para caixa UUID,1429 frontend em regressão ampla e22 focados finais sobrepostos (16 novos e6 adaptados), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 marco,1 documento/ficheiro,2 eventos/auditorias e1 pedido de scan; lock do marco demonstrado, seguido de replay documental.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_room_recovery_increment_20261103; sem migrações/escritas activas.
+
+### 03/11/2026 — AUD-PART-01: candidaturas identificadas, recuperação e avaliação no contexto revisto
+
+[PARTNERSHIP-CANDIDACIES-20261103] Corrigidas quatro falhas reproduzidas: omissão apagava organização/declarações; actualizar outra candidatura podia atingir o registo errado; faltava autorização efectiva por candidatura na resposta; repetição de submissão já executada devolvia409. Agora identidade explícita, omissões conservadas e remoções explícitas, versões/consentimento/representação anteriores mantidos, snapshots privados de submissão/avaliação e repetição actor/parceria/tipo/chave sem nova decisão. Formulários mantêm preparação e comparam divergências; declaração e avaliação têm bases próprias, perda de acesso conserva apenas preparação local e não concede autoridade. Versão da parceria/hash de critérios conferidos no servidor para novos clientes, retirada independente da janela/requisitos. Ordem de locks parceria→candidatura partilhada.47 Feature/401 asserções (13 novos),1451 frontend (22 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real:1 ressubmissão/1 avaliação antiga recusada409,1 evento/auditoria,2 notificações locais e replay só de leitura.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_candidacies_increment_20261103; sem migrações/escritas activas.
+
+### 03/11/2026 — AUD-PART-01: consulta privada das versões e decisões das candidaturas
+
+[PARTNERSHIP-HISTORY-20261103] Leitor dos eventos existentes, sem recalcular ou reconstruir valores históricos com dados actuais. Acesso actual à candidatura/parceria e conferência adicional do âmbito guardado em cada versão para o candidato. Página privada com comparação antes/depois, avaliação e parâmetros realmente guardados, links no painel e candidatura; paginação estável por cursor cifrado vinculado à conta/candidatura. 57 Feature/488 asserções (10 novos),1460 frontend (9 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, identidade/owner/RLS/lock conferidos. Recibo partnership_history_increment_20261103;68 recibos e177 provas anteriores preservados. AUD-PART-01 permanece parcial, sem instalação/escritas no activo.
+
+[PARTNERSHIP-HISTORY-FOLLOWUP-20261103] Próxima acção concreta identificada na revisão: o dashboard anterior ainda selecciona p.title actual para uma candidatura, incluindo quando a parceria deixou de estar publicada, e as notificações são listadas pelo destinatário histórico sem voltar a conferir a representação. O novo leitor não devolve esse título privado; esta prova limita-se ao GET do histórico. Conferir/corrigir a projecção e os links do painel e os destinatários/visibilidade das notificações com provas próprias, reutilizando a autoridade existente. Não declarar a privacidade de todos os consumidores encerrada por este incremento.
+
+### 03/11/2026 — AUD-PART-01: painel e avisos pelo âmbito actual e histórico
+
+[PARTNERSHIP-DASHBOARD-20261103] Corrigidas três falhas reproduzidas: título privado após despublicação, organização eliminada ainda no painel e aviso de representante revogado. Painel projecta só título/link autorizados; representação usa o mesmo cadastro activo de owns. Avisos novos seguem participantes operacionais actuais e guardam contexto no evento existente; leitura e confirmação exigem destinatário, acesso actual e âmbito guardado. Links reconstruídos para candidatura/sala/parceria; primeira leitura preservada. 73 Feature/576 asserções (16 novos),1466 frontend (6 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.69 recibos e185 provas anteriores preservados. Recibo partnership_dashboard_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-PART-01: recuperação da publicação e moderação da parceria
+
+[PARTNERSHIP-PUBLICATION-20261103] Publicação/moderação preserva motivo por proposta/conta e compara contexto antes de nova tentativa; replay por UUID/actor no evento, autoridade actual e estados existentes. Suspensão exposta pela capacidade real. Snapshot anterior/aplicado privado, metadados seguros no detalhe e um único aviso de saída com as candidaturas. 85 Feature/642 asserções (12 novos),1482 frontend (16 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.70 recibos e194 provas anteriores preservados. Recibo partnership_publication_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-PART-01: leitura privada das versões da publicação
+
+[PARTNERSHIP-VERSIONS-20261103] Leitor privado do histórico da publicação, antes/depois, por acesso actual e âmbito histórico. Captura de novas criações/edições reutiliza o snapshot das transições, sem inventar o placeholder de criação ou conteúdo legado.10 eventos por página, cursor cifrado por conta/processo/propósito, sem dados actuais no lugar dos antigos. 97 Feature/739 asserções (12 novos),1490 frontend (8 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.71 recibos e204 provas anteriores preservados. Recibo partnership_versions_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-PART-01: recuperação de edições sem confirmação
+
+[PARTNERSHIP-DRAFT-RECOVERY-20261103] Edições identificadas por operation_key/actor/processo, com replay no evento existente antes de validar cadastros vivos, sem repetir versão ou efeitos. Editor conserva comando e alterações posteriores, revalida consulta antes de nova tentativa e separa contas. Critérios/tipos anteriores mantêm identificação e remoção explícita da preparação. 109 Feature/802 asserções (12 novos),1502 frontend (12 novos) e28 focados verificados sem somar repetições;PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.72 recibos e212 provas anteriores preservados. Recibo partnership_draft_recovery_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-PART-01: recuperação e revisão de contexto nos acordos
+
+[PARTNERSHIP-AGREEMENTS-20261103] Acordos com tentativa identificada por actor/sala, recuperação sem duplicar efeitos após estados terminais e revisão da versão da proposta/candidatura. Confirmação bilateral pelas partes efectivas, histórico completo anterior e preparado posterior conservado; assinatura jurídica continua não verificada. 121 Feature/905 asserções (12 novos),1514 frontend (12 novos),28 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;73 recibos e224 provas anteriores preservados. Recibo partnership_agreements_increment_20261103; parcial, sem entrega activa.
+
+### 03/11/2026 — AUD-PART-01: leitura legada e histórico privado dos acordos
+
+[PARTNERSHIP-AGREEMENT-HISTORY-20261103] Leitura de instrumentos antigos sem falha/confirmações inventadas e histórico privado ligado à sala, com snapshots antes/depois, âmbitos actuais/históricos separados e paginação cifrada por conta/relação/finalidade. 132 Feature/1009 asserções (11 novos),1525 frontend (11 novos),39 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;74 recibos e237 provas preservados. Recibo partnership_agreement_history_increment_20261103; parcial, sem entrega activa.
+
+### 03/11/2026 — AUD-PART-01: histórico do acordo fora da resposta corrente da sala
+
+[PARTNERSHIP-AGREEMENT-PROJECTION-20261103] Sala corrente projecta título, condições, assinatura guardada e confirmações reconhecidas; versões anteriores e metadados privados ficam no servidor e no leitor histórico autorizado. 141 Feature/1146 asserções (9 novos),39 frontend focados;PHPStan/Pint aprovados e QA45 vazias/owner/RLS/lock conferidos. Frontend1525/tipos/lint/build anteriores reutilizados com fontes cliente e artefactos conferidos.75 recibos e248 provas anteriores preservados. Recibo partnership_agreement_projection_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-PART-01: síntese do histórico no detalhe da parceria
+
+[PARTNERSHIP-PUBLICATION-SUMMARY-20261103] Síntese de até cinco alterações recentes no detalhe, com autoridade do leitor histórico, metadados reservados ocultos e linguagem partilhada com o histórico completo. 149 Feature/1247 asserções (8 novos),1533 frontend (8 novos),55 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;76 recibos e254 provas anteriores preservados. Recibo partnership_publication_summary_increment_20261103; parcial, sem entrega activa.
+
+### 03/11/2026 — AUD-CRM-01: recuperação da criação de tarefas e conservação da preparação
+
+[CRM-TASK-CREATION-20261103] Recuperação da criação de tarefas CRM sem duplicar a tarefa/eventos de negócio e sem apagar edições feitas durante o envio. 77 Feature/877 asserções (10 novos), confirmação final sobreposta10/79;1545 frontend (12 novos),41 focados. PHPStan/Pint/tipos/formato/lint/build aprovados. QA45 vazias com owner/RLS/lock conferidos; índice único novo somente em QA. 77 recibos/266 provas anteriores preservados. Recibo crm_task_creation_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-CRM-01: preparação recuperável de nova tarefa, por conta e lead
+
+[CRM-TASK-PREPARATION-20261103] Preparação de nova tarefa CRM cifrada, por conta/lead, com gravação automática, comparação antes de adoptar e retoma do envio original sem duplicar. 48 Feature/369 asserções antes da última normalização;14/123 específicos finais sobrepostos em13 casos (14 novos no total).57 frontend actuais (16 novos,41 sobrepostos com a ronda integral anterior1545, que não foi repetida). PHPStan/Pint/tipos/formato/lint/build aprovados. QA46 vazias/owner/RLS/lock;1 tabela nova somente em QA.78 recibos/278 provas anteriores preservados. Recibo crm_task_preparation_increment_20261103; parcial, sem instalação/escritas no activo.
+
+### 03/11/2026 — AUD-EDU-01/03: acompanhamento interno e revisão contextual de declarações
+
+[EDUCATION-WORK-QUEUE-20261103] Painel interno dos gestores com acompanhamento próprio, revisão independente e detalhe contextual. Revisão fixa a versão analisada, exige comparação se mudou, conserva edições posteriores e repete a mesma tentativa sem nova decisão. Fundamentos anteriores/novos preservados em snapshot cifrado e consulta privada paginada. 30 Feature/629 asserções (16 novos,14 anteriores);22 frontend (17 novos,cinco anteriores). PHPStan/Pint/tipos/formato/lint/build aprovados;54 tabelas QA vazias, owner/RLS/lock conferidos.79 recibos/289 provas anteriores preservados. Recibo education_work_queue_increment_20261103. Parcial local, sem migração/escritas no activo.
+
+### 03/11/2026 — AUD-PROFILE-20: incidentes técnicos e perfil próprio de suporte
+
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Registo automático de falhas técnicas de submissão/publicação, referência correlacionada, consulta própria e perfil próprio de Suporte técnico com fila por organização/tipo. Reutiliza auditoria append-only e atribuições existentes, sem aprovação ou acesso documental adicional.15 Feature/264 asserções (oito novos,sete anteriores);12 frontend (seis novos,seis anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Base final QA com59 tabelas vazias, owner/RLS/lock conferidos; primeira execução mista acompanhada separadamente.80 recibos/298 provas anteriores preservados. Recibo opportunity_technical_incidents_increment_20261103. Parcial local; migração do papel somente em QA, sem alterações no activo.
+
+### 03/11/2026 — AUD-PROFILE-20: tratamento auditado e recuperação do envio de suporte
+
+[TECHNICAL-INCIDENT-HANDLING-20261103] Tratamento de incidentes pelo perfil existente: assunção/substituição explícita, notas cifradas, devolução à fila, resolução e reabertura, histórico privado paginado e filtros pelo estado actual. Versão e tentativa identificada preservam notas e impedem repetição de efeitos.18 Feature/339 asserções (dez novos,oito anteriores);28 frontend (16 novos,12 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Um cenário com dois processos e espera real no incidente:200/409, replay só de leitura, investimento e raiz intactos. QA final59 tabelas vazias; prova concorrente retém só amostras sintéticas declaradas.81 recibos/306 provas anteriores preservados. Recibo technical_incident_handling_increment_20261103. Parcial local, zero novas migrações/escritas activas.
+
+### 03/11/2026 — AUD-PROFILE-20: actualização de Suporte técnico pelo instalador existente
+
+[SUPPORT-PROFILE-INSTALLATION-20261103] Actualização do perfil de Suporte técnico integrada no instalador autenticado existente: prévia, MFA, provas do destino/código, confirmação e recibo idempotente. Schema e ledger partilham a mesma verificação no servidor e na disponibilidade do perfil.18 Feature finais/230 asserções (dez novos,oito do instalador anterior); regressão inicial36/569;30 frontend (15 novos,15 do tratamento anterior),PHPStan/Pint/tipos/formato/lint/build aprovados. Backup PostgreSQL e arquivo de candidato/original privado sintético efectivamente restaurados em QA: 190 tabelas,30 sequências,1567 ficheiros e três envelopes MFA legíveis. Actualização e repetição conservaram todas as tabelas salvo uma entrada de migração e um recibo; zero atribuições de suporte inferidas. QA de testes62 tabelas vazias.82 recibos/318 provas anteriores preservados. Recibo support_profile_installation_increment_20261103. Parcial local, sem instalação/escrita activa.
+
+### 03/11/2026 — AUD-PROFILE-20: avisos internos de incidentes por consultar
+
+[SUPPORT-INCIDENT-NOTICES-20261103] Avisos internos de incidentes por consultar para o Suporte técnico efectivo, com contador próprio na navegação, filtro antes da paginação e marca explícita de consulta por actor/raiz. A consulta não é tratamento, resolução, aprovação ou acesso documental.25 Feature finais/376 asserções (sete novos,18 de instalação anteriores);31 frontend (nove novos,22 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. QA62 tabelas vazias e identidade/owner/RLS/FORCE conferidos.83 recibos/330 provas anteriores preservados. Recibo support_incident_notices_increment_20261103. Parcial local, sem migração ou escrita activa.
+
+### 03/11/2026 — AUD-PROFILE-20: incidentes de uploads e preservação de originais em falhas
+
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Incidentes de upload de documentos/imagens e preparação WebP integrados no mesmo suporte, avisos e tratamento por âmbito. Limpeza conservadora conserva originais referenciados e bytes de resultado incerto; falhas na limpeza não escondem o erro original.23 Feature/285 asserções (oito novos,cinco de recursos e dez do instalador); um caso adicional sem GD/duas asserções;37 frontend (seis novos,31 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. GD/WebP carregado apenas no processo CLI de QA; configuração normal sem alteração. QA64 tabelas vazias, com identidade/owner/RLS/FORCE conferidos.84 recibos/339 provas anteriores preservados. Recibo resource_technical_incidents_increment_20261103. Parcial local, sem migração ou escrita activa.
+
+### 03/11/2026 — AUD-PROFILE-20: despacho, workers e resultados antigos da análise de documentos
+
+[SCAN-TECHNICAL-INCIDENTS-20261103] Falhas no despacho e execução da análise de documentos ligadas ao Suporte técnico por contexto capturado e acesso actual. Tentativas e callbacks identificados no histórico existente; resultados antigos não substituem resultados posteriores, e falha de confirmação da fila não reverte um documento já limpo.30 Feature/365 asserções finais (15 novos,cinco de recursos,dez do instalador), com42/574 anteriores sobrepostos;43 frontend (seis novos). PHPStan/Pint/tipos/formato/lint/build aprovados.67 tabelas QA vazias. Uma mensagem de fila real consumida por outro processo, com ClamD deliberadamente indisponível: inconclusivo, quarentena, original cifrado intacto,zero temporários e incidente próprio.85 recibos/351 provas preservados;14 provas novas. Recibo scan_technical_incidents_increment_20261103. Parcial local,zero escrita/migração activa.
+
+### 03/11/2026 — AUD-PROFILE-20: repetição de análises e confirmação efectiva do envio
+
+[SCAN-RETRY-20261103] Repetição da análise distingue aceite, reserva existente, contexto alterado, envio não confirmado e envio diferido. Reserva existente não altera o documento nem duplica o pedido; falha tardia não sobrepõe clean/infected/scanning. Mesma autoridade documental, revalidada após commit, com auditoria da preparação e original preservado. Botão dos anexos de zonas usa resposta Inertia; avisos aparecem também na gestão documental.36 Feature/378 asserções (11 novos,15 de scans,dez do instalador),24/228 iniciais sobrepostos e47 frontend (quatro novos),PHPStan/Pint/tipos/formato/lint/build aprovados.69 tabelas QA vazias. Ensaio com reserva em cache PostgreSQL e fila reais: segundo pedido preservou190 tabelas; outro processo consumiu uma mensagem e libertou a reserva do seu dono. ClamD deliberadamente indisponível manteve quarentena, cifra e histórico,zero temporários.86 recibos/365 provas preservados;14 novas provas. Recibo scan_retry_increment_20261103. Parcial local,zero escrita/migração activa.
+
+### 03/11/2026 — AUD-COUNTRY-01/02 e AUD-PROFILE-25: perfil e empresas sem duplicação por repetição
+
+[INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa.
+
+### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: editor organizacional com confirmação e recuperação
+
+[ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa.
+
+### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: reutilização de país com pré-visualização e confirmação repetível
+
+[ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa.
diff --git a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv
index b6f57890..dadac045 100644
--- a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv
+++ b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv
@@ -655,8 +655,8 @@ MASTER-471012ab-0120,"Seleccionar componente, cultura ou serviço e manifestar i
MASTER-471012ab-0121,"Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1444 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4292 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1446 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3080 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4292,oportunidades,/api/v1/business-opportunities; /api/v1/business-opportunities/{slug}; /investidor/terra-duat; /investidor/terra-duat/novo; /investidor/terra-duat/{id}; /investidor/terra-duat/{id}/actualizacoes; /investidor/terra-duat/{id}/documentos; /investidor/terra-duat/{id}/documentos/{attachment}; /investidor/terra-duat/{id}/editar; /investidor/terra-duat/{id}/imprimir; /investidor/terra-duat/{id}/solicitar-apoio; /management/opportunities,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0121: Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado. | MASTER-e1169a77-0274: Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado. | MASTER-f70ce307-0130: Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado. | MASTER-51b8f0ad-0210: Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado. | MASTER-edece80c-0274: Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado.",P2,MASTER-471012ab-0121: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0274: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0130: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0210: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0274: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0121 | MASTER-e1169a77-0274 | MASTER-f70ce307-0130 | MASTER-51b8f0ad-0210 | MASTER-edece80c-0274,5,"[{""id"":""MASTER-471012ab-0121"",""pedido"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1444""],""aceitacao"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-e1169a77-0274"",""pedido"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4292""],""aceitacao"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-f70ce307-0130"",""pedido"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1446""],""aceitacao"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-51b8f0ad-0210"",""pedido"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3080""],""aceitacao"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-edece80c-0274"",""pedido"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4292""],""aceitacao"":""Nota editorial: custos, metas, maturidade, entidades responsáveis e disponibilidade para investimento devem ser confirmados com o MPD e a entidade de tutela antes da publicação. A ficha pública deve distinguir claramente informação oficial, estimativa, oportunidade complementar e chamada exploratória ao mercado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.opportunities: 6 registos; public.opportunity_images: tabela ausente; public.opportunity_documents: tabela ausente; public.opportunity_location_drafts: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/OpportunityManagement.php; app/Services/OpportunityResources.php; resources/js/pages/management/opportunity-draft.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"OpportunityManagementTest, OpportunityResourcesTest, OpportunityOriginReviewTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-471012ab-0122,"Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1447 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4295 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1449 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3083 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4295,cartografia/relações,/api/v1/geo/drafts; /api/v1/geo/search; /api/v1/geo/sources; /api/v1/geo/sources/{id}/transitions; /api/v1/geo/territories; /api/v1/geo/territories/{id}; /api/v1/geo/territories/{id}/transitions; /api/v1/geo/territories/{type}/{id}; /api/v1/geo/{collection}; /api/v1/investment/compare; /api/v1/investment/export; /api/v1/investment/favourites/{id},"InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Demonstrar consumidor: pesquisar→selecionar→gravar→nova sessão→renderizar limite correto; conservar pai, código e fonte. Critério individual original preservado; cobertura atual ainda não individualizada.","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0122: Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal. | MASTER-e1169a77-0275: Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal. | MASTER-f70ce307-0131: Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal. | MASTER-51b8f0ad-0211: Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal. | MASTER-edece80c-0275: Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal.",P1,MASTER-471012ab-0122: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0275: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0131: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0211: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0275: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0122 | MASTER-e1169a77-0275 | MASTER-f70ce307-0131 | MASTER-51b8f0ad-0211 | MASTER-edece80c-0275,5,"[{""id"":""MASTER-471012ab-0122"",""pedido"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1447""],""aceitacao"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-e1169a77-0275"",""pedido"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4295""],""aceitacao"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-f70ce307-0131"",""pedido"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1449""],""aceitacao"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-51b8f0ad-0211"",""pedido"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3083""],""aceitacao"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-edece80c-0275"",""pedido"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4295""],""aceitacao"":""Local do investimento: país, região, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência e coordenadas geográficas, quando disponíveis. Projectos nacionais ou multiterritoriais devem listar cada área abrangida e indicar a localização principal."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.geo_locations: 1990 registos; public.geo_geometries: 0 registos; public.project_locations: 28 registos; public.cluster_projects: 13 registos; public.opportunity_projects: 0 registos; public.opportunity_clusters: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Demonstrar consumidor: pesquisar→selecionar→gravar→nova sessão→renderizar limite correto; conservar pai, código e fonte. Critério individual original preservado; cobertura atual ainda não individualizada.","InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: território. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,território,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",resources/js/components/investment-territory.tsx; app/Http/Controllers/InvestmentTerritoryController.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"InvestmentTerritoryTest, TerritorialRegistryTest, InvestmentTerritorialTraceabilityTest, InvestmentZoneTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-471012ab-0123,"Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1460 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4308 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1462 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3096 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4308,cartografia/relações,/api/v1/geo/drafts; /api/v1/geo/search; /api/v1/geo/sources; /api/v1/geo/sources/{id}/transitions; /api/v1/geo/territories; /api/v1/geo/territories/{id}; /api/v1/geo/territories/{id}/transitions; /api/v1/geo/territories/{type}/{id}; /api/v1/geo/{collection}; /api/v1/investment/compare; /api/v1/investment/export; /api/v1/investment/favourites/{id},"InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Demonstrar consumidor: pesquisar→selecionar→gravar→nova sessão→renderizar limite correto; conservar pai, código e fonte. Critério individual original preservado; cobertura atual ainda não individualizada.","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0123: Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas. | MASTER-e1169a77-0276: Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas. | MASTER-f70ce307-0132: Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas. | MASTER-51b8f0ad-0212: Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas. | MASTER-edece80c-0276: Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas.",P1,MASTER-471012ab-0123: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0276: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0132: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0212: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0276: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0123 | MASTER-e1169a77-0276 | MASTER-f70ce307-0132 | MASTER-51b8f0ad-0212 | MASTER-edece80c-0276,5,"[{""id"":""MASTER-471012ab-0123"",""pedido"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1460""],""aceitacao"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-e1169a77-0276"",""pedido"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4308""],""aceitacao"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-f70ce307-0132"",""pedido"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1462""],""aceitacao"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-51b8f0ad-0212"",""pedido"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3096""],""aceitacao"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""},{""id"":""MASTER-edece80c-0276"",""pedido"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4308""],""aceitacao"":""Localização normalizada: país, âmbito nacional ou regional, província, distrito, posto administrativo, localidade, município ou cidade, corredor, zona económica, parque industrial ou bacia, endereço ou referência, latitude, longitude e localização principal. Registos multiterritoriais devem admitir múltiplas localizações relacionadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""cartografia/relações""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.geo_locations: 1990 registos; public.geo_geometries: 0 registos; public.project_locations: 28 registos; public.cluster_projects: 13 registos; public.opportunity_projects: 0 registos; public.opportunity_clusters: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Demonstrar consumidor: pesquisar→selecionar→gravar→nova sessão→renderizar limite correto; conservar pai, código e fonte. Critério individual original preservado; cobertura atual ainda não individualizada.","InvestmentGeography, campos TerritoryFields/ProvinceSelect, geo_locations/geo_geometries e importador autenticado","QA408/581INE; ativo0geometrias;173correspondências por nome/edição/pai, Mandie ambíguo. Publicação é ação separada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: território. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,território,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",resources/js/components/investment-territory.tsx; app/Http/Controllers/InvestmentTerritoryController.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"InvestmentTerritoryTest, TerritorialRegistryTest, InvestmentTerritorialTraceabilityTest, InvestmentZoneTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
-MASTER-471012ab-0124,"Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1470 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4318 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1472 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3106 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4318,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. Continuidade local: InvestmentOpportunityAlerts, InvestmentWorkspace, notificações e pesquisa públicas reutilizadas.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [OPPORTUNITY-ALERTS-20261102] ACT-11 local: preferências e correspondência do catálogo público, confirmação, critérios, frequência, canal no portal e cancelamento; notificações de manifestações preservadas. 16 testes Feature/253 asserções e dois frontend aprovados; PHPStan, tipos, lint e compilação passaram. Fonte/versão/critério conservados; lote201, falha/repetição e migração com dados anteriores demonstrados. Recibo opportunity_alerts_increment_20261102 e manual de 02/11/2026. Sem instalação ou prova visual; fontes de concursos/incentivos e canais externos pendentes. [QUICK-SEARCH-COTTON-20261102] Pedido Tempo: plantio de algodao. Pesquisa combina palavras e variantes delimitadas de cultivo, normaliza acentos, usa hierarquia territorial pública e preserva filtros. Duas APIs, página, mapa e exportação consistentes; fichas de transformação apenas como relacionadas quando não existe correspondência completa. Barra GET/autofill. Nove testes Feature/205 asserções e cinco frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo quick_opportunity_search_increment_20261102 e manual. Sem dados reais inventados, instalação ou prova visual; requisito agregado parcial. [TENDER-ALERTS-20261102] ACT-11 local: escolha voluntária de concursos nas preferências existentes, sem alterar subscrições anteriores. Consulta pública e versões reutilizadas; sem rascunhos, propostas ou competências novas. Critérios próprios, frequência, cancelamento, proveniência e histórico; lotes por catálogo sem bloqueio da outra fonte. 30 testes distintos/607 asserções e seis frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo tender_alerts_increment_20261102 e manual de 02/11. Saldo de concursos do recorte anterior implementado em QA; incentivos/canais externos, instalação/agendador e visual pendentes. Requisito agregado parcial.","Implementado parcialmente — alertas do catálogo em QA local. Histórico anterior: Sem evidência suficiente","Continuidade 02/11/2026: oportunidades e concursos integrados em alertas no portal com escolha explícita e provas QA; pendência local de concursos do recorte anterior actualizada. Restam incentivos, canais externos, disponibilização/agendador, visual e correspondência dos restantes critérios agregados. Histórico preservado: 02/11/2026: alertas do catálogo público implementados e demonstrados em QA local. Restam disponibilização, visual, restantes fontes/canais de alertas e correspondência individual das demais capacidades desta cláusula; sem fecho transversal. Histórico preservado: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0124: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-e1169a77-0277: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-f70ce307-0133: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-51b8f0ad-0213: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-edece80c-0277: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos.",P2,MASTER-471012ab-0124: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0277: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0133: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0213: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0277: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0124 | MASTER-e1169a77-0277 | MASTER-f70ce307-0133 | MASTER-51b8f0ad-0213 | MASTER-edece80c-0277,5,"[{""id"":""MASTER-471012ab-0124"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1470""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-e1169a77-0277"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4318""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-f70ce307-0133"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1472""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-51b8f0ad-0213"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3106""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-edece80c-0277"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4318""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Continuidade 02/11/2026: oportunidades e concursos integrados em alertas no portal com escolha explícita e provas QA; pendência local de concursos do recorte anterior actualizada. Restam incentivos, canais externos, disponibilização/agendador, visual e correspondência dos restantes critérios agregados. Histórico preservado: 02/11/2026: alertas do catálogo público implementados e demonstrados em QA local. Restam disponibilização, visual, restantes fontes/canais de alertas e correspondência individual das demais capacidades desta cláusula; sem fecho transversal.
-Histórico: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [OPPORTUNITY-ALERTS-20261102] ACT-11 local: preferências e correspondência do catálogo público, confirmação, critérios, frequência, canal no portal e cancelamento; notificações de manifestações preservadas. 16 testes Feature/253 asserções e dois frontend aprovados; PHPStan, tipos, lint e compilação passaram. Fonte/versão/critério conservados; lote201, falha/repetição e migração com dados anteriores demonstrados. Recibo opportunity_alerts_increment_20261102 e manual de 02/11/2026. Sem instalação ou prova visual; fontes de concursos/incentivos e canais externos pendentes. [QUICK-SEARCH-COTTON-20261102] Pedido Tempo: plantio de algodao. Pesquisa combina palavras e variantes delimitadas de cultivo, normaliza acentos, usa hierarquia territorial pública e preserva filtros. Duas APIs, página, mapa e exportação consistentes; fichas de transformação apenas como relacionadas quando não existe correspondência completa. Barra GET/autofill. Nove testes Feature/205 asserções e cinco frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo quick_opportunity_search_increment_20261102 e manual. Sem dados reais inventados, instalação ou prova visual; requisito agregado parcial. [TENDER-ALERTS-20261102] ACT-11 local: escolha voluntária de concursos nas preferências existentes, sem alterar subscrições anteriores. Consulta pública e versões reutilizadas; sem rascunhos, propostas ou competências novas. Critérios próprios, frequência, cancelamento, proveniência e histórico; lotes por catálogo sem bloqueio da outra fonte. 30 testes distintos/607 asserções e seis frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo tender_alerts_increment_20261102 e manual de 02/11. Saldo de concursos do recorte anterior implementado em QA; incentivos/canais externos, instalação/agendador e visual pendentes. Requisito agregado parcial.",balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
+MASTER-471012ab-0124,"Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1470 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4318 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1472 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3106 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4318,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. Continuidade local: InvestmentOpportunityAlerts, InvestmentWorkspace, notificações e pesquisa públicas reutilizadas.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [OPPORTUNITY-ALERTS-20261102] ACT-11 local: preferências e correspondência do catálogo público, confirmação, critérios, frequência, canal no portal e cancelamento; notificações de manifestações preservadas. 16 testes Feature/253 asserções e dois frontend aprovados; PHPStan, tipos, lint e compilação passaram. Fonte/versão/critério conservados; lote201, falha/repetição e migração com dados anteriores demonstrados. Recibo opportunity_alerts_increment_20261102 e manual de 02/11/2026. Sem instalação ou prova visual; fontes de concursos/incentivos e canais externos pendentes. [QUICK-SEARCH-COTTON-20261102] Pedido Tempo: plantio de algodao. Pesquisa combina palavras e variantes delimitadas de cultivo, normaliza acentos, usa hierarquia territorial pública e preserva filtros. Duas APIs, página, mapa e exportação consistentes; fichas de transformação apenas como relacionadas quando não existe correspondência completa. Barra GET/autofill. Nove testes Feature/205 asserções e cinco frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo quick_opportunity_search_increment_20261102 e manual. Sem dados reais inventados, instalação ou prova visual; requisito agregado parcial. [TENDER-ALERTS-20261102] ACT-11 local: escolha voluntária de concursos nas preferências existentes, sem alterar subscrições anteriores. Consulta pública e versões reutilizadas; sem rascunhos, propostas ou competências novas. Critérios próprios, frequência, cancelamento, proveniência e histórico; lotes por catálogo sem bloqueio da outra fonte. 30 testes distintos/607 asserções e seis frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo tender_alerts_increment_20261102 e manual de 02/11. Saldo de concursos do recorte anterior implementado em QA; incentivos/canais externos, instalação/agendador e visual pendentes. Requisito agregado parcial. [FUNDING-ALERTS-20261102] ACT-11: versões publicadas de fundos/programas/incentivos do catálogo integradas no motor de alertas existente, com adesão explícita e preferências antigas preservadas. Filtros e desconhecidos explicados, origem/versão/estado conservados, retirada/acesso próprio, cancelamento, lote e reversão transaccional. 36 testes/612 asserções e seis frontend; PHPStan, tipos, lint e compilação aprovados. Recibo funding_alerts_increment_20261102 e manual. Sem canais externos, recolha externa ou instalação no activo; requisito agregado parcial. [FUNDING-ASSESSMENT-CONCURRENCY-20261102] Nove pares concorrentes observados aprovaram referências/versões/interesses, geradores duplicados, preferências idempotentes e ambas as precedências de cancelamento. Conferência de critérios mostra/envia apenas perguntas aplicáveis, preserva respostas locais e reinicia por ficha/versão. Oito frontend, tipos/lint/compilação aprovados; PHP da aplicação sem delta, provas 36 Feature/612 reutilizadas após conferir hashes. Recibo funding_assessment_concurrency_increment_20261102. Visual, vínculos de referência, canais externos e disponibilização continuam pendentes.","Implementado parcialmente — alertas do catálogo em QA local. Histórico anterior: Sem evidência suficiente","02/11/2026: concorrência do gerador verificada nos cenários delimitados e perguntas aplicáveis corrigidas. Restam visual, vínculos da referência, canais externos e disponibilização/agendador. Histórico: 02/11/2026: oportunidades, concursos e fundos/apoios do catálogo integrados em alertas locais com prova. Restam canais/outras fontes externas, concorrência específica do gerador, visual, vínculos de referência e disponibilização/agendador. Histórico: Continuidade 02/11/2026: oportunidades e concursos integrados em alertas no portal com escolha explícita e provas QA; pendência local de concursos do recorte anterior actualizada. Restam incentivos, canais externos, disponibilização/agendador, visual e correspondência dos restantes critérios agregados. Histórico preservado: 02/11/2026: alertas do catálogo público implementados e demonstrados em QA local. Restam disponibilização, visual, restantes fontes/canais de alertas e correspondência individual das demais capacidades desta cláusula; sem fecho transversal. Histórico preservado: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0124: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-e1169a77-0277: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-f70ce307-0133: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-51b8f0ad-0213: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos. | MASTER-edece80c-0277: Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos.",P2,MASTER-471012ab-0124: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0277: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0133: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0213: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0277: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0124 | MASTER-e1169a77-0277 | MASTER-f70ce307-0133 | MASTER-51b8f0ad-0213 | MASTER-edece80c-0277,5,"[{""id"":""MASTER-471012ab-0124"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1470""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-e1169a77-0277"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4318""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-f70ce307-0133"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1472""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-51b8f0ad-0213"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3106""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-edece80c-0277"",""pedido"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4318""],""aceitacao"":""Disponibilizar pesquisa, filtros, comparação, favoritos, alertas e recomendação de projectos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","02/11/2026: concorrência do gerador verificada nos cenários delimitados e perguntas aplicáveis corrigidas. Restam visual, vínculos da referência, canais externos e disponibilização/agendador. Histórico: 02/11/2026: oportunidades, concursos e fundos/apoios do catálogo integrados em alertas locais com prova. Restam canais/outras fontes externas, concorrência específica do gerador, visual, vínculos de referência e disponibilização/agendador. Histórico: Continuidade 02/11/2026: oportunidades e concursos integrados em alertas no portal com escolha explícita e provas QA; pendência local de concursos do recorte anterior actualizada. Restam incentivos, canais externos, disponibilização/agendador, visual e correspondência dos restantes critérios agregados. Histórico preservado: 02/11/2026: alertas do catálogo público implementados e demonstrados em QA local. Restam disponibilização, visual, restantes fontes/canais de alertas e correspondência individual das demais capacidades desta cláusula; sem fecho transversal.
+Histórico: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [OPPORTUNITY-ALERTS-20261102] ACT-11 local: preferências e correspondência do catálogo público, confirmação, critérios, frequência, canal no portal e cancelamento; notificações de manifestações preservadas. 16 testes Feature/253 asserções e dois frontend aprovados; PHPStan, tipos, lint e compilação passaram. Fonte/versão/critério conservados; lote201, falha/repetição e migração com dados anteriores demonstrados. Recibo opportunity_alerts_increment_20261102 e manual de 02/11/2026. Sem instalação ou prova visual; fontes de concursos/incentivos e canais externos pendentes. [QUICK-SEARCH-COTTON-20261102] Pedido Tempo: plantio de algodao. Pesquisa combina palavras e variantes delimitadas de cultivo, normaliza acentos, usa hierarquia territorial pública e preserva filtros. Duas APIs, página, mapa e exportação consistentes; fichas de transformação apenas como relacionadas quando não existe correspondência completa. Barra GET/autofill. Nove testes Feature/205 asserções e cinco frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo quick_opportunity_search_increment_20261102 e manual. Sem dados reais inventados, instalação ou prova visual; requisito agregado parcial. [TENDER-ALERTS-20261102] ACT-11 local: escolha voluntária de concursos nas preferências existentes, sem alterar subscrições anteriores. Consulta pública e versões reutilizadas; sem rascunhos, propostas ou competências novas. Critérios próprios, frequência, cancelamento, proveniência e histórico; lotes por catálogo sem bloqueio da outra fonte. 30 testes distintos/607 asserções e seis frontend aprovados; PHPStan, tipos, lint e compilação passaram. Recibo tender_alerts_increment_20261102 e manual de 02/11. Saldo de concursos do recorte anterior implementado em QA; incentivos/canais externos, instalação/agendador e visual pendentes. Requisito agregado parcial. [FUNDING-ALERTS-20261102] ACT-11: versões publicadas de fundos/programas/incentivos do catálogo integradas no motor de alertas existente, com adesão explícita e preferências antigas preservadas. Filtros e desconhecidos explicados, origem/versão/estado conservados, retirada/acesso próprio, cancelamento, lote e reversão transaccional. 36 testes/612 asserções e seis frontend; PHPStan, tipos, lint e compilação aprovados. Recibo funding_alerts_increment_20261102 e manual. Sem canais externos, recolha externa ou instalação no activo; requisito agregado parcial. [FUNDING-ASSESSMENT-CONCURRENCY-20261102] Nove pares concorrentes observados aprovaram referências/versões/interesses, geradores duplicados, preferências idempotentes e ambas as precedências de cancelamento. Conferência de critérios mostra/envia apenas perguntas aplicáveis, preserva respostas locais e reinicia por ficha/versão. Oito frontend, tipos/lint/compilação aprovados; PHP da aplicação sem delta, provas 36 Feature/612 reutilizadas após conferir hashes. Recibo funding_assessment_concurrency_increment_20261102. Visual, vínculos de referência, canais externos e disponibilização continuam pendentes.",balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-471012ab-0125,"Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”.",portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1471 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4319 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1473 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3107 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4319,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-471012ab-0125: Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”. | MASTER-e1169a77-0278: Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”. | MASTER-f70ce307-0134: Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”. | MASTER-51b8f0ad-0214: Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”. | MASTER-edece80c-0278: Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”.",P2,MASTER-471012ab-0125: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0278: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0134: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0214: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0278: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0125 | MASTER-e1169a77-0278 | MASTER-f70ce307-0134 | MASTER-51b8f0ad-0214 | MASTER-edece80c-0278,5,"[{""id"":""MASTER-471012ab-0125"",""pedido"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1471""],""aceitacao"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-e1169a77-0278"",""pedido"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4319""],""aceitacao"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-f70ce307-0134"",""pedido"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1473""],""aceitacao"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-51b8f0ad-0214"",""pedido"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3107""],""aceitacao"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-edece80c-0278"",""pedido"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4319""],""aceitacao"":""Implementar chamadas para acção: “Manifestar interesse”, “Solicitar dossier”, “Agendar reunião” e “Propor financiamento ou parceria”."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-471012ab-0126,Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas.,portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1505 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4354 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1507 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3141 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4354,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-471012ab-0126: Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas. | MASTER-e1169a77-0279: Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas. | MASTER-f70ce307-0135: Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas. | MASTER-51b8f0ad-0215: Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas. | MASTER-edece80c-0279: Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas.,P2,MASTER-471012ab-0126: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0279: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0135: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0215: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0279: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0126 | MASTER-e1169a77-0279 | MASTER-f70ce307-0135 | MASTER-51b8f0ad-0215 | MASTER-edece80c-0279,5,"[{""id"":""MASTER-471012ab-0126"",""pedido"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1505""],""aceitacao"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-e1169a77-0279"",""pedido"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4354""],""aceitacao"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-f70ce307-0135"",""pedido"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1507""],""aceitacao"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-51b8f0ad-0215"",""pedido"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3141""],""aceitacao"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-edece80c-0279"",""pedido"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4354""],""aceitacao"":""Identificar cadeia e localização → captar interesse → validar capacidade → formar grupos por elo → visitas → propostas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-471012ab-0127,Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento.,portal do investidor\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1515 | portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4364 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1517 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3151 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4364,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-471012ab-0127: Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento. | MASTER-e1169a77-0280: Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento. | MASTER-f70ce307-0136: Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento. | MASTER-51b8f0ad-0216: Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento. | MASTER-edece80c-0280: Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento.,P2,MASTER-471012ab-0127: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-e1169a77-0280: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0136: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0216: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0280: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-471012ab-0127 | MASTER-e1169a77-0280 | MASTER-f70ce307-0136 | MASTER-51b8f0ad-0216 | MASTER-edece80c-0280,5,"[{""id"":""MASTER-471012ab-0127"",""pedido"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""fontes"":[""portal do investidor\\upgrade do portal de investimentos.docx; SHA 471012abb0f56377956f4ab822fe3186e2561bee0471508a5d807091f2e0154f; w:p 1515""],""aceitacao"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-e1169a77-0280"",""pedido"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 4364""],""aceitacao"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-f70ce307-0136"",""pedido"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 1517""],""aceitacao"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-51b8f0ad-0216"",""pedido"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 3151""],""aceitacao"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-edece80c-0280"",""pedido"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 4364""],""aceitacao"":""Mapear janelas de financiamento → adaptar concept note → identificar consórcio → validar elegibilidade → submissão → seguimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
@@ -753,11 +753,11 @@ MASTER-e1169a77-0016,"Sequência de materialização: 1) criar a árvore normati
MASTER-e1169a77-0017,5.9.1. Documentos obrigatórios e controlos dos campos MIN88,portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 301 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 301,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,MASTER-e1169a77-0017: 5.9.1. Documentos obrigatórios e controlos dos campos MIN88 | MASTER-edece80c-0017: 5.9.1. Documentos obrigatórios e controlos dos campos MIN88,P2,MASTER-e1169a77-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-e1169a77-0017 | MASTER-edece80c-0017,2,"[{""id"":""MASTER-e1169a77-0017"",""pedido"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN88"",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 301""],""aceitacao"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN88"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-edece80c-0017"",""pedido"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN88"",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 301""],""aceitacao"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN88"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-e1169a77-0018,"A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento.","portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 420 | portal do investidor\Portal V4\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 80 | portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 122 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 420
-[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] SEG-bf26caee-p440 §2.1; SEG-bf26caee-p441 §2.1; SEG-bf26caee-p442 §2.1; SEG-bf26caee-p443 §2.1; SEG-bf26caee-p444 §2.1; SEG-bf26caee-p445 §2.1; SEG-bf26caee-p666 §6; SEG-bf26caee-p744 §6.1; SEG-bf26caee-p865 §8.6; SEG-bf26caee-p866 §8.6; SEG-bf26caee-p867 §8.6; SEG-bf26caee-p868 §8.6; SEG-bf26caee-p869 §8.6; SEG-bf26caee-p870 §8.6; SEG-bf26caee-p871 §8.6",Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-e1169a77-0018: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-f70ce307-0003: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-51b8f0ad-0003: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-edece80c-0018: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento.",P2,"MASTER-e1169a77-0018: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0018: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas
+[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] SEG-bf26caee-p440 §2.1; SEG-bf26caee-p441 §2.1; SEG-bf26caee-p442 §2.1; SEG-bf26caee-p443 §2.1; SEG-bf26caee-p444 §2.1; SEG-bf26caee-p445 §2.1; SEG-bf26caee-p666 §6; SEG-bf26caee-p744 §6.1; SEG-bf26caee-p865 §8.6; SEG-bf26caee-p866 §8.6; SEG-bf26caee-p867 §8.6; SEG-bf26caee-p868 §8.6; SEG-bf26caee-p869 §8.6; SEG-bf26caee-p870 §8.6; SEG-bf26caee-p871 §8.6",Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103. [PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa. [PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103. [PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa. [PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa.","Implementado parcialmente","Saldo 03/11/2026: painel factual, registo manual de experiências e contagens de pesquisa dos nove canais implementados/ensaiados localmente. A medição é de respostas HTTP registadas, não pessoas/pesquisas únicas, visitas ou utilização integral; recolha best effort e fontes não instrumentadas, incluindo fundos e correspondências internas, continuam identificadas. Restam aquisição/activação, comparação pública, correspondência CRM/qualificação/reuniões/diligência/propostas, investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte/pós-investimento; ligação transversal dos editores/alterações e execução/eventos de variantes. Pesos/pilotos de AUD-HUMAN-03 são definição distinta, sem score inventado. Visual/login real e disponibilização/migração no destino pendentes. Histórico anterior: Saldo 03/11/2026: painel factual e registo manual versionado implementados/ensaiados localmente. Restam ligação transversal das alterações/editores ao registo, atribuição/execução de variantes e eventos por grupo com consentimento/âmbito definidos; aquisição/activação, pesquisa/zero resultados, comparação pública, CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte e pós-investimento. Pesos/pilotos de AUD-HUMAN-03 permanecem uma definição distinta; nenhum score inventado. Visual/login real e disponibilização/migração no destino continuam pendentes. Histórico anterior: Saldo 03/11/2026: primeiro painel operacional local implementado; não equivale à cobertura integral de métricas de produto. Restam aquisição/activação, pesquisa e zero resultados, comparação pública, correspondência individual CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão do roteiro versionado, tempo projecto/submissão e etapas, abandono, satisfação/suporte, pós-investimento e registo de experiências controladas com hipótese/indicador/período/segmento/resultado/decisão. Não foram inventados pesos, baseline de pilotos, limiares, consentimentos ou eventos de visitantes. Visual/login real e disponibilização continuam pendentes. Histórico anterior: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-e1169a77-0018: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-f70ce307-0003: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-51b8f0ad-0003: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento. | MASTER-edece80c-0018: A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento.",P2,"MASTER-e1169a77-0018: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-f70ce307-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-51b8f0ad-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0018: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas
[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Fases0–4 do §2 são releases de desenvolvimento, não as cinco fases/19 etapas. Agrupamentos §3.3.1 não convertem categorias. Papéis genéricos §3.1 não concedem permissão. §6 contém estados documentais, não prova do ambiente atual. §7p811 não reabre credibilidade das fontes oficiais. SLA/ofertas/competências continuam decisões separadas. Disponibilidade do guia/modelos só por URL/exemplar verificado.",MASTER-e1169a77-0018 | MASTER-f70ce307-0003 | MASTER-51b8f0ad-0003 | MASTER-edece80c-0018; SEG-bf26caee-p440; SEG-bf26caee-p441; SEG-bf26caee-p442; SEG-bf26caee-p443; SEG-bf26caee-p444; SEG-bf26caee-p445; SEG-bf26caee-p666; SEG-bf26caee-p744; SEG-bf26caee-p865; SEG-bf26caee-p866; SEG-bf26caee-p867; SEG-bf26caee-p868; SEG-bf26caee-p869; SEG-bf26caee-p870; SEG-bf26caee-p871,19,"[{""id"": ""MASTER-e1169a77-0018"", ""pedido"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""fontes"": [""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 420""], ""aceitacao"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""estado"": ""parcial"", ""variantes"": ""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"", ""modulo"": ""Balcão/orientação""}, {""id"": ""MASTER-f70ce307-0003"", ""pedido"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""fontes"": [""portal do investidor\\Portal V4\\upgrade do portal de investimentos v1.docx; SHA f70ce3075523c6278e00dce15b9c7acf2b690679e16959ae5f7d007e754cfc6e; w:p 80""], ""aceitacao"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""estado"": ""parcial"", ""variantes"": ""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"", ""modulo"": ""Balcão/orientação""}, {""id"": ""MASTER-51b8f0ad-0003"", ""pedido"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""fontes"": [""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 122""], ""aceitacao"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""estado"": ""parcial"", ""variantes"": ""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"", ""modulo"": ""Balcão/orientação""}, {""id"": ""MASTER-edece80c-0018"", ""pedido"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""fontes"": [""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 420""], ""aceitacao"": ""A evolução do portal deve ser orientada por métricas de produto e experiências controladas. O painel deverá medir aquisição, activação, pesquisa, comparação, pedidos de dossier, qualificação, reuniões, diligência, propostas, investimento confirmado, tempo por etapa, abandono de formulários, pesquisa sem resultados, satisfação e utilização pós-investimento. Alterações de jornada, conteúdo, formulário ou campanha devem possuir hipótese, indicador, período de teste, segmento, resultado e decisão. Nenhum teste pode reduzir transparência, consentimento, segurança ou igualdade de tratamento."", ""estado"": ""parcial"", ""variantes"": ""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"", ""modulo"": ""Balcão/orientação""}, {""id"": ""SEG-bf26caee-p440"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p440"", ""first_paragraph"": 440, ""last_paragraph"": 440, ""text"": ""Experiência responsiva, acessível e orientada a tarefas."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p441"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p441"", ""first_paragraph"": 441, ""last_paragraph"": 441, ""text"": ""Fonte única de dados para evitar duplicações entre módulos e portais."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p442"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p442"", ""first_paragraph"": 442, ""last_paragraph"": 442, ""text"": ""Rastreabilidade entre requisito, regra, formulário, evidência e entidade responsável."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p443"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p443"", ""first_paragraph"": 443, ""last_paragraph"": 443, ""text"": ""Validação de campos, anexos, estados e permissões."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p444"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p444"", ""first_paragraph"": 444, ""last_paragraph"": 444, ""text"": ""Registo de auditoria, segurança, protecção de dados e controlo de versões."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p445"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""2.1"", ""locator"": ""word/document.xml#p445"", ""first_paragraph"": 445, ""last_paragraph"": 445, ""text"": ""Indicadores de utilização, conclusão de jornadas, erros e tempo de resposta."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p666"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""6"", ""locator"": ""word/document.xml#p666"", ""first_paragraph"": 666, ""last_paragraph"": 671, ""text"": ""INV-010 | Indicadores de utilização, abandono e conclusão | Sim | Parcial | QA | Demonstrar abandono, conclusão e tempos por jornada, módulo, sector e localização."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p744"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""6.1"", ""locator"": ""word/document.xml#p744"", ""first_paragraph"": 744, ""last_paragraph"": 750, ""text"": ""§8.6 | Indicadores de abandono, conclusão e tempo por jornada | INV-010 | Sim | Parcial | QA | Demonstrar fórmula, eventos, dimensões, período, fonte e painéis no ambiente activo."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p865"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p865"", ""first_paragraph"": 865, ""last_paragraph"": 865, ""text"": ""Percentagem de investidores que concluem o roteiro."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p866"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p866"", ""first_paragraph"": 866, ""last_paragraph"": 866, ""text"": ""Tempo médio entre criação do projecto e submissão completa."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p867"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p867"", ""first_paragraph"": 867, ""last_paragraph"": 867, ""text"": ""Taxa de formulários devolvidos por erro ou falta de documentação."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p868"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p868"", ""first_paragraph"": 868, ""last_paragraph"": 868, ""text"": ""Precisão das correspondências de fundos e oportunidades."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p869"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p869"", ""first_paragraph"": 869, ""last_paragraph"": 869, ""text"": ""Taxa de duplicados detectados nas importações."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p870"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p870"", ""first_paragraph"": 870, ""last_paragraph"": 870, ""text"": ""Disponibilidade do portal e tempo de resposta dos serviços críticos."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p871"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.6"", ""locator"": ""word/document.xml#p871"", ""first_paragraph"": 871, ""last_paragraph"": 871, ""text"": ""Satisfação dos utilizadores e redução de pedidos de suporte."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,"Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada
-[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Pedidos relacionados sem novo inventário/backlog paralelo; referência documental acrescentada, critérios anteriores preservados. Confirmar os bytes do v1(3) antes do fecho documental.",parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
+[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Pedidos relacionados sem novo inventário/backlog paralelo; referência documental acrescentada, critérios anteriores preservados. Confirmar os bytes do v1(3) antes do fecho documental.",parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Saldo 03/11/2026: painel factual, registo manual de experiências e contagens de pesquisa dos nove canais implementados/ensaiados localmente. A medição é de respostas HTTP registadas, não pessoas/pesquisas únicas, visitas ou utilização integral; recolha best effort e fontes não instrumentadas, incluindo fundos e correspondências internas, continuam identificadas. Restam aquisição/activação, comparação pública, correspondência CRM/qualificação/reuniões/diligência/propostas, investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte/pós-investimento; ligação transversal dos editores/alterações e execução/eventos de variantes. Pesos/pilotos de AUD-HUMAN-03 são definição distinta, sem score inventado. Visual/login real e disponibilização/migração no destino pendentes. Histórico anterior: Saldo 03/11/2026: painel factual e registo manual versionado implementados/ensaiados localmente. Restam ligação transversal das alterações/editores ao registo, atribuição/execução de variantes e eventos por grupo com consentimento/âmbito definidos; aquisição/activação, pesquisa/zero resultados, comparação pública, CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte e pós-investimento. Pesos/pilotos de AUD-HUMAN-03 permanecem uma definição distinta; nenhum score inventado. Visual/login real e disponibilização/migração no destino continuam pendentes. Histórico anterior: Saldo 03/11/2026: primeiro painel operacional local implementado; não equivale à cobertura integral de métricas de produto. Restam aquisição/activação, pesquisa e zero resultados, comparação pública, correspondência individual CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão do roteiro versionado, tempo projecto/submissão e etapas, abandono, satisfação/suporte, pós-investimento e registo de experiências controladas com hipótese/indicador/período/segmento/resultado/decisão. Não foram inventados pesos, baseline de pilotos, limiares, consentimentos ou eventos de visitantes. Visual/login real e disponibilização continuam pendentes. Histórico anterior: Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento; VirtualDesk/desk_cases/desk_requests/desk_events, histórico cifrado, manage-portal e PrivateInvestmentResponse existentes, serviços versionados, comparação e guias já entregues; manage-portal/PrivateInvestmentResponse, ProductUsageMetrics e definições/snapshots, cifragem Laravel, audit_events e mecanismos PostgreSQL de versões/histórico existentes; sem segundo workflow de decisão de investimento; resultados/paginadores públicos existentes, ProductUsageMetrics/ProductExperiments, permissões e snapshot de leitura existentes; sem segundo motor de pesquisa ou de decisões","A recolha agregada autorizada foi desenvolvida sem aguardar pesos/pilotos. Novos canais e execução de variantes dependem do âmbito/evento concreto; observação/instalação no destino mantêm os limites próprios. Registo manual e protecções de integridade desenvolvidos com a autoridade de gestão existente; não aguardam pesos de sucesso ou aprovação genérica. Execução/ligação automática de variantes e eventos requerem o âmbito e os pontos de integração concretos. Métricas observáveis desenvolvidas com as fontes operacionais disponíveis; não ficam genericamente bloqueadas pela definição de pesos/pilotos de AUD-HUMAN-03. Fontes/eventos/denominadores dos restantes indicadores e protecção da privacidade devem ser concretizados por incremento. Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolhas técnicas: coorte de pedidos criados no período UTC, estados deduplicados por pedido, histórico contíguo verificável, devoluções livres não classificadas automaticamente, médias excluem intervalos negativos. Não alteram regras de decisão ou garantem sucesso/investimento. Estado do registo e decisão são declarações do autor; não publicam alterações ou concedem competências. Data do primeiro registo não é retroactiva; alterações posteriores ficam identificadas. Relatório agregado não é amostra de controlo/variante. Referências de evidência são declaradas, sem importação/validação automática de anexos. Nenhuma experiência com pessoas reais foi executada. Unidade técnica explícita: resposta HTTP200 de primeira página com critério aplicado. Refresh/repetições contam de novo, bots/cache não são identificados. Sem termos/valores/IDs, não se mede aquisição, pessoas únicas ou causalidade. Orçamentos SQL são escolhas técnicas configuráveis, não SLA. Primeiro/último instante são metadados agregados por dia/canal. Não há backfill ou zero presumido.",Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. [PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103. [PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa. [PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa.",balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-e1169a77-0019,"Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas.",portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 421 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 421,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-e1169a77-0019: Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas. | MASTER-edece80c-0019: Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas.",P2,MASTER-e1169a77-0019: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0019: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-e1169a77-0019 | MASTER-edece80c-0019,2,"[{""id"":""MASTER-e1169a77-0019"",""pedido"":""Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 421""],""aceitacao"":""Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-edece80c-0019"",""pedido"":""Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 421""],""aceitacao"":""Antes da construção dos novos módulos, deverá ser concluída a Fase Zero definida nas secções 4.8.3 e 4.8.6, que concentra as melhorias imediatas da versão existente e os respectivos critérios de entrega. Esta etapa não depende de integrações institucionais ainda não confirmadas."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-e1169a77-0021,"A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados.",portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 423 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 423,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-e1169a77-0021: A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados. | MASTER-edece80c-0021: A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados.",P2,MASTER-e1169a77-0021: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0021: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-e1169a77-0021 | MASTER-edece80c-0021,2,"[{""id"":""MASTER-e1169a77-0021"",""pedido"":""A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 423""],""aceitacao"":""A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-edece80c-0021"",""pedido"":""A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 423""],""aceitacao"":""A implementação deverá partir de um diagnóstico técnico e funcional da versão actual do portal, identificando componentes reutilizáveis, dívida técnica, limitações de conteúdo, integrações existentes, qualidade dos dados, desempenho, segurança, acessibilidade e cobertura dos fluxos. Esse diagnóstico deverá produzir uma matriz Conservar, Melhorar, Substituir ou Descontinuar, evitando a reconstrução de funcionalidades estáveis e preservando os investimentos já realizados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
MASTER-e1169a77-0023,"O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM.",portal do investidor\Portal V4\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 437 | portal do investidor\Portal V4\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 437,oportunidades,/api/v1/business-opportunities; /api/v1/business-opportunities/{slug}; /investidor/terra-duat; /investidor/terra-duat/novo; /investidor/terra-duat/{id}; /investidor/terra-duat/{id}/actualizacoes; /investidor/terra-duat/{id}/documentos; /investidor/terra-duat/{id}/documentos/{attachment}; /investidor/terra-duat/{id}/editar; /investidor/terra-duat/{id}/imprimir; /investidor/terra-duat/{id}/solicitar-apoio; /management/opportunities,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-e1169a77-0023: O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM. | MASTER-edece80c-0023: O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM.",P2,MASTER-e1169a77-0023: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-edece80c-0023: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-e1169a77-0023 | MASTER-edece80c-0023,2,"[{""id"":""MASTER-e1169a77-0023"",""pedido"":""O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v6 programacao.docx; SHA e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e; w:p 437""],""aceitacao"":""O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-edece80c-0023"",""pedido"":""O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM."",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v5 programacao.docx; SHA edece80c0519537244f8a8b86456af0aa92de1c526f791bb0ee9b85af7a7e8b2; w:p 437""],""aceitacao"":""O upgrade deverá preservar, avaliar e aprofundar os cinco eixos informativos já apresentados no portal InvestMoz — “Porquê investir em Moçambique”, “Actividades económicas”, “Oportunidades de negócios”, “Áreas de investimento” e “Reguladores” — convertendo-os progressivamente de páginas predominantemente informativas numa jornada orientada à decisão e à conversão. Antes de substituir qualquer componente, a equipa deverá confirmar o seu uso, qualidade, dependências e possibilidade de reutilização. Cada conteúdo deverá conduzir o visitante da compreensão do mercado para a selecção de uma oportunidade, consulta de requisitos, manifestação de interesse e acompanhamento no CRM."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.opportunities: 6 registos; public.opportunity_images: tabela ausente; public.opportunity_documents: tabela ausente; public.opportunity_location_drafts: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/OpportunityManagement.php; app/Services/OpportunityResources.php; resources/js/pages/management/opportunity-draft.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"OpportunityManagementTest, OpportunityResourcesTest, OpportunityOriginReviewTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,,
@@ -4066,8 +4066,24 @@ AUD-FIELD-043,"Pesquisar, selecionar, guardar e recuperar no consumidor resource
AUD-FIELD-044,"Pesquisar, selecionar, guardar e recuperar no consumidor resources/js/pages/portfolio/index.tsx:77; B{Dados e documentos completos?}B -->|Não| B1[Guardar rascunho e indicar pendências]B1 --> AB -->|Sim| C[Submeter oportunidade]C --> C1{Serviço disponível e anexos íntegros?}C1 -->|Não| C2[Manter dados, registar incidente e tentar novamente]C2 --> C3{Prazo técnico excedido?}C3 -->|Não| C1C3 -->|Sim| ES1[Escalar para suporte e gestor operacional]ES1 --> C1C1 -->|Sim| D[Estado: Submetida]D --> E[Distribuição automática ao Validador]E --> F{Validador disponível e sem conflito?}F -->|Conflito| F1[Registar impedimento e reatribuir]F1 --> EF -->|Indisponível| F2{SLA de atribuição excedido?}F2 -->|Não| EF2 -->|Sim| ES2[Escalar ao coordenador de validação]ES2 --> EF -->|Sim| H[Validação técnica e documental]H --> H1{Dependência externa ou dúvida crítica?}H1 -->|Sim| H2[Estado: Pendente de parecer]H2 --> H3{Parecer recebido no prazo?}H3 -->|Sim| HH3 -->|Não| ES3[Escalar ao responsável técnico ou jurídico]ES3 --> HH1 -->|Não| I{Decisão}I -->|Corrigir| J[Registar motivo, campos e prazo]J --> K[Estado: Correcção solicitada]K --> K1{Promotor responde no prazo?}K1 -->|Sim| L[Corrigir e voltar a submeter]L --> DK1 -->|Não| K2[Enviar lembrete e conceder tolerância]K2 --> K3{Tolerância excedida?}K3 -->|Não| K1K3 -->|Sim| K4[Arquivar por inactividade, com reabertura autorizada]I -->|Corrigir novamente| J2{Limite de ciclos excedido?}J2 -->|Não| JJ2 -->|Sim| ES4[Escalar ao coordenador para decisão assistida]ES4 --> II -->|Rejeitar| M[Registar fundamento e evidências]M --> N[Estado: Rejeitada]N --> N1{Promotor apresenta recurso no prazo?}N1 -->|Não| N2[Encerrar processo]N1 -->|Sim| N3[Encaminhar a instância distinta de recurso]N3 --> N4{Decisão de recurso}N4 -->|Manter rejeição| N2N4 -->|Reabrir| DI -->|Aprovar| P[Estado: Aprovada]P --> Q[Publicador verifica aprovação, integridade e conformidade]Q --> R{Condições de publicação satisfeitas?}R -->|Não corrigível| S[Devolver para correcção administrativa]S --> JR -->|Risco grave ou ilegalidade| ES5[Suspender fluxo e escalar à gestão e conformidade]ES5 --> ES6{Decisão extraordinária}ES6 -->|Regularizar| SES6 -->|Cancelar| N2R -->|Sim| T[Publicar ou programar publicação]T --> T1{Publicação concluída?}T1 -->|Falha técnica| T2[Reverter, preservar versão e abrir incidente]T2 --> ES1T1 -->|Sim| U[Estado: Publicada]U --> V{Denúncia, erro material ou risco superveniente?}V -->|Não| UV -->|Sim| W[Suspensão preventiva com motivo e prazo]W --> X[Notificar responsáveis e iniciar revisão urgente]X --> Y{Resultado da revisão}Y -->|Repor| UY -->|Corrigir| SY -->|Arquivar| Z[Estado: Arquivada]"", ""fontes"": [""Gestao de perfis investeMOZ v1.docx | parágrafo 283 | SHA256 f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEV1-P0292"", ""pedido"": ""Suporte técnico; gestor operacional se o SLA técnico for excedido."", ""fontes"": [""Gestao de perfis investeMOZ v1.docx | parágrafo 292 | SHA256 f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEV1-P0293"", ""pedido"": ""Código do erro, tentativa, versão, utilizador, data e correlação do incidente."", ""fontes"": [""Gestao de perfis investeMOZ v1.docx | parágrafo 293 | SHA256 f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEV1-P0309"", ""pedido"": ""Número do ciclo, itens reincidentes e fundamentos."", ""fontes"": [""Gestao de perfis investeMOZ v1.docx | parágrafo 309 | SHA256 f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEOLD-P0261"", ""pedido"": ""Suporte técnico; gestor operacional se o SLA técnico for excedido."", ""fontes"": [""Gestao de perfis investeMOZ.docx | parágrafo 261 | SHA256 283a32f4c4b02bdfd9318a9174268224eeefac4349c49e3171545707bd222855""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEOLD-P0262"", ""pedido"": ""Código do erro, tentativa, versão, utilizador, data e correlação do incidente."", ""fontes"": [""Gestao de perfis investeMOZ.docx | parágrafo 262 | SHA256 283a32f4c4b02bdfd9318a9174268224eeefac4349c49e3171545707bd222855""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""PROFILEOLD-P0278"", ""pedido"": ""Número do ciclo, itens reincidentes e fundamentos."", ""fontes"": [""Gestao de perfis investeMOZ.docx | parágrafo 278 | SHA256 283a32f4c4b02bdfd9318a9174268224eeefac4349c49e3171545707bd222855""], ""aceitacao"": ""Falha técnica conserva submissão/versão, abre incidente e encaminha sem dar ao suporte permissão de decisão ou dados indevidos."", ""estado"": ""não implementado"", ""variantes"": ""Versão1.0 ou exemplar anterior preservados integralmente; divergências em perfis-v1-reconciliacao.md."", ""modulo"": ""perfis e oportunidades""}, {""id"": ""SEG-bf26caee-p860"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.4"", ""locator"": ""word/document.xml#p860"", ""first_paragraph"": 860, ""last_paragraph"": 860, ""text"": ""A operação deve definir níveis de suporte, canais de atendimento, horário, severidade, tempos de resposta e resolução, escalonamento, base de conhecimento e comunicação de indisponibilidades. Cada módulo e integração deve possuir proprietário técnico e funcional, painel de saúde, procedimento operacional, contacto de escalonamento e revisão periódica dos incidentes. A aceitação operacional deve ocorrer antes do Go-Live."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}, {""id"": ""SEG-bf26caee-p861"", ""source"": ""\\\\mac\\home\\Documents\\TEMPO\\Portal Tempo\\Servicos Tempo\\Relatorios\\novos\\segmentar processos v1.docx"", ""sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""section"": ""8.4"", ""locator"": ""word/document.xml#p861"", ""first_paragraph"": 861, ""last_paragraph"": 861, ""text"": ""O plano de adopção deve segmentar investidores, gestores de conteúdo, administradores, equipas de suporte e entidades participantes. Para cada grupo devem ser definidos materiais, sessões práticas, ambiente de treino, avaliação de competência, canal de dúvidas e acompanhamento após o lançamento. A comunicação deve explicar alterações, benefícios, responsabilidades, limitações do portal e procedimentos de contingência."", ""document_state_not_acceptance"": true, ""requested_exemplar_identity_pending"": true}]","Preparada em QA, sem demonstração visual. C37 e A/B mantidos pendentes.",Correspondência documental preparada; protocolo de incidentes da submissão não implementado neste workflow.,QA: entities canónicas/papéis/pedidos/workflow/audit_events; gravações sintéticas somente. Não inferir persistência dos fluxos descritos como pendentes.,Pedidos e rascunho15 recuperados em novas sessõesMFA; auditoria/revogação/dupla comprovadas nos escopos descritos. Outros critérios pendentes não fechados.,Props/JSON/mensagens de autorização verificados; resultado renderizado no navegador pendente.,"Mesmo CSV canónico.32requisitos funcionais novos; parágrafos de fontes preservados como ocorrências, incluindo estrutura/tabelas/casos, sem os contar como requisitos independentes.
-[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Pedidos relacionados sem novo inventário/backlog paralelo; referência documental acrescentada, critérios anteriores preservados. Confirmar os bytes do v1(3) antes do fecho documental.",não implementado,Leitura10/10: instalação040000ausente; PORTAL_PROFILE_ACCESS_ENABLED=false; nenhuma conta ativa alterada. QA18097: schema instalado e flagtrue.,"Recuperação técnica de uploads/worker existe, mas o suporte/incidentes por papel solicitado permanece ausente; não equivale ao suporte funcional completo.","Suporte/incidentes por perfil com recuperação e alertas próprios não implementado integralmente; falhas técnicas worker/upload anteriores são provas específicas, não o módulo de suporte.","OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.,oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Incidentes recuperáveis, suporte atribuído, falha de submissão/ficheiro sem perda, alertas e estados próprios.","Reutilizar entidades existentes; QA isolada; aceitação visual pendente. Dependências concretas descritas no critério/lacuna, sem bloquear trabalho independente.",Balcão/tarefas/audit_events existentes; suporte mapeado sem acesso documental automático; nenhum gestor fictício.,Correspondência documental preparada; protocolo de incidentes da submissão não implementado neste workflow. | Evidências privadas sanitizadas: profiles-v1-http-qa.json; profiles-v1-recovery-audit-qa.json; profiles-v1-final-qa.xml; profiles-v1-current-version-qa.json quando disponível.,Correspondência documental preparada; protocolo de incidentes da submissão não implementado neste workflow.,,,,"2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa.",,,
+[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Pedidos relacionados sem novo inventário/backlog paralelo; referência documental acrescentada, critérios anteriores preservados. Confirmar os bytes do v1(3) antes do fecho documental.",não implementado,Leitura10/10: instalação040000ausente; PORTAL_PROFILE_ACCESS_ENABLED=false; nenhuma conta ativa alterada. QA18097: schema instalado e flagtrue.,"Recuperação técnica de uploads/worker existe, mas o suporte/incidentes por papel solicitado permanece ausente; não equivale ao suporte funcional completo.","Suporte/incidentes por perfil com recuperação e alertas próprios não implementado integralmente; falhas técnicas worker/upload anteriores são provas específicas, não o módulo de suporte.
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Concluir assunção, notas, resolução/reabertura e histórico do incidente com este papel; alertas/saúde/outros consumidores, parâmetros/escalonamento aplicáveis, instalador e entrega. A escolha de perfil próprio foi decidida pelo proprietário e não é pendência.
+[TECHNICAL-INCIDENT-HANDLING-20261103] Continuar alertas próprios, saúde/outros pontos de falha, parâmetros/escalonamento aplicáveis, instalador e disponibilização/visual. Preparação não confirmada ainda em memória. Assunção, notas, resolução/reabertura e histórico deixam de ser lacunas de implementação neste recorte.
+[SUPPORT-PROFILE-INSTALLATION-20261103] Continuar avisos internos por âmbito, saúde/outros limites, configuração/escalonamento aplicáveis, instalação no destino/visual e retoma durável. Instalar o módulo e atribuir o perfil são acções distintas; a integração agora demonstrada deixa de ser lacuna de implementação.
+[SUPPORT-INCIDENT-NOTICES-20261103] Continuar saúde/outros limites técnicos, alertas de actualizações de tratamento quando aplicáveis, configuração/escalonamento definido, instalação no destino/visual e retoma durável. Consulta do aviso não resolve o incidente e não concede acesso aos documentos.
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Continuar despacho/execução de scans, workers/integrações, saúde operacional, outros limites e reconciliação de bytes retidos; configuração GD/instalação no destino, visual e retoma durável permanecem. Não declarar todos os pontos de falha cobertos.
+[SCAN-TECHNICAL-INCIDENTS-20261103] Continuar fiabilidade do despacho e saúde operacional com autoridade existente; concorrência física/carga, restantes fronteiras, reconciliação de bytes, GD/destino, retoma durável e instalação/visual pendentes.
+[SCAN-RETRY-20261103] Continuar saúde operacional e fiabilidade transaccional do despacho; contexto das restantes origens, concorrência/carga, reconciliação de bytes, destino/backup/restauro/visual e retoma durável pendentes.","OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Auditoria append-only, transacção do workflow, atribuições independentes/âmbito/vigência/revogação, no-store e navegação existentes.
+[TECHNICAL-INCIDENT-HANDLING-20261103] Mesma raiz/atribuição de suporte; auditoria append-only, Crypt, transacção e bloqueio da raiz, transporte CSRF/credenciais existentes. Investimento e documentos não são alterados pelo tratamento.
+[SUPPORT-PROFILE-INSTALLATION-20261103] Reutilizados instalação/lock/advisory/recibo/autenticação/MFA e Gestão de perfis; fonte única de disponibilidade por schema e ledger. Nenhuma atribuição automática ou alteração de dados de negócio.
+[SUPPORT-INCIDENT-NOTICES-20261103] Query autorizada da fila, bloqueio da raiz e auditoria append-only existentes; sem tabela, migração, destinatário externo ou segunda fonte de autoridade.
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Mesma raiz, papel/âmbitos, fila/avisos/tratamento e auditoria append-only; detector de ligação do Laravel, verificação de referências e savepoint. Scan/decisão/publicação continuam independentes.
+[SCAN-TECHNICAL-INCIDENTS-20261103] Mesmos grants/fila/avisos/tratamento, audit_events e contador de scans; afterCommit e UUID da fila; sem nova tabela ou privilégio.
+[SCAN-RETRY-20261103] UniqueLock/Dispatcher, lease por documento e owner, DocumentManagementAccess, afterCommit, histórico de scans e avisos/flash existentes; sem nova tabela, migração ou política de tentativas.","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Migração080000 somente QA; integração no instalador e entrega não executadas. Sem inventar SLA, responsáveis nominativos ou canal externo.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Proprietário: «Perfil próprio de Suporte técnico». Não concede decisão de investimento ou acesso documental automático; só metadados no âmbito actual e capturado.
+[TECHNICAL-INCIDENT-HANDLING-20261103] Perfil próprio já decidido pela Tempo. Tratamento técnico partilhado no âmbito efectivo; responsabilidade identificada não inventa competência exclusiva ou novas alçadas. Sem aprovação de investimento, SLA ou canal externo automático.
+[SUPPORT-PROFILE-INSTALLATION-20261103] Perfil próprio já decidido pelo proprietário. Actualização é escolha técnica dentro do instalador existente; provas preservam as condições já aprovadas, sem novo aprovador ou canal externo.
+[SUPPORT-INCIDENT-NOTICES-20261103] Perfil próprio decidido pelo proprietário. Aviso interno e consulta individual são escolhas técnicas no âmbito autorizado, sem novos aprovadores/SLA/canais ou pessoas reais.
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Perfil próprio já decidido pelo proprietário. Limpeza conservadora e extensão dos limites técnicos são implementação autorizada, sem novo destinatário/SLA/aprovador ou inferência de acesso aos documentos. GD activado apenas no CLI sintético, sem alterar a configuração activa.
+[SCAN-TECHNICAL-INCIDENTS-20261103] Perfil próprio já decidido pelo proprietário. Sistema identificado por actor null, conta iniciadora em metadado mínimo; suporte não ganha documento ou competência de repetir análise. Sem novo SLA/canal/destinatário.
+[SCAN-RETRY-20261103] Perfil próprio já decidido; Suporte técnico não ganha competência documental/repetição por inferência. Correcção técnica conserva as permissões e prazos existentes; reserva não declara job vivo.",Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.
+[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] [OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Registo automático de falhas técnicas de submissão/publicação, referência correlacionada, consulta própria e perfil próprio de Suporte técnico com fila por organização/tipo. Reutiliza auditoria append-only e atribuições existentes, sem aprovação ou acesso documental adicional.15 Feature/264 asserções (oito novos,sete anteriores);12 frontend (seis novos,seis anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Base final QA com59 tabelas vazias, owner/RLS/lock conferidos; primeira execução mista acompanhada separadamente.80 recibos/298 provas anteriores preservados. Recibo opportunity_technical_incidents_increment_20261103. Parcial local; migração do papel somente em QA, sem alterações no activo.
+[TECHNICAL-INCIDENT-HANDLING-20261103] [TECHNICAL-INCIDENT-HANDLING-20261103] Tratamento de incidentes pelo perfil existente: assunção/substituição explícita, notas cifradas, devolução à fila, resolução e reabertura, histórico privado paginado e filtros pelo estado actual. Versão e tentativa identificada preservam notas e impedem repetição de efeitos.18 Feature/339 asserções (dez novos,oito anteriores);28 frontend (16 novos,12 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Um cenário com dois processos e espera real no incidente:200/409, replay só de leitura, investimento e raiz intactos. QA final59 tabelas vazias; prova concorrente retém só amostras sintéticas declaradas.81 recibos/306 provas anteriores preservados. Recibo technical_incident_handling_increment_20261103. Parcial local, zero novas migrações/escritas activas.
+[SUPPORT-PROFILE-INSTALLATION-20261103] [SUPPORT-PROFILE-INSTALLATION-20261103] Actualização do perfil de Suporte técnico integrada no instalador autenticado existente: prévia, MFA, provas do destino/código, confirmação e recibo idempotente. Schema e ledger partilham a mesma verificação no servidor e na disponibilidade do perfil.18 Feature finais/230 asserções (dez novos,oito do instalador anterior); regressão inicial36/569;30 frontend (15 novos,15 do tratamento anterior),PHPStan/Pint/tipos/formato/lint/build aprovados. Backup PostgreSQL e arquivo de candidato/original privado sintético efectivamente restaurados em QA: 190 tabelas,30 sequências,1567 ficheiros e três envelopes MFA legíveis. Actualização e repetição conservaram todas as tabelas salvo uma entrada de migração e um recibo; zero atribuições de suporte inferidas. QA de testes62 tabelas vazias.82 recibos/318 provas anteriores preservados. Recibo support_profile_installation_increment_20261103. Parcial local, sem instalação/escrita activa.
+[SUPPORT-INCIDENT-NOTICES-20261103] [SUPPORT-INCIDENT-NOTICES-20261103] Avisos internos de incidentes por consultar para o Suporte técnico efectivo, com contador próprio na navegação, filtro antes da paginação e marca explícita de consulta por actor/raiz. A consulta não é tratamento, resolução, aprovação ou acesso documental.25 Feature finais/376 asserções (sete novos,18 de instalação anteriores);31 frontend (nove novos,22 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. QA62 tabelas vazias e identidade/owner/RLS/FORCE conferidos.83 recibos/330 provas anteriores preservados. Recibo support_incident_notices_increment_20261103. Parcial local, sem migração ou escrita activa.
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] [RESOURCE-TECHNICAL-INCIDENTS-20261103] Incidentes de upload de documentos/imagens e preparação WebP integrados no mesmo suporte, avisos e tratamento por âmbito. Limpeza conservadora conserva originais referenciados e bytes de resultado incerto; falhas na limpeza não escondem o erro original.23 Feature/285 asserções (oito novos,cinco de recursos e dez do instalador); um caso adicional sem GD/duas asserções;37 frontend (seis novos,31 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. GD/WebP carregado apenas no processo CLI de QA; configuração normal sem alteração. QA64 tabelas vazias, com identidade/owner/RLS/FORCE conferidos.84 recibos/339 provas anteriores preservados. Recibo resource_technical_incidents_increment_20261103. Parcial local, sem migração ou escrita activa.
+[SCAN-TECHNICAL-INCIDENTS-20261103] [SCAN-TECHNICAL-INCIDENTS-20261103] Falhas no despacho e execução da análise de documentos ligadas ao Suporte técnico por contexto capturado e acesso actual. Tentativas e callbacks identificados no histórico existente; resultados antigos não substituem resultados posteriores, e falha de confirmação da fila não reverte um documento já limpo.30 Feature/365 asserções finais (15 novos,cinco de recursos,dez do instalador), com42/574 anteriores sobrepostos;43 frontend (seis novos). PHPStan/Pint/tipos/formato/lint/build aprovados.67 tabelas QA vazias. Uma mensagem de fila real consumida por outro processo, com ClamD deliberadamente indisponível: inconclusivo, quarentena, original cifrado intacto,zero temporários e incidente próprio.85 recibos/351 provas preservados;14 provas novas. Recibo scan_technical_incidents_increment_20261103. Parcial local,zero escrita/migração activa.
+[SCAN-RETRY-20261103] [SCAN-RETRY-20261103] Repetição da análise distingue aceite, reserva existente, contexto alterado, envio não confirmado e envio diferido. Reserva existente não altera o documento nem duplica o pedido; falha tardia não sobrepõe clean/infected/scanning. Mesma autoridade documental, revalidada após commit, com auditoria da preparação e original preservado. Botão dos anexos de zonas usa resposta Inertia; avisos aparecem também na gestão documental.36 Feature/378 asserções (11 novos,15 de scans,dez do instalador),24/228 iniciais sobrepostos e47 frontend (quatro novos),PHPStan/Pint/tipos/formato/lint/build aprovados.69 tabelas QA vazias. Ensaio com reserva em cache PostgreSQL e fila reais: segundo pedido preservou190 tabelas; outro processo consumiu uma mensagem e libertou a reserva do seu dono. ClamD deliberadamente indisponível manteve quarentena, cifra e histórico,zero temporários.86 recibos/365 provas preservados;14 novas provas. Recibo scan_retry_increment_20261103. Parcial local,zero escrita/migração activa.",oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Incidentes recuperáveis, suporte atribuído, falha de submissão/ficheiro sem perda, alertas e estados próprios.","Reutilizar entidades existentes; QA isolada; aceitação visual pendente. Dependências concretas descritas no critério/lacuna, sem bloquear trabalho independente.",Balcão/tarefas/audit_events existentes; suporte mapeado sem acesso documental automático; nenhum gestor fictício.,Correspondência documental preparada; protocolo de incidentes da submissão não implementado neste workflow. | Evidências privadas sanitizadas: profiles-v1-http-qa.json; profiles-v1-recovery-audit-qa.json; profiles-v1-final-qa.xml; profiles-v1-current-version-qa.json quando disponível.,Correspondência documental preparada; protocolo de incidentes da submissão não implementado neste workflow.,,,,"2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa.",,,
AUD-PROFILE-21,Recurso com instância independente e conservação da decisão original,"Pedido direto do responsável10/10/2026 nesta conversa
[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] SEG-bf26caee-p160 §1.6; SEG-bf26caee-p161 §1.6; SEG-bf26caee-p163 §1.7; SEG-bf26caee-p164 §1.7; SEG-bf26caee-p165 §1.7; SEG-bf26caee-p166 §1.7; SEG-bf26caee-p167 §1.7; SEG-bf26caee-p168 §1.7; SEG-bf26caee-p169 §1.7; SEG-bf26caee-p170 §1.7; SEG-bf26caee-p660 §6; SEG-bf26caee-p681 §6.1",perfis e oportunidades,/dashboard; /perfil/promotor; /minhas-oportunidades; /perfis/gestao; /perfis/auditoria; /perfis/*,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.,Implementado parcialmente,"Perfis e transições das seis categorias base demonstrados em QA; atribuições reais ativas. Restam variantes e ações não abrangidas pelos recibos específicos, conforme workflow-criterios-saida-20261011.md. Não tratar todos os consumidores como concluídos; manter independência, auditoria e contexto por organização/tipo.","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Recurso não sobrescreve decisão; revisor distinto e autorizado decide com razão, sem publicar.",P1,"Exemplar anterior e v1 preservados. Administração integral anterior passa a controlada na v1; edição organizacional aprovada nesta conversa; Promotor solicita arquivo; gestores legados não se tornam Superutilizadores. p337/p355/SU04/SU05/GOV01 acrescentam governança/atomicidade.
@@ -9742,11 +9976,20 @@ AUD-PROFILE-25,"Interface responsiva, gravação segura, erros e acompanhamento"
Gestao de perfis investeMOZ.docx | parágrafo 320 | SHA256 283a32f4c4b02bdfd9318a9174268224eeefac4349c49e3171545707bd222855
-[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] SEG-bf26caee-p481 §3.2.2",perfis e oportunidades,/dashboard; /perfil/promotor; /minhas-oportunidades; /perfis/gestao; /perfis/auditoria; /perfis/*,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.; correspondência explícita de prova agrupada: A11Y-OP
+[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] SEG-bf26caee-p481 §3.2.2",perfis e oportunidades,/dashboard; /perfil/promotor; /minhas-oportunidades; /perfis/gestao; /perfis/auditoria; /perfis/*,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.
+[INVESTMENT-PROFILE-COMMANDS-20261103] Perfil e declarações privadas com recibo idempotente por conta, preparação conservada, comparação/adopção explícita de versões, erro por campo único e limites/multilinha adequados.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] País organizacional com comando repetível, reautorização após lock, preparação conservada, comparação/adopção explícita, erro único e recuperação de permissão consultada no mesmo contexto.
+[ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita com consulta/pré-visualização, confirmação repetível cifrada, versões/fonte preservadas, acesso actual no replay e mutex com o formulário para não substituir edições.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.; correspondência explícita de prova agrupada: A11Y-OP
-[B8 QA 13/10/2026] 18/18posições técnicas satisfeitas na mesma checklist;8visuaisabertos,22grupos preservados. Restante6–10h apenasL4/consolidação; não é percentagem do produto, fecho global ou candidatafinal. Sete fontesQA/bundle recompilado, sem alteraçõesativas;A/B/C37/COUNTRY02 preservados;C132 separado.",Implementado parcialmente,"320/390px, teclado e axe de rotas anteriores preservados; restam leitor/zoom/PDFs/dispositivos reais e novos erros do contacto. GET não demonstra apresentação.
+[B8 QA 13/10/2026] 18/18posições técnicas satisfeitas na mesma checklist;8visuaisabertos,22grupos preservados. Restante6–10h apenasL4/consolidação; não é percentagem do produto, fecho global ou candidatafinal. Sete fontesQA/bundle recompilado, sem alteraçõesativas;A/B/C37/COUNTRY02 preservados;C132 separado.
+[INVESTMENT-PROFILE-COMMANDS-20261103] [INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] [ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa.
+[ORGANIZATION-COUNTRY-REUSE-20261103] [ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa.",Implementado parcialmente,"320/390px, teclado e axe de rotas anteriores preservados; restam leitor/zoom/PDFs/dispositivos reais e novos erros do contacto. GET não demonstra apresentação.
-[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Formulários recuperam dados, mostram ações/erros/pendências e não perdem resposta; navegação acessível por perfil.",P1,"Exemplar anterior e v1 preservados. Administração integral anterior passa a controlada na v1; edição organizacional aprovada nesta conversa; Promotor solicita arquivo; gestores legados não se tornam Superutilizadores. p337/p355/SU04/SU05/GOV01 acrescentam governança/atomicidade.
+[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.
+[INVESTMENT-PROFILE-COMMANDS-20261103] Recuperação/repetição do perfil e declarações cobertas neste incremento; continuam editor do cadastro mestre organizacional, demais consumidores/perfis, retoma durável/expiração, visual e destino.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] Editor do país organizacional coberto neste incremento; restam reutilização explícita na declaração, demais consumidores/perfis, retoma durável/expiração, visual e disponibilização.
+[ORGANIZATION-COUNTRY-REUSE-20261103] Editor e reutilização do país cobertos neste recorte; permanecem outros consumidores/perfis, retoma durável/expiração, visual, preenchimento real autorizado e destino.","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Formulários recuperam dados, mostram ações/erros/pendências e não perdem resposta; navegação acessível por perfil.",P1,"Exemplar anterior e v1 preservados. Administração integral anterior passa a controlada na v1; edição organizacional aprovada nesta conversa; Promotor solicita arquivo; gestores legados não se tornam Superutilizadores. p337/p355/SU04/SU05/GOV01 acrescentam governança/atomicidade.
[Workflow QA 11/10/2026 — critérios de saída] Pendências históricas substituídas apenas nos subcritérios demonstrados, conservadas: {""Lacuna"": ""[C37 fechado QA18 10/10/2026] C37 não é mais pendência de autenticação QA18; permanecem os demais critérios do requisito. Histórico abaixo preservado e superado apenas neste âmbito. | [Visual QA 10/10/2026] C37: confirmar atualização, logout e novo login no navegador habitual; confirmação de acesso não encerra todo o ciclo. ERR_TOO_MANY_REDIRECTS não foi demonstrado como ciclo persistente pelo rastreio; distinguir409 de atualização Inertia de rejeiçãoMFA e de autorização403. Outros perfis/dispositivos/consumidores pendentes. | Histórico preservado: [Visual QA 10 /10/2026 ] C37 : confirmar atualização, logout e novo login no navegador habitual; confirmação de acesso não encerra todo o ciclo. ERR_TOO_MANY_REDIRECTS não foi demonstrado como ciclo persistente pelo rastreio; distinguir 409 de atualização Inertia de rejeição MFA e de autorização 403. Outros perfis /dispositivos/consumidores pendentes. | Histórico preservado: Demonstração visual /acessibilidade , autosave e erros por campo nos contratos completos. | [Workflow QA 10 /10/2026 ] Nenhum clique /render observado:dashboard→contratos /erros →workflow→recuperação ainda exige navegador; geometrias /parcela e objetos sem editor completo permanecem abertos. | [Semântica QA 10 /10/2026 ] C37 e navegação /render/erros/seletores/ciclo por conta 21 ainda pendentes; código e props não demonstram cliques. Preserva nova sessão e acesso direto às ferramentas. | [C85/logout QA 10/10/2026] C37: logout manual QA18 demonstrado; F5 explícito e novo login/MFA QA18 após este logout ainda por confirmar. Nova sessão Chromium QA21 demonstrada separadamente. Restantes consumidores, perfis, critérios A/B, móvel/acessibilidade integral e ativação não encerrados por este ensaio."", ""Dependência"": ""Reutilizar entidades existentes; QA isolada; aceitação visual pendente. Dependências concretas descritas no critério/lacuna, sem bloquear trabalho independente. | [Workflow QA 10/10/2026] Continuar componentes canónicos/workflow/tarefas existentes; seis categorias estruturais disponíveisQA, quatro dependem de perfil modular versionado aprovado. Visual/C37, semântica/editor e políticas reais mantêm-se abertos conforme lacuna. Não requer integração externa para preparação interna.""}
@@ -9792,9 +10035,21 @@ Gestao de perfis investeMOZ.docx | parágrafo 320 | SHA256 283a32f4c4b02bdfd9318
[QA 11/10/2026 — arrendamento54 completo / consolidada] C125/f07f34a11eab integrado na próxima revisão única; candidata3d9d392e0a0f preservada. Apenas critérios acima encerrados; requisito geral conserva o estado.",parcial,"COUNTRY02 ativo485ee04c40b2 preservado, somente050000; ativo288tabelas/13contas/0org/representações,030/040/190 ausentes e flags restantesOFF conforme prova ativa anterior. Incremento somente cópiaQA, nenhuma escrita/configuração/aplicação ativa. Hashes críticos ativos e todos os assets conservados.
-[Candidata workflow QA 11/10/2026 — fecho do lote] Nenhuma escrita ativa;288tabelas13contas0org/representações,020/050presentes,COUNTRY02ON,demaisflagsOFF. QA295tem7tabelas de030/040 adicionais; não importar/povoar por inferência. Reversão/limites/decisões no pacote.","Capacidades/provas específicas anteriores existem, mas o requisito agregado ainda tem os critérios restantes explicitados; fechos parciais preservados.",[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.; visao-consolidada-modulos.md e proof-groups.json: A11Y-OP
+[Candidata workflow QA 11/10/2026 — fecho do lote] Nenhuma escrita ativa;288tabelas13contas0org/representações,020/050presentes,COUNTRY02ON,demaisflagsOFF. QA295tem7tabelas de030/040 adicionais; não importar/povoar por inferência. Reversão/limites/decisões no pacote.","Capacidades/provas específicas anteriores existem, mas o requisito agregado ainda tem os critérios restantes explicitados; fechos parciais preservados.","[B8 QA 13/10/2026] Somente oito percursos visuaisL4/C135 e consolidação/backup-restauroQA da revisãofixa restam na checklistB; não há exigência técnica genérica nova. Requisito agregado continua parcial; critérios foraB e ativação separados.
+[INVESTMENT-PROFILE-COMMANDS-20261103] Continuar editor do país organizacional e consumidores restantes; manter fonte única, versões, autorização e snapshots anteriores. Visual/móvel, retoma durável, preenchimento real autorizado e disponibilização continuam pendentes.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] Continuar recuperação/idempotência do botão de reutilização e consumidores restantes; conservar snapshots, representação, fonte e separação residência/constituição/origem. Retoma durável, visual/móvel, preenchimento real autorizado e destino pendentes.
+[ORGANIZATION-COUNTRY-REUSE-20261103] Confrontar os consumidores e preparações restantes com a matriz; manter fonte única, versões, representação actual e snapshots históricos. Retoma durável, visual/móvel, backup/restauro e disponibilização pendentes.","OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources
+[INVESTMENT-PROFILE-COMMANDS-20261103] Fortify/conta existente, CountryCatalogue/CountrySelect, users row lock, audit_events cifrado, versões/ACL do workspace, transportes/UUID/guarda Inertia existentes; sem nova tabela ou cadastro duplicado.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] Mesmo InvestmentProfileCommands/audit_events cifrado, users/memberships/organizations e versões existentes; hook/editor comuns, selector ISO, transportes e guarda única da página. Sem nova tabela, migração ou cadastro paralelo.
+[ORGANIZATION-COUNTRY-REUSE-20261103] Mesmo InvestmentProfileCommands/audit_events cifrado, readableSnapshot com locks, declaração/organização existentes, transportes/UUID e guarda de saída da página; sem novo cadastro ou migração.","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.
+[INVESTMENT-PROFILE-COMMANDS-20261103] Correcção técnica autorizada de repetição/erros, sem novo destinatário, aprovador ou condição de representação. Residência, constituição, país histórico e origem continuam separados; nenhuma inferência do país real ou de vínculo por nome.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] Correcção técnica autorizada, mantendo papéis existentes e prevalência do Auditor. Permissão consultada não concede representação nem dispensa autorização de escrita/replay no servidor. Não se infere país real ou vínculo por nome.
+[ORGANIZATION-COUNTRY-REUSE-20261103] Correcção técnica autorizada da operação de leitura/reutilização existente, incluindo viewer no seu âmbito. Não concede edição do mestre, representação ou aprovação; país e fonte são obtidos no servidor, sem correspondência por nome.",Completar critérios restantes sem repetir provas válidas,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/reused-evidence-integrity.json: 35 recibos anteriores com hashes correspondentes; o âmbito de cada recibo permanece limitado ao critério ensaiado. outputs/investmoz-audit-current-20261012/http-promoter.json; http-validator.json; http-publisher.json; http-manager.json.; visao-consolidada-modulos.md e proof-groups.json: A11Y-OP
-[B8 QA 13/10/2026] 18/18posições técnicas satisfeitas na mesma checklist;8visuaisabertos,22grupos preservados. Restante6–10h apenasL4/consolidação; não é percentagem do produto, fecho global ou candidatafinal. Sete fontesQA/bundle recompilado, sem alteraçõesativas;A/B/C37/COUNTRY02 preservados;C132 separado.",oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Restauro de oportunidade proposta R-ARCHIVE/R-DRAFT, sem implementação antecipada. Variantes por modalidade e contratos §25 ainda por critério, conforme tabela por categoria; Response§27 de compatibilidade com normative_response_complete=false (IDs/história/estados preservados). Interesse no anúncio público de negócio existente e outras variantes de país/estatística/mapa/documento têm consumidores separados.173correspondências eMandie/Guro; partilha individual de documentos de oportunidade não criada. Leitor de ecrã, PDF etiquetado e dispositivos reais pendentes. Sem fecho global por contagem de testes.
+[B8 QA 13/10/2026] 18/18posições técnicas satisfeitas na mesma checklist;8visuaisabertos,22grupos preservados. Restante6–10h apenasL4/consolidação; não é percentagem do produto, fecho global ou candidatafinal. Sete fontesQA/bundle recompilado, sem alteraçõesativas;A/B/C37/COUNTRY02 preservados;C132 separado.
+[INVESTMENT-PROFILE-COMMANDS-20261103] [INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa.
+[ORGANIZATION-COUNTRY-EDITOR-20261103] [ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa.
+[ORGANIZATION-COUNTRY-REUSE-20261103] [ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa.",oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Restauro de oportunidade proposta R-ARCHIVE/R-DRAFT, sem implementação antecipada. Variantes por modalidade e contratos §25 ainda por critério, conforme tabela por categoria; Response§27 de compatibilidade com normative_response_complete=false (IDs/história/estados preservados). Interesse no anúncio público de negócio existente e outras variantes de país/estatística/mapa/documento têm consumidores separados.173correspondências eMandie/Guro; partilha individual de documentos de oportunidade não criada. Leitor de ecrã, PDF etiquetado e dispositivos reais pendentes. Sem fecho global por contagem de testes.
[QA 11/10/2026 — arrendamento54/C125] Critérios agora demonstrados: edição/validação de renda e recuperação do rascunho de arrendamento54; navegação sem opções duplicadas. Continuam pendentes submissão, revisão, documentos aplicáveis e publicação específicas de arrendamento, demais variantes categoria/Response§27, restauração por decidir e acessibilidade integral. Os códigos monthly e demais enums conservam o valor canónico; apresentação traduzida desses rótulos continua P2. Não encerra o requisito completo.
@@ -10565,31 +10820,31 @@ AUD-LEG-07,"Verificar imagens, anexos, links, pesquisa, permissões e duplicaç
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",documentos e legado,15/10/2026 — fecho do piloto ativo e preparação por leitura dos restantes setores; sem novos testes funcionais.,,,"[Visual QA 10/10/2026] Cobertura integral, mais perfis/dispositivos, leitor de ecrã e editor administrativoC74 não demonstrados. Mercado Financeiro permanece privado/corpo vazio confirmado na origem; rotas404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia/Mineração. | Histórico preservado: [Visual QA 10 /10/2026 ] Cobertura integral, mais perfis /dispositivos , leitor de ecrã e editor administrativo C74 não demonstrados. Mercado Financeiro permanece privado /corpo vazio confirmado na origem; rotas 404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia /Mineração. | Histórico preservado: 22 originais /5 imagens /hashes/scans/replay e 16 novos artigos públicos testados;32 versões restantes, anexos /links externos /C68 ,móvel /acessibilidade e perfis adicionais por testar. | Histórico anterior: Imagens /links/pesquisa/permissões/deduplicação do piloto demonstrados. Anexos /referências dos restantes conteúdos e imagem histórica 404 por resolver; cobertura global permanece parcial.",Biblioteca/documentos existentes; Balcão+09/190000 para dossier. Expansão cartográfica exige correspondências fundamentadas. C37/A-B/SLA/perfis e ativação mantêm âmbito próprio.,Dois originais com ClamD real/hash; links dos consumidores200; pesquisahit/miss; permissões; repetição do importador sem novas linhas e associação idempotente.,"[Interface legado QA 10 /10/2026 ] Chromium instalado, contextos isolados, desktop 1440 px / móvel 390 px: fotografia /fontes/paleta , pesquisa hit /miss , Enter /foco de 3 px, links carteira /zonas/biblioteca/oportunidade. Promotor QA21 : login→MFA→dossier→fonte→retorno→logout→novo contexto /MFA →recuperação /F5 →associação repetida. Conta 23:403 e artigo público sem título privado; anónimo sem contexto privado. UI observada; referência /evento únicos e originais /hash/scan confirmados em leitura QA. legacy-content-browser-qa.json ; legacy-content-browser-persistence-qa.json ; legado-piloto-qa.md . | Evidência anterior preservada: legado-piloto-qa.md ; legacy-content-http-qa.json : recursos 6 /5 públicos, hashes verificados, pesquisa, login /MFA21 , criação /continuação , logout /nova sessão, recuperação, replay único e isolamento. Interface não observada. | [Confirmação manual recebida 10 /10/2026 ] Responsável confirmou leitura pública → autenticação → criar /escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta /perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37 /QA18 ou A /B. Ver legado-piloto-qa.md , confirmação manual. | [Setores QA após C71 10 /10/2026 ] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos /recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia 200. Chromium desktop:16 artigos, pesquisa /imagens , Energia e Mineração distintas, C72 título preservado; QA21 criou 4 dossiers, retorno, logout /novaMFA/F5/replay ; QA23 negado 403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP /Chromium , uma referência /evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence} -qa.json ; legacy-financial-origin-20261010 /proof.json. C37 /QA18 ,A /B ,móvel /acessibilidade/cobertura integral não encerrados. | [Visual QA 10 /10/2026 ] Falhas C77 – C83 corrigidas em QA: landmarks, nome ARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal /hash , tabelas financeiras focáveis por teclado, reflow de tarefas /select/data no dossier, langpt-MZ apenas no router QA e proteção da recuperação assíncrona do simulador. Após correções 15 execuções axe /390 –320–1440 px,0 violações automáticas /0overflow e idioma PT; skiplink primeiro Tab→conteúdo em 3 páginas; tabelas financeiras focadas /teclas no Chromium . Não equivale a leitor de ecrã, zoom /dispositivo real ou cobertura de todo oportal. Legacy Content Test 5 /84 e rastreio MFA 1 /14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos. | [Visual QA 10/10/2026] FalhasC77–C83 corrigidas emQA: landmarks, nomeARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal/hash, tabelas financeiras focáveis por teclado, reflow de tarefas/select/data no dossier, langpt-MZ apenas no routerQA e proteção da recuperação assíncrona do simulador. Após correções15execuções axe/390–320–1440px,0violações automáticas/0overflow e idiomaPT; skiplink primeiroTab→conteúdo em3páginas; tabelas financeiras focadas/teclas no Chromium. Não equivale a leitor de ecrã, zoom/dispositivo real ou cobertura de todo oportal. LegacyContentTest5/84 e rastreioMFA1/14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos.","GET públicos e escritas autenticadas no servidor18097, alvo real55441 confirmado; publicação separada do importador. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.",,,"Fecho exclusivo do piloto agronegócio; não cobre todo o acervo, versões, URLs, anexos ou setores. Mercado Financeiro vazio continua separado.","2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa.",,,
-AUD-MARKET-01,"Negócios similares por área, raio, sector e classificação, com fonte, data e cobertura",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-004; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p630; SEG-bf26caee-p716,INV-004 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","ExistingBusiness, InvestmentGeography e taxonomias existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | 02/11/2026: primeiro consumidor local de negocios semelhantes na ficha publica, mesma modalidade e sector conhecido; reutiliza catalogo publico e filtros, exclui origem/duplicados. Frontend 2 testes; Feature 3/158 assercoes em QA isolada; tipos, lint, PHPStan e build aprovados. Parcial: sem raio/distancia, fonte/data individuais ou prova visual; sem instalacao. Ver manual existente. | Continuidade 02/11/2026: provincia principal apenas quando divulgada/consultavel; classificacao publica escolhida expressamente conserva tipo, alvo e finalidade, sem transferir seleccao entre fichas. Fonte do catalogo e data de publicacao explicitas, origem factual nao inferida; resposta malformada e erro recuperavel. Quatro testes frontend do consumidor passaram; ver manual. Raio e proveniencia externa continuam pendentes.",Não implementado,Consulta de negócios similares por raio/classificação não implementada.,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Filtro por área/raio/sector recuperável, fonte/data/cobertura explícitas; ausência de dados não produz comparação inventada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",Pesquisa combina raio/sector/classificação; apresenta fonte/data/cobertura/limitações; recupera os mesmos registos; não mostra dados privados nem locais sem correspondência.,P2,"Código INV-004 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p630; SEG-bf26caee-p716,6,"[{""id"": ""SEG-bf26caee-p99"", ""section"": ""1.0.2"", ""first_paragraph"": 99, ""last_paragraph"": 103, ""text"": ""Artigos 5 a 10 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Classificação da empresa e critérios aplicáveis | INV-001; INV-004; INV-008; §§3.2, 4.2 e 4.3 | Classificação versionada por finalidade, com fonte, vigência e regra utilizada na pesquisa, importação e personalização do roteiro."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p99"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p483"", ""section"": ""3.2.3"", ""first_paragraph"": 483, ""last_paragraph"": 483, ""text"": ""A pesquisa deve permitir combinar texto, sector, localização, raio, dimensão, classificação, estado, período e fonte, com ordenação e paginação consistentes. Os resultados de negócios similares, fundos e oportunidades devem apresentar data de actualização, cobertura, critérios usados e limitações conhecidas. Sempre que existir correspondência ou recomendação automatizada, o portal deve explicar os factores considerados, permitir correcção dos dados de entrada e evitar classificações baseadas em informação incompleta ou não validada."", ""requirements"": [""AUD-FUND-01"", ""AUD-MARKET-01"", ""AUD-OP-04""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p483"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p630"", ""section"": ""6"", ""first_paragraph"": 630, ""last_paragraph"": 635, ""text"": ""INV-004 | Negócios similares por área, raio, sector e classificação | Sim | Sem demonstração suficiente | — | Importar cadastros aplicáveis e demonstrar pesquisa com fonte, raio e classificação."", ""requirements"": [""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p630"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p716"", ""section"": ""6.1"", ""first_paragraph"": 716, ""last_paragraph"": 722, ""text"": ""§1.5 | Cadastros turísticos e empresas licenciadas | INV-004 e INV-008 | Sim | Sem demonstração suficiente | — | Inventariar cobertura, normalizar, deduplicar, georreferenciar e demonstrar pesquisa de negócios similares."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p716"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+AUD-MARKET-01,"Negócios similares por área, raio, sector e classificação, com fonte, data e cobertura",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-004; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p630; SEG-bf26caee-p716,INV-004 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","ExistingBusiness, InvestmentGeography e taxonomias existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [BUSINESS-PROXIMITY-20261102] Implementação local parcial: API e interface de similares combinam raio/sector/modalidade/classificação, áreas e percurso recuperável. Distância geodésica apenas de pontos primários públicos exactos, válidos, Point/4326 e dentro dos limites; sem centróides ou coordenadas privadas. Fonte, datas de registo e cobertura antes do raio explícitas; publicação não representa actualidade da origem. Privacidade de precisão territorial corrigida. Onze Feature/384 asserções (incluindo quick search plantio de algodao), dez frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo business_proximity_increment_20261102. Sem escrita no activo ou aceitação visual; cobertura real e alimentação de pontos/documentação de origem pendentes. [BUSINESS-POINT-PUBLICATION-20261102] Alimentação do ponto ligada ao formulário privado existente, opt-in explícito e mesma revisão/aprovação/publicação. Territórios e fonte reutilizados, escolha do local primário em múltiplos caminhos, coordenadas reservadas até publicação, fonte pública só por escolha expressa, data desconhecida preservada. Substituição mantém UUID/locais secundários e geometria/fonte anteriores no journal cifrado. 28 Feature/677 asserções e 17 frontend aprovados, PHPStan em cache isolada/tipos/lint/Pint/build. Recibo business_point_publication_increment_20261102. Migração apenas em QA sintético; visual/cobertura real/destino pendentes.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | 02/11/2026: primeiro consumidor local de negocios semelhantes na ficha publica, mesma modalidade e sector conhecido; reutiliza catalogo publico e filtros, exclui origem/duplicados. Frontend 2 testes; Feature 3/158 assercoes em QA isolada; tipos, lint, PHPStan e build aprovados. Parcial: sem raio/distancia, fonte/data individuais ou prova visual; sem instalacao. Ver manual existente. | Continuidade 02/11/2026: provincia principal apenas quando divulgada/consultavel; classificacao publica escolhida expressamente conserva tipo, alvo e finalidade, sem transferir seleccao entre fichas. Fonte do catalogo e data de publicacao explicitas, origem factual nao inferida; resposta malformada e erro recuperavel. Quatro testes frontend do consumidor passaram; ver manual. Raio e proveniencia externa continuam pendentes. [BUSINESS-PROXIMITY-20261102] Implementação local parcial: API e interface de similares combinam raio/sector/modalidade/classificação, áreas e percurso recuperável. Distância geodésica apenas de pontos primários públicos exactos, válidos, Point/4326 e dentro dos limites; sem centróides ou coordenadas privadas. Fonte, datas de registo e cobertura antes do raio explícitas; publicação não representa actualidade da origem. Privacidade de precisão territorial corrigida. Onze Feature/384 asserções (incluindo quick search plantio de algodao), dez frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo business_proximity_increment_20261102. Sem escrita no activo ou aceitação visual; cobertura real e alimentação de pontos/documentação de origem pendentes. [BUSINESS-POINT-PUBLICATION-20261102] Alimentação do ponto ligada ao formulário privado existente, opt-in explícito e mesma revisão/aprovação/publicação. Territórios e fonte reutilizados, escolha do local primário em múltiplos caminhos, coordenadas reservadas até publicação, fonte pública só por escolha expressa, data desconhecida preservada. Substituição mantém UUID/locais secundários e geometria/fonte anteriores no journal cifrado. 28 Feature/677 asserções e 17 frontend aprovados, PHPStan em cache isolada/tipos/lint/Pint/build. Recibo business_point_publication_increment_20261102. Migração apenas em QA sintético; visual/cobertura real/destino pendentes.","Parcial","02/11/2026: pesquisa por raio e alimentação pelo formulário com publicação normal implementadas localmente e ensaiadas. Restam cobertura real de pontos/fontes, observação visual e disponibilização no destino; alterações de anúncios já publicados mantêm o percurso/competências anterior, sem criar reabertura ou editor com autoridade adicional. Não geocodifica nem comprova correspondência espacial. Histórico: 02/11/2026: pesquisa combinada por raio implementada e ensaiada em QA sintético. Restam cobertura real de pontos públicos exactos e sua alimentação pela gestão/origem autorizada, datas/fontes de origem quando não registadas no cadastro, observação visual e disponibilização no destino. Não tratar contagem sem ponto como ausência de negócios. Histórico: Consulta de negócios similares por raio/classificação não implementada.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Filtro por área/raio/sector recuperável, fonte/data/cobertura explícitas; ausência de dados não produz comparação inventada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",Pesquisa combina raio/sector/classificação; apresenta fonte/data/cobertura/limitações; recupera os mesmos registos; não mostra dados privados nem locais sem correspondência.,P2,"Código INV-004 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p630; SEG-bf26caee-p716,6,"[{""id"": ""SEG-bf26caee-p99"", ""section"": ""1.0.2"", ""first_paragraph"": 99, ""last_paragraph"": 103, ""text"": ""Artigos 5 a 10 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Classificação da empresa e critérios aplicáveis | INV-001; INV-004; INV-008; §§3.2, 4.2 e 4.3 | Classificação versionada por finalidade, com fonte, vigência e regra utilizada na pesquisa, importação e personalização do roteiro."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p99"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p483"", ""section"": ""3.2.3"", ""first_paragraph"": 483, ""last_paragraph"": 483, ""text"": ""A pesquisa deve permitir combinar texto, sector, localização, raio, dimensão, classificação, estado, período e fonte, com ordenação e paginação consistentes. Os resultados de negócios similares, fundos e oportunidades devem apresentar data de actualização, cobertura, critérios usados e limitações conhecidas. Sempre que existir correspondência ou recomendação automatizada, o portal deve explicar os factores considerados, permitir correcção dos dados de entrada e evitar classificações baseadas em informação incompleta ou não validada."", ""requirements"": [""AUD-FUND-01"", ""AUD-MARKET-01"", ""AUD-OP-04""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p483"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p630"", ""section"": ""6"", ""first_paragraph"": 630, ""last_paragraph"": 635, ""text"": ""INV-004 | Negócios similares por área, raio, sector e classificação | Sim | Sem demonstração suficiente | — | Importar cadastros aplicáveis e demonstrar pesquisa com fonte, raio e classificação."", ""requirements"": [""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p630"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p716"", ""section"": ""6.1"", ""first_paragraph"": 716, ""last_paragraph"": 722, ""text"": ""§1.5 | Cadastros turísticos e empresas licenciadas | INV-004 e INV-008 | Sim | Sem demonstração suficiente | — | Inventariar cobertura, normalizar, deduplicar, georreferenciar e demonstrar pesquisa de negócios similares."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p716"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 13: Implementar filtro área/raio/sector/classificação, fonte/data/cobertura e casos sem coordenadas sem inventar resultados.","Consulta de negócios similares por raio/classificação não implementada.
+[RECONCILIACAO-43-20261019] 13: Implementar filtro área/raio/sector/classificação, fonte/data/cobertura e casos sem coordenadas sem inventar resultados.","02/11/2026: pesquisa por raio e alimentação pelo formulário com publicação normal implementadas localmente e ensaiadas. Restam cobertura real de pontos/fontes, observação visual e disponibilização no destino; alterações de anúncios já publicados mantêm o percurso/competências anterior, sem criar reabertura ou editor com autoridade adicional. Não geocodifica nem comprova correspondência espacial. Histórico: 02/11/2026: pesquisa combinada por raio implementada e ensaiada em QA sintético. Restam cobertura real de pontos públicos exactos e sua alimentação pela gestão/origem autorizada, datas/fontes de origem quando não registadas no cadastro, observação visual e disponibilização no destino. Não tratar contagem sem ponto como ausência de negócios. Histórico: Consulta de negócios similares por raio/classificação não implementada.
-[UTILIZACAO-HOMOLOGACAO-20261019] 13: Desenvolvimento restante — Consumidor de negócios similares ainda em falta no saldo aprovado; não é apenas ausência de dados no servidor.","ExistingBusiness, InvestmentGeography e taxonomias existentes","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Filtro por área/raio/sector recuperável, fonte/data/cobertura explícitas; ausência de dados não produz comparação inventada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Negócios similares=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Negócios similares=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 13: Desenvolvimento restante — Consumidor de negócios similares ainda em falta no saldo aprovado; não é apenas ausência de dados no servidor.","ExistingBusiness, InvestmentGeography e taxonomias existentes PublicBusinessLocations, BusinessProximitySearch, catálogo/Resource/SimilarBusinesses e classificação pública existentes; sem novo cadastro ou alterações no schema. BusinessFormSchema, ExistingBusinessDrafts/Intake, BusinessPointPublication e journal imutável; nenhuma rota/papel paralelo.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Filtro por área/raio/sector recuperável, fonte/data/cobertura explícitas; ausência de dados não produz comparação inventada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Negócios similares=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Negócios similares=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Sem consumidor de negócios similares por raio/classificação demonstrado. O marketplace de negócios não comprova um cadastro de estabelecimentos.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar ExistingBusiness/objetos e geo_locations/geo_geometries para estabelecimentos comprovados. Separar estabelecimento observado de anúncio de transação; pesquisa espacial explicada, sem transformar artigo ou licença em oportunidade.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,24–40 h após dados georreferenciados e regras de distância definidos.,,,
-AUD-ESTABLISHMENT-01,"Importar empresas licenciadas e empreendimentos turísticos com normalização, correspondências e rejeições, sem duplicações",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-008; SEG-bf26caee-p94; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p559; SEG-bf26caee-p560; SEG-bf26caee-p561; SEG-bf26caee-p562; SEG-bf26caee-p563; SEG-bf26caee-p654; SEG-bf26caee-p716; SEG-bf26caee-p820; SEG-bf26caee-p823; SEG-bf26caee-p826; SEG-bf26caee-p829; SEG-bf26caee-p832; SEG-bf26caee-p838; SEG-bf26caee-p839; SEG-bf26caee-p840; SEG-bf26caee-p841; SEG-bf26caee-p842; SEG-bf26caee-p843,INV-008 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Importadores autenticados, organizations, cadastros existentes e hashes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento.,Não implementado,Importador reconciliado de empresas licenciadas/empreendimentos não implementado.,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Prévia, rejeições/correspondências por entidade, aplicação idempotente e recuperação; preservar IDs/versões. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",Prévia sem escrita; casos inequívocos/casos ambíguos/rejeições por linha; aplicação QA com ator autorizado; repetição sem duplicações; fonte/data/história e recuperação; nenhuma georreferenciação inventada.,P2,"Código INV-008 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p94; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p559; SEG-bf26caee-p560; SEG-bf26caee-p561; SEG-bf26caee-p562; SEG-bf26caee-p563; SEG-bf26caee-p654; SEG-bf26caee-p716; SEG-bf26caee-p820; SEG-bf26caee-p823; SEG-bf26caee-p826; SEG-bf26caee-p829; SEG-bf26caee-p832; SEG-bf26caee-p838; SEG-bf26caee-p839; SEG-bf26caee-p840; SEG-bf26caee-p841; SEG-bf26caee-p842; SEG-bf26caee-p843,22,"[{""id"": ""SEG-bf26caee-p94"", ""section"": ""1.0.2"", ""first_paragraph"": 94, ""last_paragraph"": 98, ""text"": ""Artigos 1 a 4 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Objecto, actividade empresarial, empresário e empresa | INV-001; INV-008; §§3.2, 4.2 e 9.1 | Qualificação do investidor, da actividade, da empresa e do projecto; evidência no cadastro, roteiro e modelo de dados."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p94"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p99"", ""section"": ""1.0.2"", ""first_paragraph"": 99, ""last_paragraph"": 103, ""text"": ""Artigos 5 a 10 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Classificação da empresa e critérios aplicáveis | INV-001; INV-004; INV-008; §§3.2, 4.2 e 4.3 | Classificação versionada por finalidade, com fonte, vigência e regra utilizada na pesquisa, importação e personalização do roteiro."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p99"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p559"", ""section"": ""4.3"", ""first_paragraph"": 559, ""last_paragraph"": 559, ""text"": ""Cada entidade deve possuir identificador único, estado, origem, datas de criação e actualização."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p559"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p560"", ""section"": ""4.3"", ""first_paragraph"": 560, ""last_paragraph"": 560, ""text"": ""Província, distrito, posto administrativo e localidade devem usar dados mestres partilhados."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p560"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p561"", ""section"": ""4.3"", ""first_paragraph"": 561, ""last_paragraph"": 561, ""text"": ""Não duplicar investidores, empresas, estabelecimentos ou oportunidades; aplicar regras de correspondência e revisão."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p561"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p562"", ""section"": ""4.3"", ""first_paragraph"": 562, ""last_paragraph"": 562, ""text"": ""Importações de folhas de cálculo devem passar por preparação, validação, normalização, georreferenciação e relatório de rejeições."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p562"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p563"", ""section"": ""4.3"", ""first_paragraph"": 563, ""last_paragraph"": 563, ""text"": ""Os dados das empresas licenciadas e dos empreendimentos turísticos devem conservar a fonte, data de referência e histórico de actualização."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p563"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p654"", ""section"": ""6"", ""first_paragraph"": 654, ""last_paragraph"": 659, ""text"": ""INV-008 | Importar empresas e empreendimentos sem duplicações | Sim | Sem demonstração suficiente | — | Demonstrar inventário, normalização, deduplicação e georreferenciação."", ""requirements"": [""AUD-ESTABLISHMENT-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p654"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p716"", ""section"": ""6.1"", ""first_paragraph"": 716, ""last_paragraph"": 722, ""text"": ""§1.5 | Cadastros turísticos e empresas licenciadas | INV-004 e INV-008 | Sim | Sem demonstração suficiente | — | Inventariar cobertura, normalizar, deduplicar, georreferenciar e demonstrar pesquisa de negócios similares."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p716"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p820"", ""section"": ""7.3"", ""first_paragraph"": 820, ""last_paragraph"": 822, ""text"": ""Requisitos e licenças | Validar regras, documentos, taxas, prazos e entidade competente | Trimestral e após alteração normativa"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p820"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p823"", ""section"": ""7.3"", ""first_paragraph"": 823, ""last_paragraph"": 825, ""text"": ""Fiscalidade e contribuições | Actualizar parâmetros, fórmulas, vigência e memória explicativa | A cada alteração aplicável"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p823"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p826"", ""section"": ""7.3"", ""first_paragraph"": 826, ""last_paragraph"": 828, ""text"": ""Fundos e oportunidades | Confirmar disponibilidade, prazo, cobertura e elegibilidade | Mensal"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p826"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p829"", ""section"": ""7.3"", ""first_paragraph"": 829, ""last_paragraph"": 831, ""text"": ""Empresas e estabelecimentos | Reconciliar fontes, resolver duplicados e actualizar georreferenciação | Mensal ou por nova carga"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p829"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p832"", ""section"": ""7.3"", ""first_paragraph"": 832, ""last_paragraph"": 834, ""text"": ""Conteúdo institucional | Confirmar denominação, competência, contacto e ligação oficial | Trimestral"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p832"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p838"", ""section"": ""8.1"", ""first_paragraph"": 838, ""last_paragraph"": 838, ""text"": ""Inventariar fontes, proprietários, estrutura, actualidade e restrições de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p838"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p839"", ""section"": ""8.1"", ""first_paragraph"": 839, ""last_paragraph"": 839, ""text"": ""Mapear colunas para o modelo canónico e definir dados obrigatórios."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p839"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p840"", ""section"": ""8.1"", ""first_paragraph"": 840, ""last_paragraph"": 840, ""text"": ""Normalizar nomes, classificações, localizações, contactos e identificadores."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p840"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p841"", ""section"": ""8.1"", ""first_paragraph"": 841, ""last_paragraph"": 841, ""text"": ""Detectar duplicados e submeter conflitos à validação do responsável pelos dados."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p841"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p842"", ""section"": ""8.1"", ""first_paragraph"": 842, ""last_paragraph"": 842, ""text"": ""Geocodificar apenas registos com localização suficientemente validada."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p842"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p843"", ""section"": ""8.1"", ""first_paragraph"": 843, ""last_paragraph"": 843, ""text"": ""Executar carga de ensaio, reconciliar totais e obter aprovação antes da carga final."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p843"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [BUSINESS-PROXIMITY-20261102] Implementação local parcial: API e interface de similares combinam raio/sector/modalidade/classificação, áreas e percurso recuperável. Distância geodésica apenas de pontos primários públicos exactos, válidos, Point/4326 e dentro dos limites; sem centróides ou coordenadas privadas. Fonte, datas de registo e cobertura antes do raio explícitas; publicação não representa actualidade da origem. Privacidade de precisão territorial corrigida. Onze Feature/384 asserções (incluindo quick search plantio de algodao), dez frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo business_proximity_increment_20261102. Sem escrita no activo ou aceitação visual; cobertura real e alimentação de pontos/documentação de origem pendentes. [BUSINESS-POINT-PUBLICATION-20261102] Alimentação do ponto ligada ao formulário privado existente, opt-in explícito e mesma revisão/aprovação/publicação. Territórios e fonte reutilizados, escolha do local primário em múltiplos caminhos, coordenadas reservadas até publicação, fonte pública só por escolha expressa, data desconhecida preservada. Substituição mantém UUID/locais secundários e geometria/fonte anteriores no journal cifrado. 28 Feature/677 asserções e 17 frontend aprovados, PHPStan em cache isolada/tipos/lint/Pint/build. Recibo business_point_publication_increment_20261102. Migração apenas em QA sintético; visual/cobertura real/destino pendentes.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Sem consumidor de negócios similares por raio/classificação demonstrado. O marketplace de negócios não comprova um cadastro de estabelecimentos.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar ExistingBusiness/objetos e geo_locations/geo_geometries para estabelecimentos comprovados. Separar estabelecimento observado de anúncio de transação; pesquisa espacial explicada, sem transformar artigo ou licença em oportunidade.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,24–40 h após dados georreferenciados e regras de distância definidos.,,,
+AUD-ESTABLISHMENT-01,"Importar empresas licenciadas e empreendimentos turísticos com normalização, correspondências e rejeições, sem duplicações",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-008; SEG-bf26caee-p94; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p559; SEG-bf26caee-p560; SEG-bf26caee-p561; SEG-bf26caee-p562; SEG-bf26caee-p563; SEG-bf26caee-p654; SEG-bf26caee-p716; SEG-bf26caee-p820; SEG-bf26caee-p823; SEG-bf26caee-p826; SEG-bf26caee-p829; SEG-bf26caee-p832; SEG-bf26caee-p838; SEG-bf26caee-p839; SEG-bf26caee-p840; SEG-bf26caee-p841; SEG-bf26caee-p842; SEG-bf26caee-p843,INV-008 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Importadores autenticados, organizations, cadastros existentes e hashes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [PROACTIVE-SUPPLY-REVIEW-20261102] Reconciliação com prova aceite de28/10/2026: importação privada específica já entregue, com361464 observações administrativas,147165 repetições conservadas e214299 projecções distintas; nenhum destes números é contagem de empresas únicas. Recibo proactive-supply-git-delivery-20261028.json e motores prepare/export/load-proactive-supply.py preservados. Os estados anteriores a essa entrega são históricos, não prova de ausência actual. Acrescentada consulta privada só de leitura das origens/linhas, pendências territoriais, repetições e conflitos, com cobertura explícita, referências recuperáveis e filtros sem acentos. Corrigidas respostas antigas após mudança de contexto; hashes de identidade/recibos privados excluídos da projecção. 9 Feature/138 asserções e seis frontend; PHPStan, tipos, lint/Pint/build aprovados. Onze tabelas QA com contagens/checksums iguais antes/depois. Recibo proactive_supply_review_increment_20261102; sem importação ou alteração no activo.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [PROACTIVE-SUPPLY-REVIEW-20261102] Reconciliação com prova aceite de28/10/2026: importação privada específica já entregue, com361464 observações administrativas,147165 repetições conservadas e214299 projecções distintas; nenhum destes números é contagem de empresas únicas. Recibo proactive-supply-git-delivery-20261028.json e motores prepare/export/load-proactive-supply.py preservados. Os estados anteriores a essa entrega são históricos, não prova de ausência actual. Acrescentada consulta privada só de leitura das origens/linhas, pendências territoriais, repetições e conflitos, com cobertura explícita, referências recuperáveis e filtros sem acentos. Corrigidas respostas antigas após mudança de contexto; hashes de identidade/recibos privados excluídos da projecção. 9 Feature/138 asserções e seis frontend; PHPStan, tipos, lint/Pint/build aprovados. Onze tabelas QA com contagens/checksums iguais antes/depois. Recibo proactive_supply_review_increment_20261102; sem importação ou alteração no activo.","Implementado parcialmente","Saldo02/11/2026: implementação parcial; importador privado específico e consulta das pendências existem. Restam reconciliação/consolidação rastreável de entidades, outros formatos/lotes delimitados e observação visual/disponibilização do delta. Revisão não aplica correspondências nem prova actividade actual; faltas na base não provam ausência de oferta. Histórico anterior: Importador reconciliado de empresas licenciadas/empreendimentos não implementado.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Prévia, rejeições/correspondências por entidade, aplicação idempotente e recuperação; preservar IDs/versões. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",Prévia sem escrita; casos inequívocos/casos ambíguos/rejeições por linha; aplicação QA com ator autorizado; repetição sem duplicações; fonte/data/história e recuperação; nenhuma georreferenciação inventada.,P2,"Código INV-008 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p94; SEG-bf26caee-p99; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p559; SEG-bf26caee-p560; SEG-bf26caee-p561; SEG-bf26caee-p562; SEG-bf26caee-p563; SEG-bf26caee-p654; SEG-bf26caee-p716; SEG-bf26caee-p820; SEG-bf26caee-p823; SEG-bf26caee-p826; SEG-bf26caee-p829; SEG-bf26caee-p832; SEG-bf26caee-p838; SEG-bf26caee-p839; SEG-bf26caee-p840; SEG-bf26caee-p841; SEG-bf26caee-p842; SEG-bf26caee-p843,22,"[{""id"": ""SEG-bf26caee-p94"", ""section"": ""1.0.2"", ""first_paragraph"": 94, ""last_paragraph"": 98, ""text"": ""Artigos 1 a 4 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Objecto, actividade empresarial, empresário e empresa | INV-001; INV-008; §§3.2, 4.2 e 9.1 | Qualificação do investidor, da actividade, da empresa e do projecto; evidência no cadastro, roteiro e modelo de dados."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p94"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p99"", ""section"": ""1.0.2"", ""first_paragraph"": 99, ""last_paragraph"": 103, ""text"": ""Artigos 5 a 10 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Classificação da empresa e critérios aplicáveis | INV-001; INV-004; INV-008; §§3.2, 4.2 e 4.3 | Classificação versionada por finalidade, com fonte, vigência e regra utilizada na pesquisa, importação e personalização do roteiro."", ""requirements"": [""AUD-DESK-02"", ""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p99"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p559"", ""section"": ""4.3"", ""first_paragraph"": 559, ""last_paragraph"": 559, ""text"": ""Cada entidade deve possuir identificador único, estado, origem, datas de criação e actualização."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p559"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p560"", ""section"": ""4.3"", ""first_paragraph"": 560, ""last_paragraph"": 560, ""text"": ""Província, distrito, posto administrativo e localidade devem usar dados mestres partilhados."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p560"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p561"", ""section"": ""4.3"", ""first_paragraph"": 561, ""last_paragraph"": 561, ""text"": ""Não duplicar investidores, empresas, estabelecimentos ou oportunidades; aplicar regras de correspondência e revisão."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p561"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p562"", ""section"": ""4.3"", ""first_paragraph"": 562, ""last_paragraph"": 562, ""text"": ""Importações de folhas de cálculo devem passar por preparação, validação, normalização, georreferenciação e relatório de rejeições."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p562"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p563"", ""section"": ""4.3"", ""first_paragraph"": 563, ""last_paragraph"": 563, ""text"": ""Os dados das empresas licenciadas e dos empreendimentos turísticos devem conservar a fonte, data de referência e histórico de actualização."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-GEO-03"", ""RF-CRM-001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p563"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p654"", ""section"": ""6"", ""first_paragraph"": 654, ""last_paragraph"": 659, ""text"": ""INV-008 | Importar empresas e empreendimentos sem duplicações | Sim | Sem demonstração suficiente | — | Demonstrar inventário, normalização, deduplicação e georreferenciação."", ""requirements"": [""AUD-ESTABLISHMENT-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p654"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p716"", ""section"": ""6.1"", ""first_paragraph"": 716, ""last_paragraph"": 722, ""text"": ""§1.5 | Cadastros turísticos e empresas licenciadas | INV-004 e INV-008 | Sim | Sem demonstração suficiente | — | Inventariar cobertura, normalizar, deduplicar, georreferenciar e demonstrar pesquisa de negócios similares."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p716"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p820"", ""section"": ""7.3"", ""first_paragraph"": 820, ""last_paragraph"": 822, ""text"": ""Requisitos e licenças | Validar regras, documentos, taxas, prazos e entidade competente | Trimestral e após alteração normativa"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p820"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p823"", ""section"": ""7.3"", ""first_paragraph"": 823, ""last_paragraph"": 825, ""text"": ""Fiscalidade e contribuições | Actualizar parâmetros, fórmulas, vigência e memória explicativa | A cada alteração aplicável"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p823"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p826"", ""section"": ""7.3"", ""first_paragraph"": 826, ""last_paragraph"": 828, ""text"": ""Fundos e oportunidades | Confirmar disponibilidade, prazo, cobertura e elegibilidade | Mensal"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p826"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p829"", ""section"": ""7.3"", ""first_paragraph"": 829, ""last_paragraph"": 831, ""text"": ""Empresas e estabelecimentos | Reconciliar fontes, resolver duplicados e actualizar georreferenciação | Mensal ou por nova carga"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p829"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p832"", ""section"": ""7.3"", ""first_paragraph"": 832, ""last_paragraph"": 834, ""text"": ""Conteúdo institucional | Confirmar denominação, competência, contacto e ligação oficial | Trimestral"", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p832"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p838"", ""section"": ""8.1"", ""first_paragraph"": 838, ""last_paragraph"": 838, ""text"": ""Inventariar fontes, proprietários, estrutura, actualidade e restrições de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p838"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p839"", ""section"": ""8.1"", ""first_paragraph"": 839, ""last_paragraph"": 839, ""text"": ""Mapear colunas para o modelo canónico e definir dados obrigatórios."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p839"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p840"", ""section"": ""8.1"", ""first_paragraph"": 840, ""last_paragraph"": 840, ""text"": ""Normalizar nomes, classificações, localizações, contactos e identificadores."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p840"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p841"", ""section"": ""8.1"", ""first_paragraph"": 841, ""last_paragraph"": 841, ""text"": ""Detectar duplicados e submeter conflitos à validação do responsável pelos dados."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p841"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p842"", ""section"": ""8.1"", ""first_paragraph"": 842, ""last_paragraph"": 842, ""text"": ""Geocodificar apenas registos com localização suficientemente validada."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p842"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p843"", ""section"": ""8.1"", ""first_paragraph"": 843, ""last_paragraph"": 843, ""text"": ""Executar carga de ensaio, reconciliar totais e obter aprovação antes da carga final."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-LIB-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p843"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 6: Faltam candidatos aproximados explicáveis e consolidação/reversão genérica por tipo. Não confundir reparação sectorial com fusão de entidades. | 14: Implementar prévia, normalização, conflitos/rejeições, idempotência e rastreio do primeiro formato.","Importador reconciliado de empresas licenciadas/empreendimentos não implementado.
+[RECONCILIACAO-43-20261019] 6: Faltam candidatos aproximados explicáveis e consolidação/reversão genérica por tipo. Não confundir reparação sectorial com fusão de entidades. | 14: Implementar prévia, normalização, conflitos/rejeições, idempotência e rastreio do primeiro formato.","Saldo02/11/2026: implementação parcial; importador privado específico e consulta das pendências existem. Restam reconciliação/consolidação rastreável de entidades, outros formatos/lotes delimitados e observação visual/disponibilização do delta. Revisão não aplica correspondências nem prova actividade actual; faltas na base não provam ausência de oferta. Histórico anterior: Importador reconciliado de empresas licenciadas/empreendimentos não implementado.
-[UTILIZACAO-HOMOLOGACAO-20261019] 6: Desenvolvimento restante — Detecção aproximada e consolidação rastreável continuam abertas; a execução de reconciliação sectorial existente não demonstra consolidação genérica. | 14: Desenvolvimento restante + correspondências — Primeiro formato/lote idempotente de empresas e conflitos ainda por implementar/delimitar.","Importadores autenticados, organizations, cadastros existentes e hashes","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Prévia, rejeições/correspondências por entidade, aplicação idempotente e recuperação; preservar IDs/versões.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Duplicados distintos — deteção e consolidação=Não demonstrado; Importação de empresas/empreendimentos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Duplicados distintos — deteção e consolidação=Não demonstrado; Importação de empresas/empreendimentos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 6: Desenvolvimento restante — Detecção aproximada e consolidação rastreável continuam abertas; a execução de reconciliação sectorial existente não demonstra consolidação genérica. | 14: Desenvolvimento restante + correspondências — Primeiro formato/lote idempotente de empresas e conflitos ainda por implementar/delimitar.","Importadores autenticados, organizations, cadastros existentes e hashes; importador privado prepare/export/load-proactive-supply.py, ProactiveSupply/RLS, observações/hash/linha existentes e novo visor privado de pendências","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Prévia, rejeições/correspondências por entidade, aplicação idempotente e recuperação; preservar IDs/versões. O lote já aceite não depende de nova autenticação genérica da fonte. Extensões exigem formato/recorte concretos; eventual decisão de identidade ou correspondência mantém os dados originais e não decorre de igualdade de nomes.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolha técnica: consulta privada sem escrita e com a mesma autorização; nenhuma fusão, correspondência geográfica ou publicação inferida. Não criar importador paralelo nem tratar projecções administrativas como empresas únicas.","Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Duplicados distintos — deteção e consolidação=Não demonstrado; Importação de empresas/empreendimentos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Duplicados distintos — deteção e consolidação=Não demonstrado; Importação de empresas/empreendimentos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Importador específico destes cadastros e reconciliação de entidades/versões ainda por preparar. Importação de artigos do legado e geometrias não substitui esta carga.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Inventariar os ficheiros fornecidos, inspecionar colunas e IDs reais; reutilizar organizações/estabelecimentos existentes por correspondência, serviços de importação privada/hash e hierarquia territorial. Não criar organizações automaticamente com base em nome ou licença.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,24–48 h por formato aprovado; acesso ao ficheiro e identificadores são pré-condições.,,,
-AUD-FUND-01,Catálogo de fundos nacionais e territoriais com elegibilidade explicada e atualização,[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-005; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p636; SEG-bf26caee-p723,INV-005 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca, taxonomias, fontes e filtros comuns. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [FUNDING-EDITOR-20261102] Catálogo e editor locais: rascunhos, prévia vinculada, publicação/retirada com autoridade editorial existente, versões imutáveis, janelas/critério explicado, documentos por versão e interesse privado. Quatro testes/91 asserções e tipos aprovados. Filtros territoriais/sectoriais, ensaios de documentos, fontes reais, visual e disponibilização pendentes; requisito parcial, sem alteração no activo. Manual de 02/11 e funding_editor_increment_20261102. [FUNDING-FILTERS-20261102] Filtros locais por sector, cobertura territorial e estado de janela, com desconhecidos explícitos e cobertura parcial. Nomes/caminhos territoriais e sectores conservados por versão. Descarga verifica versão, checksum, direitos, análise e bytes; prévia obsoleta recusada. Seis testes/204 asserções, PHPStan, tipos, lint sem avisos e compilação aprovados. Recibo funding_filters_increment_20261102 e manual. Faltam fontes reais incorporadas, validação visual, ensaios de concorrência e disponibilização; requisito parcial. [FUNDING-REFERENCES-20261102] Referência oficial FDEL empacotada com fontes/edições/hashes e prévia editorial; prepara rascunho sem publicar. Uma ficha e chamada municipal histórica, repetição sem duplicar ou substituir. Sete testes/235 asserções; PHPStan, tipos e lint aprovados. Recibo funding_references_increment_20261102; manual de 02/11. Ligações sectorial/cartográfica, concorrência, visual, alertas e disponibilização pendentes. Parcial local, sem escrita no activo. [FUNDING-CONCURRENCY-20261102] Ensaio com cinco pares de processos e bloqueios observados no PostgreSQL identificou deadlock 40P01 entre retirada e interesse da mesma pessoa. Bloqueio da conta ajustado a FOR NO KEY UPDATE, conservando serialização e referências de auditoria. Cinco cenários passaram após correcção; sete Feature/235 asserções e PHPStan/Pint aprovados. Dados/versão/interesse e auditoria sem duplicação conservados; recibo funding_concurrency_increment_20261102. Não comprova carga ou todas as intercalações. Visual, vínculos da referência, alertas e disponibilização pendentes.","Parcial — implementação local em QA","02/11/2026: concorrência demonstrada nos cinco cenários delimitados e impasse corrigido. Restam visual, vínculos ao cadastro da referência, alertas de incentivos e disponibilização. Histórico: 02/11/2026: referência oficial preparada pela interface com prova local; restam vínculos sectorial/cartográfico da referência, concorrência/visual, alertas de incentivos e disponibilização. Histórico: 02/11/2026: filtros e ensaios específicos de documentos implementados/verificados localmente. Restam fontes reais incorporadas, visual, concorrência e disponibilização; integração de incentivos nos alertas não demonstrada. Histórico preservado: 02/11/2026: implementação local parcial com editor e percurso público; restam filtros territoriais/sectoriais, provas específicas de documentos/conflitos, fontes reais e visual/disponibilização. Histórico: Catálogo de fundos com janelas e elegibilidade não implementado; ofertas experimentais não o substituem.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fundos com fonte/data, elegibilidade explicada e janela; indeterminado quando parâmetros faltam. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Fonte, gestor, sectores, cobertura nacional ou territorial, datas/estado e documentos; filtro e explicação por critério; fundos expirados sinalizados; guardar interesse autorizado sem duplicação.",P2,"Código INV-005 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p636; SEG-bf26caee-p723,5,"[{""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p483"", ""section"": ""3.2.3"", ""first_paragraph"": 483, ""last_paragraph"": 483, ""text"": ""A pesquisa deve permitir combinar texto, sector, localização, raio, dimensão, classificação, estado, período e fonte, com ordenação e paginação consistentes. Os resultados de negócios similares, fundos e oportunidades devem apresentar data de actualização, cobertura, critérios usados e limitações conhecidas. Sempre que existir correspondência ou recomendação automatizada, o portal deve explicar os factores considerados, permitir correcção dos dados de entrada e evitar classificações baseadas em informação incompleta ou não validada."", ""requirements"": [""AUD-FUND-01"", ""AUD-MARKET-01"", ""AUD-OP-04""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p483"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p636"", ""section"": ""6"", ""first_paragraph"": 636, ""last_paragraph"": 641, ""text"": ""INV-005 | Fundos compatíveis com explicação da correspondência | Sim | Sem demonstração suficiente | — | Demonstrar catálogo, cobertura, critérios, prazos, actualização e justificação."", ""requirements"": [""AUD-FUND-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p636"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p723"", ""section"": ""6.1"", ""first_paragraph"": 723, ""last_paragraph"": 729, ""text"": ""§1.5 | Fundos nacionais e territoriais | INV-005 | Sim | Sem demonstração suficiente | — | Demonstrar cadastro, fonte, actualização, cobertura, critérios, prazos e correspondência fundamentada."", ""requirements"": [""AUD-FUND-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p723"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [PROACTIVE-SUPPLY-REVIEW-20261102] Reconciliação com prova aceite de28/10/2026: importação privada específica já entregue, com361464 observações administrativas,147165 repetições conservadas e214299 projecções distintas; nenhum destes números é contagem de empresas únicas. Recibo proactive-supply-git-delivery-20261028.json e motores prepare/export/load-proactive-supply.py preservados. Os estados anteriores a essa entrega são históricos, não prova de ausência actual. Acrescentada consulta privada só de leitura das origens/linhas, pendências territoriais, repetições e conflitos, com cobertura explícita, referências recuperáveis e filtros sem acentos. Corrigidas respostas antigas após mudança de contexto; hashes de identidade/recibos privados excluídos da projecção. 9 Feature/138 asserções e seis frontend; PHPStan, tipos, lint/Pint/build aprovados. Onze tabelas QA com contagens/checksums iguais antes/depois. Recibo proactive_supply_review_increment_20261102; sem importação ou alteração no activo.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Importador específico destes cadastros e reconciliação de entidades/versões ainda por preparar. Importação de artigos do legado e geometrias não substitui esta carga.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Inventariar os ficheiros fornecidos, inspecionar colunas e IDs reais; reutilizar organizações/estabelecimentos existentes por correspondência, serviços de importação privada/hash e hierarquia territorial. Não criar organizações automaticamente com base em nome ou licença.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,24–48 h por formato aprovado; acesso ao ficheiro e identificadores são pré-condições.,,,
+AUD-FUND-01,Catálogo de fundos nacionais e territoriais com elegibilidade explicada e atualização,[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-005; SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p636; SEG-bf26caee-p723,INV-005 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca, taxonomias, fontes e filtros comuns. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [FUNDING-EDITOR-20261102] Catálogo e editor locais: rascunhos, prévia vinculada, publicação/retirada com autoridade editorial existente, versões imutáveis, janelas/critério explicado, documentos por versão e interesse privado. Quatro testes/91 asserções e tipos aprovados. Filtros territoriais/sectoriais, ensaios de documentos, fontes reais, visual e disponibilização pendentes; requisito parcial, sem alteração no activo. Manual de 02/11 e funding_editor_increment_20261102. [FUNDING-FILTERS-20261102] Filtros locais por sector, cobertura territorial e estado de janela, com desconhecidos explícitos e cobertura parcial. Nomes/caminhos territoriais e sectores conservados por versão. Descarga verifica versão, checksum, direitos, análise e bytes; prévia obsoleta recusada. Seis testes/204 asserções, PHPStan, tipos, lint sem avisos e compilação aprovados. Recibo funding_filters_increment_20261102 e manual. Faltam fontes reais incorporadas, validação visual, ensaios de concorrência e disponibilização; requisito parcial. [FUNDING-REFERENCES-20261102] Referência oficial FDEL empacotada com fontes/edições/hashes e prévia editorial; prepara rascunho sem publicar. Uma ficha e chamada municipal histórica, repetição sem duplicar ou substituir. Sete testes/235 asserções; PHPStan, tipos e lint aprovados. Recibo funding_references_increment_20261102; manual de 02/11. Ligações sectorial/cartográfica, concorrência, visual, alertas e disponibilização pendentes. Parcial local, sem escrita no activo. [FUNDING-CONCURRENCY-20261102] Ensaio com cinco pares de processos e bloqueios observados no PostgreSQL identificou deadlock 40P01 entre retirada e interesse da mesma pessoa. Bloqueio da conta ajustado a FOR NO KEY UPDATE, conservando serialização e referências de auditoria. Cinco cenários passaram após correcção; sete Feature/235 asserções e PHPStan/Pint aprovados. Dados/versão/interesse e auditoria sem duplicação conservados; recibo funding_concurrency_increment_20261102. Não comprova carga ou todas as intercalações. Visual, vínculos da referência, alertas e disponibilização pendentes. [FUNDING-ALERTS-20261102] ACT-11: versões publicadas de fundos/programas/incentivos do catálogo integradas no motor de alertas existente, com adesão explícita e preferências antigas preservadas. Filtros e desconhecidos explicados, origem/versão/estado conservados, retirada/acesso próprio, cancelamento, lote e reversão transaccional. 36 testes/612 asserções e seis frontend; PHPStan, tipos, lint e compilação aprovados. Recibo funding_alerts_increment_20261102 e manual. Sem canais externos, recolha externa ou instalação no activo; requisito agregado parcial. [FUNDING-ASSESSMENT-CONCURRENCY-20261102] Nove pares concorrentes observados aprovaram referências/versões/interesses, geradores duplicados, preferências idempotentes e ambas as precedências de cancelamento. Conferência de critérios mostra/envia apenas perguntas aplicáveis, preserva respostas locais e reinicia por ficha/versão. Oito frontend, tipos/lint/compilação aprovados; PHP da aplicação sem delta, provas 36 Feature/612 reutilizadas após conferir hashes. Recibo funding_assessment_concurrency_increment_20261102. Visual, vínculos de referência, canais externos e disponibilização continuam pendentes.","Parcial — implementação local em QA","02/11/2026: concorrência do gerador verificada nos cenários delimitados e perguntas aplicáveis corrigidas. Restam visual, vínculos da referência, canais externos e disponibilização/agendador. Histórico: 02/11/2026: oportunidades, concursos e fundos/apoios do catálogo integrados em alertas locais com prova. Restam canais/outras fontes externas, concorrência específica do gerador, visual, vínculos de referência e disponibilização/agendador. Histórico: 02/11/2026: concorrência demonstrada nos cinco cenários delimitados e impasse corrigido. Restam visual, vínculos ao cadastro da referência, alertas de incentivos e disponibilização. Histórico: 02/11/2026: referência oficial preparada pela interface com prova local; restam vínculos sectorial/cartográfico da referência, concorrência/visual, alertas de incentivos e disponibilização. Histórico: 02/11/2026: filtros e ensaios específicos de documentos implementados/verificados localmente. Restam fontes reais incorporadas, visual, concorrência e disponibilização; integração de incentivos nos alertas não demonstrada. Histórico preservado: 02/11/2026: implementação local parcial com editor e percurso público; restam filtros territoriais/sectoriais, provas específicas de documentos/conflitos, fontes reais e visual/disponibilização. Histórico: Catálogo de fundos com janelas e elegibilidade não implementado; ofertas experimentais não o substituem.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fundos com fonte/data, elegibilidade explicada e janela; indeterminado quando parâmetros faltam. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Fonte, gestor, sectores, cobertura nacional ou territorial, datas/estado e documentos; filtro e explicação por critério; fundos expirados sinalizados; guardar interesse autorizado sem duplicação.",P2,"Código INV-005 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p157; SEG-bf26caee-p158; SEG-bf26caee-p483; SEG-bf26caee-p636; SEG-bf26caee-p723,5,"[{""id"": ""SEG-bf26caee-p157"", ""section"": ""1.5"", ""first_paragraph"": 157, ""last_paragraph"": 157, ""text"": ""Permitir a consulta de negócios similares na zona antes da abertura de um empreendimento, apoiando a análise de viabilidade. As fontes iniciais incluem os ficheiros de cadastro de empreendimentos turísticos de três, quatro e cinco estrelas e de empresas licenciadas já disponibilizados ao projecto. Antes da utilização, estes dados devem ser inventariados, normalizados, deduplicados, georreferenciados e sujeitos a validação de actualidade, cobertura e autorização de uso."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p157"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p158"", ""section"": ""1.5"", ""first_paragraph"": 158, ""last_paragraph"": 158, ""text"": ""Publicar fundos de financiamento por localização ou com cobertura nacional, conforme a respectiva distribuição geográfica."", ""requirements"": [""AUD-ESTABLISHMENT-01"", ""AUD-FUND-01"", ""AUD-MARKET-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p158"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p483"", ""section"": ""3.2.3"", ""first_paragraph"": 483, ""last_paragraph"": 483, ""text"": ""A pesquisa deve permitir combinar texto, sector, localização, raio, dimensão, classificação, estado, período e fonte, com ordenação e paginação consistentes. Os resultados de negócios similares, fundos e oportunidades devem apresentar data de actualização, cobertura, critérios usados e limitações conhecidas. Sempre que existir correspondência ou recomendação automatizada, o portal deve explicar os factores considerados, permitir correcção dos dados de entrada e evitar classificações baseadas em informação incompleta ou não validada."", ""requirements"": [""AUD-FUND-01"", ""AUD-MARKET-01"", ""AUD-OP-04""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p483"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p636"", ""section"": ""6"", ""first_paragraph"": 636, ""last_paragraph"": 641, ""text"": ""INV-005 | Fundos compatíveis com explicação da correspondência | Sim | Sem demonstração suficiente | — | Demonstrar catálogo, cobertura, critérios, prazos, actualização e justificação."", ""requirements"": [""AUD-FUND-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p636"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p723"", ""section"": ""6.1"", ""first_paragraph"": 723, ""last_paragraph"": 729, ""text"": ""§1.5 | Fundos nacionais e territoriais | INV-005 | Sim | Sem demonstração suficiente | — | Demonstrar cadastro, fonte, actualização, cobertura, critérios, prazos e correspondência fundamentada."", ""requirements"": [""AUD-FUND-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p723"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 15: Implementar fonte/gestor, janela, elegibilidade explicável, estados desconhecido/expirado e interesse idempotente.","02/11/2026: concorrência demonstrada nos cinco cenários delimitados e impasse corrigido. Restam visual, vínculos ao cadastro da referência, alertas de incentivos e disponibilização. Histórico: 02/11/2026: referência oficial preparada pela interface com prova local; restam vínculos sectorial/cartográfico da referência, concorrência/visual, alertas de incentivos e disponibilização. Histórico: 02/11/2026: filtros e ensaios específicos de documentos implementados/verificados localmente. Restam fontes reais incorporadas, visual, concorrência e disponibilização; integração de incentivos nos alertas não demonstrada. Histórico preservado: 02/11/2026: implementação local parcial com editor e percurso público; restam filtros territoriais/sectoriais, provas específicas de documentos/conflitos, fontes reais e visual/disponibilização. Histórico: Catálogo de fundos com janelas e elegibilidade não implementado; ofertas experimentais não o substituem.
+[RECONCILIACAO-43-20261019] 15: Implementar fonte/gestor, janela, elegibilidade explicável, estados desconhecido/expirado e interesse idempotente.","02/11/2026: concorrência do gerador verificada nos cenários delimitados e perguntas aplicáveis corrigidas. Restam visual, vínculos da referência, canais externos e disponibilização/agendador. Histórico: 02/11/2026: oportunidades, concursos e fundos/apoios do catálogo integrados em alertas locais com prova. Restam canais/outras fontes externas, concorrência específica do gerador, visual, vínculos de referência e disponibilização/agendador. Histórico: 02/11/2026: concorrência demonstrada nos cinco cenários delimitados e impasse corrigido. Restam visual, vínculos ao cadastro da referência, alertas de incentivos e disponibilização. Histórico: 02/11/2026: referência oficial preparada pela interface com prova local; restam vínculos sectorial/cartográfico da referência, concorrência/visual, alertas de incentivos e disponibilização. Histórico: 02/11/2026: filtros e ensaios específicos de documentos implementados/verificados localmente. Restam fontes reais incorporadas, visual, concorrência e disponibilização; integração de incentivos nos alertas não demonstrada. Histórico preservado: 02/11/2026: implementação local parcial com editor e percurso público; restam filtros territoriais/sectoriais, provas específicas de documentos/conflitos, fontes reais e visual/disponibilização. Histórico: Catálogo de fundos com janelas e elegibilidade não implementado; ofertas experimentais não o substituem.
[UTILIZACAO-HOMOLOGACAO-20261019] 15: Desenvolvimento restante + dados — Primeiro fundo documentado e tratamento de elegibilidade/prazo ainda em falta.","Biblioteca, taxonomias, fontes e filtros comuns","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fundos com fonte/data, elegibilidade explicada e janela; indeterminado quando parâmetros faltam.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Fundos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Fundos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
@@ -10597,63 +10852,63 @@ AUD-FUND-01,Catálogo de fundos nacionais e territoriais com elegibilidade expli
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [FUNDING-EDITOR-20261102] Catálogo e editor locais: rascunhos, prévia vinculada, publicação/retirada com autoridade editorial existente, versões imutáveis, janelas/critério explicado, documentos por versão e interesse privado. Quatro testes/91 asserções e tipos aprovados. Filtros territoriais/sectoriais, ensaios de documentos, fontes reais, visual e disponibilização pendentes; requisito parcial, sem alteração no activo. Manual de 02/11 e funding_editor_increment_20261102. [FUNDING-FILTERS-20261102] Filtros locais por sector, cobertura territorial e estado de janela, com desconhecidos explícitos e cobertura parcial. Nomes/caminhos territoriais e sectores conservados por versão. Descarga verifica versão, checksum, direitos, análise e bytes; prévia obsoleta recusada. Seis testes/204 asserções, PHPStan, tipos, lint sem avisos e compilação aprovados. Recibo funding_filters_increment_20261102 e manual. Faltam fontes reais incorporadas, validação visual, ensaios de concorrência e disponibilização; requisito parcial. [FUNDING-REFERENCES-20261102] Referência oficial FDEL empacotada com fontes/edições/hashes e prévia editorial; prepara rascunho sem publicar. Uma ficha e chamada municipal histórica, repetição sem duplicar ou substituir. Sete testes/235 asserções; PHPStan, tipos e lint aprovados. Recibo funding_references_increment_20261102; manual de 02/11. Ligações sectorial/cartográfica, concorrência, visual, alertas e disponibilização pendentes. Parcial local, sem escrita no activo. [FUNDING-CONCURRENCY-20261102] Ensaio com cinco pares de processos e bloqueios observados no PostgreSQL identificou deadlock 40P01 entre retirada e interesse da mesma pessoa. Bloqueio da conta ajustado a FOR NO KEY UPDATE, conservando serialização e referências de auditoria. Cinco cenários passaram após correcção; sete Feature/235 asserções e PHPStan/Pint aprovados. Dados/versão/interesse e auditoria sem duplicação conservados; recibo funding_concurrency_increment_20261102. Não comprova carga ou todas as intercalações. Visual, vínculos da referência, alertas e disponibilização pendentes.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Correspondência financeira genérica RF-CLU-005 é relacionada, mas não implementa o catálogo de fundos com cobertura e janelas. Não foram encontrados modelo/controlador/consumidor específicos no inventário de código.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,Reutilizar biblioteca e cadastro de entidades/parceiros para fontes e gestores reais; regras versionadas de cobertura/elegibilidade com indeterminado quando faltar parâmetro. Correspondência não representa aprovação ou compromisso de financiamento.,Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–32 h após inventário de fontes e campos; atualização operacional a definir pela Tempo.,,,
-AUD-COMPANY-01,"Comparador de forma societária orientado por perguntas, com fundamento, alternativas e limites",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental SOC-001; SEG-bf26caee-p109; SEG-bf26caee-p119; SEG-bf26caee-p730; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,SOC-001 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Roteiro societário, biblioteca e motor de regras existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento.,Não implementado,Comparador societário orientado por perguntas não implementado.,Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Alternativas com fundamento/versionamento e limites; não afirmar aprovação externa. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Perguntas recuperáveis, alternativas explicadas com fonte/data/limites, correção dos dados, retorno ao dossier sem alterar retrospectivamente a entidade ou garantir decisão externa.",P2,"Código SOC-001 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p109; SEG-bf26caee-p119; SEG-bf26caee-p730; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,26,"[{""id"": ""SEG-bf26caee-p109"", ""section"": ""1.0.2"", ""first_paragraph"": 109, ""last_paragraph"": 113, ""text"": ""Artigos 13 a 18 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Capacidade empresarial e situações especiais | INV-001; INV-007; SOC-001; §§3.1.1, 3.2.2 e 9.5 | Validações de capacidade e representação nos formulários e no comparador, sem decisão automática quando for necessária análise jurídica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p109"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p730"", ""section"": ""6.1"", ""first_paragraph"": 730, ""last_paragraph"": 736, ""text"": ""§3.2; §9 | Comparador societário orientado por perguntas | INV-001 e SOC-001 | Sim | Sem demonstração suficiente | — | Demonstrar perguntas, decisões explicadas, fontes, aviso informativo e ligação ao roteiro."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p730"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p874"", ""section"": ""9.0"", ""first_paragraph"": 874, ""last_paragraph"": 874, ""text"": ""O guia societário deve ser revisto por especialista competente e associado às fontes legais, data de actualização, entidade responsável e aviso de carácter informativo. A revisão deve confirmar a terminologia aplicável em Moçambique, distinguir empresário em nome individual de sociedades comerciais, verificar os tipos societários apresentados, uniformizar o termo “contrato” e eliminar formulações importadas de outros ordenamentos jurídicos. Cada modelo deve indicar finalidade, requisitos, limitações e necessidade de validação antes da utilização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p874"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p875"", ""section"": ""9.0"", ""first_paragraph"": 875, ""last_paragraph"": 875, ""text"": ""Para efeitos do guia societário e do comparador de forma jurídica, a fonte-base é o Código Comercial aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio. As denominações, formas societárias, representações comerciais, actos constitutivos, regras de responsabilidade e modelos contratuais devem ser reconciliados com a versão republicada do Código Comercial e com a legislação especial vigente antes de serem apresentados como regra automática ou conteúdo validado."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p875"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p877"", ""section"": ""9.1"", ""first_paragraph"": 877, ""last_paragraph"": 877, ""text"": ""Uma sociedade comercial resulta da associação de pessoas ou entidades para exercer uma actividade económica nos termos da legislação aplicável, com funções, responsabilidades, participações e obrigações definidas no acto constitutivo. A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital e os requisitos legais vigentes em Moçambique. O empresário em nome individual deve ser apresentado separadamente das formas societárias. A classificação e a terminologia publicadas no portal dependem de validação jurídica e da identificação das respectivas fontes e datas de actualização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p877"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p878"", ""section"": ""9.1"", ""first_paragraph"": 878, ""last_paragraph"": 878, ""text"": ""Contar com um sócio cujos objectivos e interesses estejam alinhados com os seus é um elemento essencial para o êxito de qualquer empreendimento. A relação societária deve promover sinergia, confiança e colaboração, factores imprescindíveis para enfrentar os desafios inerentes ao mundo dos negócios. Empreender exige dedicação, resiliência e compromisso — qualidades que se fortalecem quando partilhadas por uma equipa com visão comum."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p878"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p879"", ""section"": ""9.1"", ""first_paragraph"": 879, ""last_paragraph"": 879, ""text"": ""Existem diferentes tipos de sociedades empresariais, cada um regulamentando a participação de seus membros de acordo com características e responsabilidades específicas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p879"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p881"", ""section"": ""9.2"", ""first_paragraph"": 881, ""last_paragraph"": 881, ""text"": ""Empresário individual — categoria distinta das formas societárias."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p881"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p882"", ""section"": ""9.2"", ""first_paragraph"": 882, ""last_paragraph"": 882, ""text"": ""Sociedade em Nome Colectivo — designação sujeita a confirmação na legislação vigente antes da publicação no comparador."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p882"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p883"", ""section"": ""9.2"", ""first_paragraph"": 883, ""last_paragraph"": 883, ""text"": ""Sociedade em Comandita — forma a validar quanto às modalidades e requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p883"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p884"", ""section"": ""9.2"", ""first_paragraph"": 884, ""last_paragraph"": 884, ""text"": ""Sociedade de Capital e Indústria — forma a validar quanto à vigência e aos requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p884"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p885"", ""section"": ""9.2"", ""first_paragraph"": 885, ""last_paragraph"": 885, ""text"": ""Sociedade por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p885"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p886"", ""section"": ""9.2"", ""first_paragraph"": 886, ""last_paragraph"": 886, ""text"": ""Sociedade Unipessoal por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p886"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p887"", ""section"": ""9.2"", ""first_paragraph"": 887, ""last_paragraph"": 887, ""text"": ""Sociedade Anónima."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p887"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p888"", ""section"": ""9.2"", ""first_paragraph"": 888, ""last_paragraph"": 888, ""text"": ""Sucursal, agência e delegação — formas de representação comercial, não tipos autónomos de sociedade."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p888"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p889"", ""section"": ""9.2"", ""first_paragraph"": 889, ""last_paragraph"": 889, ""text"": ""Sociedades coligadas e relações de domínio — matérias de ligação ou controlo entre sociedades, não formas autónomas de constituição."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p889"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p890"", ""section"": ""9.2"", ""first_paragraph"": 890, ""last_paragraph"": 890, ""text"": ""Consórcio — instrumento de cooperação sujeito a enquadramento próprio, não forma societária."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p890"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p897"", ""section"": ""9.4"", ""first_paragraph"": 897, ""last_paragraph"": 897, ""text"": ""A participação, a responsabilidade, os direitos económicos e os poderes de gestão dependem da forma societária, do contrato de sociedade, da legislação aplicável e das deliberações válidas. As contribuições dos sócios podem assumir formas diferentes, de acordo com o regime jurídico e o acto constitutivo. A maior participação no capital não deve ser apresentada como sinónimo de principal proprietário, nem se deve presumir que a distribuição de quotas determina, por si só, a responsabilidade perante terceiros ou a participação nos lucros. O contrato de sociedade deve definir a estrutura de capital, os órgãos, os poderes, as regras de deliberação, os direitos e as obrigações aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p897"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p899"", ""section"": ""9.5"", ""first_paragraph"": 899, ""last_paragraph"": 899, ""text"": ""A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital, a actividade e os requisitos legais aplicáveis. A empresa em nome individual e a sociedade unipessoal possuem estruturas distintas e devem ser avaliadas separadamente. A entrada posterior de sócios, a transformação da forma jurídica e as alterações do capital ou do contrato dependem da legislação vigente, dos actos societários aplicáveis e do respectivo registo; por isso, o portal não deve apresentar estas modalidades como definitivamente fechadas à evolução da estrutura."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p899"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p901"", ""section"": ""9.6"", ""first_paragraph"": 901, ""last_paragraph"": 901, ""text"": ""A principal vantagem de ter sócios é a possibilidade de reunir pessoas com interesses e objectivos semelhantes em torno de uma finalidade comum, o que fortalece o desenvolvimento e a execução do projecto. Essa união permite complementar competências, partilhar responsabilidades e ampliar a capacidade de resposta às necessidades do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p901"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p902"", ""section"": ""9.6"", ""first_paragraph"": 902, ""last_paragraph"": 902, ""text"": ""No entanto, uma sociedade empresarial segue regras específicas e deve ser estruturada de forma estratégica. Falhas de alinhamento ou mal-entendidos entre os sócios podem gerar conflitos e comprometer o funcionamento da organização. Por isso, é essencial escolher cuidadosamente o modelo societário e estabelecer acordos claros desde o início."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p902"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p903"", ""section"": ""9.6"", ""first_paragraph"": 903, ""last_paragraph"": 903, ""text"": ""Existem diversos formatos de sociedade empresarial, com características e formas de participação próprias, permitindo ao empreendedor escolher o modelo mais adequado à realidade e aos objectivos do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p903"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p905"", ""section"": ""9.6.1"", ""first_paragraph"": 905, ""last_paragraph"": 905, ""text"": ""Não existe um tipo de sociedade empresarial universalmente melhor ou pior. O essencial é identificar o modelo alinhado ao propósito do negócio e à relação entre os sócios, preferencialmente com orientação profissional especializada."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p905"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p906"", ""section"": ""9.6.1"", ""first_paragraph"": 906, ""last_paragraph"": 906, ""text"": ""Também devem ser considerados formatos específicos para determinadas áreas de actuação, como a sociedade de advogados, que apenas pode ser composta por profissionais legalmente habilitados a exercer actividades na área do Direito."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p906"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p907"", ""section"": ""9.6.1"", ""first_paragraph"": 907, ""last_paragraph"": 907, ""text"": ""Uma avaliação cuidadosa do planeamento do negócio é indispensável para determinar a viabilidade da sociedade e identificar as alternativas jurídicas adequadas à sua formalização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p907"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [FUNDING-EDITOR-20261102] Catálogo e editor locais: rascunhos, prévia vinculada, publicação/retirada com autoridade editorial existente, versões imutáveis, janelas/critério explicado, documentos por versão e interesse privado. Quatro testes/91 asserções e tipos aprovados. Filtros territoriais/sectoriais, ensaios de documentos, fontes reais, visual e disponibilização pendentes; requisito parcial, sem alteração no activo. Manual de 02/11 e funding_editor_increment_20261102. [FUNDING-FILTERS-20261102] Filtros locais por sector, cobertura territorial e estado de janela, com desconhecidos explícitos e cobertura parcial. Nomes/caminhos territoriais e sectores conservados por versão. Descarga verifica versão, checksum, direitos, análise e bytes; prévia obsoleta recusada. Seis testes/204 asserções, PHPStan, tipos, lint sem avisos e compilação aprovados. Recibo funding_filters_increment_20261102 e manual. Faltam fontes reais incorporadas, validação visual, ensaios de concorrência e disponibilização; requisito parcial. [FUNDING-REFERENCES-20261102] Referência oficial FDEL empacotada com fontes/edições/hashes e prévia editorial; prepara rascunho sem publicar. Uma ficha e chamada municipal histórica, repetição sem duplicar ou substituir. Sete testes/235 asserções; PHPStan, tipos e lint aprovados. Recibo funding_references_increment_20261102; manual de 02/11. Ligações sectorial/cartográfica, concorrência, visual, alertas e disponibilização pendentes. Parcial local, sem escrita no activo. [FUNDING-CONCURRENCY-20261102] Ensaio com cinco pares de processos e bloqueios observados no PostgreSQL identificou deadlock 40P01 entre retirada e interesse da mesma pessoa. Bloqueio da conta ajustado a FOR NO KEY UPDATE, conservando serialização e referências de auditoria. Cinco cenários passaram após correcção; sete Feature/235 asserções e PHPStan/Pint aprovados. Dados/versão/interesse e auditoria sem duplicação conservados; recibo funding_concurrency_increment_20261102. Não comprova carga ou todas as intercalações. Visual, vínculos da referência, alertas e disponibilização pendentes. [FUNDING-ALERTS-20261102] ACT-11: versões publicadas de fundos/programas/incentivos do catálogo integradas no motor de alertas existente, com adesão explícita e preferências antigas preservadas. Filtros e desconhecidos explicados, origem/versão/estado conservados, retirada/acesso próprio, cancelamento, lote e reversão transaccional. 36 testes/612 asserções e seis frontend; PHPStan, tipos, lint e compilação aprovados. Recibo funding_alerts_increment_20261102 e manual. Sem canais externos, recolha externa ou instalação no activo; requisito agregado parcial. [FUNDING-ASSESSMENT-CONCURRENCY-20261102] Nove pares concorrentes observados aprovaram referências/versões/interesses, geradores duplicados, preferências idempotentes e ambas as precedências de cancelamento. Conferência de critérios mostra/envia apenas perguntas aplicáveis, preserva respostas locais e reinicia por ficha/versão. Oito frontend, tipos/lint/compilação aprovados; PHP da aplicação sem delta, provas 36 Feature/612 reutilizadas após conferir hashes. Recibo funding_assessment_concurrency_increment_20261102. Visual, vínculos de referência, canais externos e disponibilização continuam pendentes.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Correspondência financeira genérica RF-CLU-005 é relacionada, mas não implementa o catálogo de fundos com cobertura e janelas. Não foram encontrados modelo/controlador/consumidor específicos no inventário de código.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,Reutilizar biblioteca e cadastro de entidades/parceiros para fontes e gestores reais; regras versionadas de cobertura/elegibilidade com indeterminado quando faltar parâmetro. Correspondência não representa aprovação ou compromisso de financiamento.,Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–32 h após inventário de fontes e campos; atualização operacional a definir pela Tempo.,,,
+AUD-COMPANY-01,"Comparador de forma societária orientado por perguntas, com fundamento, alternativas e limites",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental SOC-001; SEG-bf26caee-p109; SEG-bf26caee-p119; SEG-bf26caee-p730; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,SOC-001 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Roteiro societário, biblioteca e motor de regras existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [COMPANY-COMPARISON-20261102] Comparador informativo implementado localmente: consulta pública, perguntas aplicáveis/recuperáveis, cinco alternativas da edição citada e distinção de representação/cooperação; fontes/artigos/datas, limites e conflitos explicados. Dossier existente guarda snapshot cifrado de respostas/perguntas/resultado/fonte, com histórico paginado; correcção cria nova edição e repetição sem alteração não duplica. Repetição de operação usa a versão de perguntas original. Escolha/criação explícita de dossier conserva respostas através do percurso de autenticação normal; nenhuma entidade, contrato, etapa ou aprovação criada automaticamente. 14 Feature/385 asserções e seis frontend aprovados, PHPStan/Pint/tipos/lint/build; recibo company_comparison_increment_20261102. Sem migração nova, IA, escrita no activo ou instalação remota.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [COMPANY-COMPARISON-20261102] Comparador informativo implementado localmente: consulta pública, perguntas aplicáveis/recuperáveis, cinco alternativas da edição citada e distinção de representação/cooperação; fontes/artigos/datas, limites e conflitos explicados. Dossier existente guarda snapshot cifrado de respostas/perguntas/resultado/fonte, com histórico paginado; correcção cria nova edição e repetição sem alteração não duplica. Repetição de operação usa a versão de perguntas original. Escolha/criação explícita de dossier conserva respostas através do percurso de autenticação normal; nenhuma entidade, contrato, etapa ou aprovação criada automaticamente. 14 Feature/385 asserções e seis frontend aprovados, PHPStan/Pint/tipos/lint/build; recibo company_comparison_increment_20261102. Sem migração nova, IA, escrita no activo ou instalação remota.","Implementado parcialmente","Saldo 02/11/2026: comparador base público e ligado ao dossier implementado e ensaiado localmente. Restam observação visual/login real, disponibilização e casos especiais/redacções adicionais não abrangidos pela edição citada; modelos de contratos/estatutos são AUD-COMPANY-02 e não foram declarados entregues. Histórico anterior: Comparador societário orientado por perguntas não implementado.",Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Alternativas com fundamento/versionamento e limites; não afirmar aprovação externa. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Perguntas recuperáveis, alternativas explicadas com fonte/data/limites, correção dos dados, retorno ao dossier sem alterar retrospectivamente a entidade ou garantir decisão externa.",P2,"Código SOC-001 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p109; SEG-bf26caee-p119; SEG-bf26caee-p730; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,26,"[{""id"": ""SEG-bf26caee-p109"", ""section"": ""1.0.2"", ""first_paragraph"": 109, ""last_paragraph"": 113, ""text"": ""Artigos 13 a 18 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Capacidade empresarial e situações especiais | INV-001; INV-007; SOC-001; §§3.1.1, 3.2.2 e 9.5 | Validações de capacidade e representação nos formulários e no comparador, sem decisão automática quando for necessária análise jurídica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p109"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p730"", ""section"": ""6.1"", ""first_paragraph"": 730, ""last_paragraph"": 736, ""text"": ""§3.2; §9 | Comparador societário orientado por perguntas | INV-001 e SOC-001 | Sim | Sem demonstração suficiente | — | Demonstrar perguntas, decisões explicadas, fontes, aviso informativo e ligação ao roteiro."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p730"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p874"", ""section"": ""9.0"", ""first_paragraph"": 874, ""last_paragraph"": 874, ""text"": ""O guia societário deve ser revisto por especialista competente e associado às fontes legais, data de actualização, entidade responsável e aviso de carácter informativo. A revisão deve confirmar a terminologia aplicável em Moçambique, distinguir empresário em nome individual de sociedades comerciais, verificar os tipos societários apresentados, uniformizar o termo “contrato” e eliminar formulações importadas de outros ordenamentos jurídicos. Cada modelo deve indicar finalidade, requisitos, limitações e necessidade de validação antes da utilização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p874"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p875"", ""section"": ""9.0"", ""first_paragraph"": 875, ""last_paragraph"": 875, ""text"": ""Para efeitos do guia societário e do comparador de forma jurídica, a fonte-base é o Código Comercial aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio. As denominações, formas societárias, representações comerciais, actos constitutivos, regras de responsabilidade e modelos contratuais devem ser reconciliados com a versão republicada do Código Comercial e com a legislação especial vigente antes de serem apresentados como regra automática ou conteúdo validado."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p875"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p877"", ""section"": ""9.1"", ""first_paragraph"": 877, ""last_paragraph"": 877, ""text"": ""Uma sociedade comercial resulta da associação de pessoas ou entidades para exercer uma actividade económica nos termos da legislação aplicável, com funções, responsabilidades, participações e obrigações definidas no acto constitutivo. A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital e os requisitos legais vigentes em Moçambique. O empresário em nome individual deve ser apresentado separadamente das formas societárias. A classificação e a terminologia publicadas no portal dependem de validação jurídica e da identificação das respectivas fontes e datas de actualização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p877"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p878"", ""section"": ""9.1"", ""first_paragraph"": 878, ""last_paragraph"": 878, ""text"": ""Contar com um sócio cujos objectivos e interesses estejam alinhados com os seus é um elemento essencial para o êxito de qualquer empreendimento. A relação societária deve promover sinergia, confiança e colaboração, factores imprescindíveis para enfrentar os desafios inerentes ao mundo dos negócios. Empreender exige dedicação, resiliência e compromisso — qualidades que se fortalecem quando partilhadas por uma equipa com visão comum."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p878"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p879"", ""section"": ""9.1"", ""first_paragraph"": 879, ""last_paragraph"": 879, ""text"": ""Existem diferentes tipos de sociedades empresariais, cada um regulamentando a participação de seus membros de acordo com características e responsabilidades específicas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p879"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p881"", ""section"": ""9.2"", ""first_paragraph"": 881, ""last_paragraph"": 881, ""text"": ""Empresário individual — categoria distinta das formas societárias."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p881"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p882"", ""section"": ""9.2"", ""first_paragraph"": 882, ""last_paragraph"": 882, ""text"": ""Sociedade em Nome Colectivo — designação sujeita a confirmação na legislação vigente antes da publicação no comparador."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p882"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p883"", ""section"": ""9.2"", ""first_paragraph"": 883, ""last_paragraph"": 883, ""text"": ""Sociedade em Comandita — forma a validar quanto às modalidades e requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p883"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p884"", ""section"": ""9.2"", ""first_paragraph"": 884, ""last_paragraph"": 884, ""text"": ""Sociedade de Capital e Indústria — forma a validar quanto à vigência e aos requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p884"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p885"", ""section"": ""9.2"", ""first_paragraph"": 885, ""last_paragraph"": 885, ""text"": ""Sociedade por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p885"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p886"", ""section"": ""9.2"", ""first_paragraph"": 886, ""last_paragraph"": 886, ""text"": ""Sociedade Unipessoal por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p886"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p887"", ""section"": ""9.2"", ""first_paragraph"": 887, ""last_paragraph"": 887, ""text"": ""Sociedade Anónima."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p887"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p888"", ""section"": ""9.2"", ""first_paragraph"": 888, ""last_paragraph"": 888, ""text"": ""Sucursal, agência e delegação — formas de representação comercial, não tipos autónomos de sociedade."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p888"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p889"", ""section"": ""9.2"", ""first_paragraph"": 889, ""last_paragraph"": 889, ""text"": ""Sociedades coligadas e relações de domínio — matérias de ligação ou controlo entre sociedades, não formas autónomas de constituição."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p889"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p890"", ""section"": ""9.2"", ""first_paragraph"": 890, ""last_paragraph"": 890, ""text"": ""Consórcio — instrumento de cooperação sujeito a enquadramento próprio, não forma societária."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p890"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p897"", ""section"": ""9.4"", ""first_paragraph"": 897, ""last_paragraph"": 897, ""text"": ""A participação, a responsabilidade, os direitos económicos e os poderes de gestão dependem da forma societária, do contrato de sociedade, da legislação aplicável e das deliberações válidas. As contribuições dos sócios podem assumir formas diferentes, de acordo com o regime jurídico e o acto constitutivo. A maior participação no capital não deve ser apresentada como sinónimo de principal proprietário, nem se deve presumir que a distribuição de quotas determina, por si só, a responsabilidade perante terceiros ou a participação nos lucros. O contrato de sociedade deve definir a estrutura de capital, os órgãos, os poderes, as regras de deliberação, os direitos e as obrigações aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p897"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p899"", ""section"": ""9.5"", ""first_paragraph"": 899, ""last_paragraph"": 899, ""text"": ""A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital, a actividade e os requisitos legais aplicáveis. A empresa em nome individual e a sociedade unipessoal possuem estruturas distintas e devem ser avaliadas separadamente. A entrada posterior de sócios, a transformação da forma jurídica e as alterações do capital ou do contrato dependem da legislação vigente, dos actos societários aplicáveis e do respectivo registo; por isso, o portal não deve apresentar estas modalidades como definitivamente fechadas à evolução da estrutura."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p899"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p901"", ""section"": ""9.6"", ""first_paragraph"": 901, ""last_paragraph"": 901, ""text"": ""A principal vantagem de ter sócios é a possibilidade de reunir pessoas com interesses e objectivos semelhantes em torno de uma finalidade comum, o que fortalece o desenvolvimento e a execução do projecto. Essa união permite complementar competências, partilhar responsabilidades e ampliar a capacidade de resposta às necessidades do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p901"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p902"", ""section"": ""9.6"", ""first_paragraph"": 902, ""last_paragraph"": 902, ""text"": ""No entanto, uma sociedade empresarial segue regras específicas e deve ser estruturada de forma estratégica. Falhas de alinhamento ou mal-entendidos entre os sócios podem gerar conflitos e comprometer o funcionamento da organização. Por isso, é essencial escolher cuidadosamente o modelo societário e estabelecer acordos claros desde o início."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p902"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p903"", ""section"": ""9.6"", ""first_paragraph"": 903, ""last_paragraph"": 903, ""text"": ""Existem diversos formatos de sociedade empresarial, com características e formas de participação próprias, permitindo ao empreendedor escolher o modelo mais adequado à realidade e aos objectivos do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p903"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p905"", ""section"": ""9.6.1"", ""first_paragraph"": 905, ""last_paragraph"": 905, ""text"": ""Não existe um tipo de sociedade empresarial universalmente melhor ou pior. O essencial é identificar o modelo alinhado ao propósito do negócio e à relação entre os sócios, preferencialmente com orientação profissional especializada."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p905"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p906"", ""section"": ""9.6.1"", ""first_paragraph"": 906, ""last_paragraph"": 906, ""text"": ""Também devem ser considerados formatos específicos para determinadas áreas de actuação, como a sociedade de advogados, que apenas pode ser composta por profissionais legalmente habilitados a exercer actividades na área do Direito."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p906"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p907"", ""section"": ""9.6.1"", ""first_paragraph"": 907, ""last_paragraph"": 907, ""text"": ""Uma avaliação cuidadosa do planeamento do negócio é indispensável para determinar a viabilidade da sociedade e identificar as alternativas jurídicas adequadas à sua formalização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p907"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 16: Implementar perguntas recuperáveis, alternativas fundamentadas e modelos exactos versionados. Exemplares ausentes permanecem lacuna de conteúdo.","Comparador societário orientado por perguntas não implementado.
+[RECONCILIACAO-43-20261019] 16: Implementar perguntas recuperáveis, alternativas fundamentadas e modelos exactos versionados. Exemplares ausentes permanecem lacuna de conteúdo.","Saldo 02/11/2026: comparador base público e ligado ao dossier implementado e ensaiado localmente. Restam observação visual/login real, disponibilização e casos especiais/redacções adicionais não abrangidos pela edição citada; modelos de contratos/estatutos são AUD-COMPANY-02 e não foram declarados entregues. Histórico anterior: Comparador societário orientado por perguntas não implementado.
-[UTILIZACAO-HOMOLOGACAO-20261019] 16: Desenvolvimento restante + documentos — Ramo comparativo societário e modelos identificados/recuperáveis ainda em falta.","Roteiro societário, biblioteca e motor de regras existentes",Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Alternativas com fundamento/versionamento e limites; não afirmar aprovação externa.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Comparador societário e modelos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Comparador societário e modelos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 16: Desenvolvimento restante + documentos — Ramo comparativo societário e modelos identificados/recuperáveis ainda em falta.","Roteiro societário, biblioteca e motor de regras existentes; CompanyComparison, VirtualDesk/desk_cases/desk_events cifrados, permissões/versão do dossier, profileJson e percurso existentes; sem cadastro ou motor paralelo","02/11/2026: base oficial republicada recuperada no portal do Tribunal Superior de Recurso de Maputo; original privado conservado por hash. A aceitação oficial anterior mantém-se; referência e redacção foram conferidas, sem segunda aprovação genérica da autenticidade. Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Alternativas com fundamento/versionamento e limites; não afirmar aprovação externa.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolhas técnicas: comparação informativa sem pontuação/classificação automática; preferência do utilizador não altera a forma jurídica mestre. Desconhecido mantém-se desconhecido, perguntas sem aplicação não entram na avaliação e respostas anteriores ficam recuperáveis. Reutiliza competências do dossier e não designa validadores novos.","Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Comparador societário e modelos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Comparador societário e modelos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Seleção de forma jurídica no roteiro não comprova comparador orientado por perguntas. Termos e pressupostos da secção9 devem ser reconciliados com o exemplar legal aplicável antes de se tornarem regras.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar organização mestre, perfil/dossier e biblioteca. Comparador informativo por número de participantes, responsabilidade, gestão, capital e atividade; separar empresário individual, sociedade, representação e cooperação.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,"24–48 h, excluindo inventário legal ainda por associar; fontes oficiais já aceites.",,,
-AUD-COMPANY-02,"Modelos versionados de estatutos e contratos sociais por forma jurídica, com finalidade e limitações",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental SOC-002; SEG-bf26caee-p119; SEG-bf26caee-p737; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p892; SEG-bf26caee-p893; SEG-bf26caee-p894; SEG-bf26caee-p895; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,SOC-002 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.",Biblioteca/versionamento/documentos originais. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.,"Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento.,Sem evidência suficiente,Modelos societários específicos ainda sem exemplares/URLs recuperáveis identificados; não confundir biblioteca genérica com entrega destes modelos.,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Localizar modelos, preservar versão/finalidade, recuperar por perfil e demonstrar ausência de perda do original. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Exemplar/URL exatos por modelo, original recuperável, versão e limitações visíveis, formulário contextual e derivada própria; nova versão conserva submissões/modelos anteriores.",P2,"Código SOC-002 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p119; SEG-bf26caee-p737; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p892; SEG-bf26caee-p893; SEG-bf26caee-p894; SEG-bf26caee-p895; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,29,"[{""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p737"", ""section"": ""6.1"", ""first_paragraph"": 737, ""last_paragraph"": 743, ""text"": ""§9.3 | Modelos de estatutos e contratos sociais | SOC-002 | Sim | Parcial: apenas modelos e URLs comprovadamente disponíveis | Ativo | Associar o estado activo aos exemplares e URLs identificados; a biblioteca não comprova cobertura completa. Reconciliar nomes, tipos, finalidade, fonte, versão, limitações e validação jurídica."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p737"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p874"", ""section"": ""9.0"", ""first_paragraph"": 874, ""last_paragraph"": 874, ""text"": ""O guia societário deve ser revisto por especialista competente e associado às fontes legais, data de actualização, entidade responsável e aviso de carácter informativo. A revisão deve confirmar a terminologia aplicável em Moçambique, distinguir empresário em nome individual de sociedades comerciais, verificar os tipos societários apresentados, uniformizar o termo “contrato” e eliminar formulações importadas de outros ordenamentos jurídicos. Cada modelo deve indicar finalidade, requisitos, limitações e necessidade de validação antes da utilização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p874"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p875"", ""section"": ""9.0"", ""first_paragraph"": 875, ""last_paragraph"": 875, ""text"": ""Para efeitos do guia societário e do comparador de forma jurídica, a fonte-base é o Código Comercial aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio. As denominações, formas societárias, representações comerciais, actos constitutivos, regras de responsabilidade e modelos contratuais devem ser reconciliados com a versão republicada do Código Comercial e com a legislação especial vigente antes de serem apresentados como regra automática ou conteúdo validado."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p875"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p877"", ""section"": ""9.1"", ""first_paragraph"": 877, ""last_paragraph"": 877, ""text"": ""Uma sociedade comercial resulta da associação de pessoas ou entidades para exercer uma actividade económica nos termos da legislação aplicável, com funções, responsabilidades, participações e obrigações definidas no acto constitutivo. A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital e os requisitos legais vigentes em Moçambique. O empresário em nome individual deve ser apresentado separadamente das formas societárias. A classificação e a terminologia publicadas no portal dependem de validação jurídica e da identificação das respectivas fontes e datas de actualização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p877"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p878"", ""section"": ""9.1"", ""first_paragraph"": 878, ""last_paragraph"": 878, ""text"": ""Contar com um sócio cujos objectivos e interesses estejam alinhados com os seus é um elemento essencial para o êxito de qualquer empreendimento. A relação societária deve promover sinergia, confiança e colaboração, factores imprescindíveis para enfrentar os desafios inerentes ao mundo dos negócios. Empreender exige dedicação, resiliência e compromisso — qualidades que se fortalecem quando partilhadas por uma equipa com visão comum."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p878"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p879"", ""section"": ""9.1"", ""first_paragraph"": 879, ""last_paragraph"": 879, ""text"": ""Existem diferentes tipos de sociedades empresariais, cada um regulamentando a participação de seus membros de acordo com características e responsabilidades específicas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p879"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p881"", ""section"": ""9.2"", ""first_paragraph"": 881, ""last_paragraph"": 881, ""text"": ""Empresário individual — categoria distinta das formas societárias."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p881"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p882"", ""section"": ""9.2"", ""first_paragraph"": 882, ""last_paragraph"": 882, ""text"": ""Sociedade em Nome Colectivo — designação sujeita a confirmação na legislação vigente antes da publicação no comparador."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p882"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p883"", ""section"": ""9.2"", ""first_paragraph"": 883, ""last_paragraph"": 883, ""text"": ""Sociedade em Comandita — forma a validar quanto às modalidades e requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p883"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p884"", ""section"": ""9.2"", ""first_paragraph"": 884, ""last_paragraph"": 884, ""text"": ""Sociedade de Capital e Indústria — forma a validar quanto à vigência e aos requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p884"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p885"", ""section"": ""9.2"", ""first_paragraph"": 885, ""last_paragraph"": 885, ""text"": ""Sociedade por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p885"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p886"", ""section"": ""9.2"", ""first_paragraph"": 886, ""last_paragraph"": 886, ""text"": ""Sociedade Unipessoal por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p886"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p887"", ""section"": ""9.2"", ""first_paragraph"": 887, ""last_paragraph"": 887, ""text"": ""Sociedade Anónima."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p887"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p888"", ""section"": ""9.2"", ""first_paragraph"": 888, ""last_paragraph"": 888, ""text"": ""Sucursal, agência e delegação — formas de representação comercial, não tipos autónomos de sociedade."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p888"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p889"", ""section"": ""9.2"", ""first_paragraph"": 889, ""last_paragraph"": 889, ""text"": ""Sociedades coligadas e relações de domínio — matérias de ligação ou controlo entre sociedades, não formas autónomas de constituição."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p889"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p890"", ""section"": ""9.2"", ""first_paragraph"": 890, ""last_paragraph"": 890, ""text"": ""Consórcio — instrumento de cooperação sujeito a enquadramento próprio, não forma societária."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p890"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p892"", ""section"": ""9.3"", ""first_paragraph"": 892, ""last_paragraph"": 892, ""text"": ""Modelo de contrato de sociedade por quotas — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p892"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p893"", ""section"": ""9.3"", ""first_paragraph"": 893, ""last_paragraph"": 893, ""text"": ""Modelo de contrato de sociedade anónima — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p893"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p894"", ""section"": ""9.3"", ""first_paragraph"": 894, ""last_paragraph"": 894, ""text"": ""Modelo de contrato de sociedade unipessoal por quotas — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p894"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p895"", ""section"": ""9.3"", ""first_paragraph"": 895, ""last_paragraph"": 895, ""text"": ""Outros modelos societários — só devem ser publicados depois de confirmada a forma jurídica, a vigência legal, a finalidade e as limitações de utilização."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p895"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p897"", ""section"": ""9.4"", ""first_paragraph"": 897, ""last_paragraph"": 897, ""text"": ""A participação, a responsabilidade, os direitos económicos e os poderes de gestão dependem da forma societária, do contrato de sociedade, da legislação aplicável e das deliberações válidas. As contribuições dos sócios podem assumir formas diferentes, de acordo com o regime jurídico e o acto constitutivo. A maior participação no capital não deve ser apresentada como sinónimo de principal proprietário, nem se deve presumir que a distribuição de quotas determina, por si só, a responsabilidade perante terceiros ou a participação nos lucros. O contrato de sociedade deve definir a estrutura de capital, os órgãos, os poderes, as regras de deliberação, os direitos e as obrigações aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p897"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p899"", ""section"": ""9.5"", ""first_paragraph"": 899, ""last_paragraph"": 899, ""text"": ""A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital, a actividade e os requisitos legais aplicáveis. A empresa em nome individual e a sociedade unipessoal possuem estruturas distintas e devem ser avaliadas separadamente. A entrada posterior de sócios, a transformação da forma jurídica e as alterações do capital ou do contrato dependem da legislação vigente, dos actos societários aplicáveis e do respectivo registo; por isso, o portal não deve apresentar estas modalidades como definitivamente fechadas à evolução da estrutura."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p899"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p901"", ""section"": ""9.6"", ""first_paragraph"": 901, ""last_paragraph"": 901, ""text"": ""A principal vantagem de ter sócios é a possibilidade de reunir pessoas com interesses e objectivos semelhantes em torno de uma finalidade comum, o que fortalece o desenvolvimento e a execução do projecto. Essa união permite complementar competências, partilhar responsabilidades e ampliar a capacidade de resposta às necessidades do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p901"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p902"", ""section"": ""9.6"", ""first_paragraph"": 902, ""last_paragraph"": 902, ""text"": ""No entanto, uma sociedade empresarial segue regras específicas e deve ser estruturada de forma estratégica. Falhas de alinhamento ou mal-entendidos entre os sócios podem gerar conflitos e comprometer o funcionamento da organização. Por isso, é essencial escolher cuidadosamente o modelo societário e estabelecer acordos claros desde o início."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p902"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p903"", ""section"": ""9.6"", ""first_paragraph"": 903, ""last_paragraph"": 903, ""text"": ""Existem diversos formatos de sociedade empresarial, com características e formas de participação próprias, permitindo ao empreendedor escolher o modelo mais adequado à realidade e aos objectivos do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p903"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p905"", ""section"": ""9.6.1"", ""first_paragraph"": 905, ""last_paragraph"": 905, ""text"": ""Não existe um tipo de sociedade empresarial universalmente melhor ou pior. O essencial é identificar o modelo alinhado ao propósito do negócio e à relação entre os sócios, preferencialmente com orientação profissional especializada."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p905"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p906"", ""section"": ""9.6.1"", ""first_paragraph"": 906, ""last_paragraph"": 906, ""text"": ""Também devem ser considerados formatos específicos para determinadas áreas de actuação, como a sociedade de advogados, que apenas pode ser composta por profissionais legalmente habilitados a exercer actividades na área do Direito."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p906"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p907"", ""section"": ""9.6.1"", ""first_paragraph"": 907, ""last_paragraph"": 907, ""text"": ""Uma avaliação cuidadosa do planeamento do negócio é indispensável para determinar a viabilidade da sociedade e identificar as alternativas jurídicas adequadas à sua formalização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p907"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [COMPANY-COMPARISON-20261102] Comparador informativo implementado localmente: consulta pública, perguntas aplicáveis/recuperáveis, cinco alternativas da edição citada e distinção de representação/cooperação; fontes/artigos/datas, limites e conflitos explicados. Dossier existente guarda snapshot cifrado de respostas/perguntas/resultado/fonte, com histórico paginado; correcção cria nova edição e repetição sem alteração não duplica. Repetição de operação usa a versão de perguntas original. Escolha/criação explícita de dossier conserva respostas através do percurso de autenticação normal; nenhuma entidade, contrato, etapa ou aprovação criada automaticamente. 14 Feature/385 asserções e seis frontend aprovados, PHPStan/Pint/tipos/lint/build; recibo company_comparison_increment_20261102. Sem migração nova, IA, escrita no activo ou instalação remota.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Seleção de forma jurídica no roteiro não comprova comparador orientado por perguntas. Termos e pressupostos da secção9 devem ser reconciliados com o exemplar legal aplicável antes de se tornarem regras.,Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar organização mestre, perfil/dossier e biblioteca. Comparador informativo por número de participantes, responsabilidade, gestão, capital e atividade; separar empresário individual, sociedade, representação e cooperação.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,"24–48 h, excluindo inventário legal ainda por associar; fontes oficiais já aceites.",,,
+AUD-COMPANY-02,"Modelos versionados de estatutos e contratos sociais por forma jurídica, com finalidade e limitações","[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental SOC-002; SEG-bf26caee-p119; SEG-bf26caee-p737; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p892; SEG-bf26caee-p893; SEG-bf26caee-p894; SEG-bf26caee-p895; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907; Complemento consolidado — Criação de empresas e minutas de contratos sociais.docx, SHA256 b20c6517784b6d44aa22beb67748d3f3b224f58c60a7dcb378a185669c2c543e, RF-SOC-001–008 e orientação final de implementar estrutura sem publicar cláusulas não fornecidas",SOC-002 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca/versionamento/documentos originais. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [COMPANY-PREPARATION-20261102] Estrutura privada de preparação factual implementada no dossier existente: sete secções, papéis explícitos/acumuláveis, reutilização de snapshots autorizados do proponente/empresa, capital/subscrições/realizações/acções com aritmética decimal exacta e desconhecidos conservados como nulos. Rascunhos incompletos são permitidos e inconsistências visíveis. Ficha, fontes/definição/conferência e autoria são cifradas e versionadas em desk_cases/desk_events, sem cadastro ou workflow paralelo. Guardas de acesso/versão, repetição/no-op e histórico paginado; recuperação de conflito conserva a edição no formulário. 18 Feature/343 asserções,12 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo company_preparation_increment_20261102. Não contém as sete minutas, cláusulas aprovadas, derivadas contratuais ou registo externo; fonte dos exemplares pendente conforme resposta do proprietário.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [COMPANY-PREPARATION-20261102] Estrutura privada de preparação factual implementada no dossier existente: sete secções, papéis explícitos/acumuláveis, reutilização de snapshots autorizados do proponente/empresa, capital/subscrições/realizações/acções com aritmética decimal exacta e desconhecidos conservados como nulos. Rascunhos incompletos são permitidos e inconsistências visíveis. Ficha, fontes/definição/conferência e autoria são cifradas e versionadas em desk_cases/desk_events, sem cadastro ou workflow paralelo. Guardas de acesso/versão, repetição/no-op e histórico paginado; recuperação de conflito conserva a edição no formulário. 18 Feature/343 asserções,12 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo company_preparation_increment_20261102. Não contém as sete minutas, cláusulas aprovadas, derivadas contratuais ou registo externo; fonte dos exemplares pendente conforme resposta do proprietário.","Implementado parcialmente","Saldo 02/11/2026: formulário factual e respectivo histórico disponíveis localmente; faltam os exemplares exactos dos sete modelos, ingestão/versionamento na biblioteca, vinculação ao modelo, geração de derivadas contratuais, catálogo de actividades/licenciamento integrado, revisão profissional e percursos de assinatura/submissão/registo. Sem prova visual/login real ou instalação no destino. A ficha de preparação não é um contrato social. Histórico anterior: Modelos societários específicos ainda sem exemplares/URLs recuperáveis identificados; não confundir biblioteca genérica com entrega destes modelos.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Localizar modelos, preservar versão/finalidade, recuperar por perfil e demonstrar ausência de perda do original. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Exemplar/URL exatos por modelo, original recuperável, versão e limitações visíveis, formulário contextual e derivada própria; nova versão conserva submissões/modelos anteriores.",P2,"Código SOC-002 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p119; SEG-bf26caee-p737; SEG-bf26caee-p874; SEG-bf26caee-p875; SEG-bf26caee-p877; SEG-bf26caee-p878; SEG-bf26caee-p879; SEG-bf26caee-p881; SEG-bf26caee-p882; SEG-bf26caee-p883; SEG-bf26caee-p884; SEG-bf26caee-p885; SEG-bf26caee-p886; SEG-bf26caee-p887; SEG-bf26caee-p888; SEG-bf26caee-p889; SEG-bf26caee-p890; SEG-bf26caee-p892; SEG-bf26caee-p893; SEG-bf26caee-p894; SEG-bf26caee-p895; SEG-bf26caee-p897; SEG-bf26caee-p899; SEG-bf26caee-p901; SEG-bf26caee-p902; SEG-bf26caee-p903; SEG-bf26caee-p905; SEG-bf26caee-p906; SEG-bf26caee-p907,29,"[{""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p737"", ""section"": ""6.1"", ""first_paragraph"": 737, ""last_paragraph"": 743, ""text"": ""§9.3 | Modelos de estatutos e contratos sociais | SOC-002 | Sim | Parcial: apenas modelos e URLs comprovadamente disponíveis | Ativo | Associar o estado activo aos exemplares e URLs identificados; a biblioteca não comprova cobertura completa. Reconciliar nomes, tipos, finalidade, fonte, versão, limitações e validação jurídica."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p737"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p874"", ""section"": ""9.0"", ""first_paragraph"": 874, ""last_paragraph"": 874, ""text"": ""O guia societário deve ser revisto por especialista competente e associado às fontes legais, data de actualização, entidade responsável e aviso de carácter informativo. A revisão deve confirmar a terminologia aplicável em Moçambique, distinguir empresário em nome individual de sociedades comerciais, verificar os tipos societários apresentados, uniformizar o termo “contrato” e eliminar formulações importadas de outros ordenamentos jurídicos. Cada modelo deve indicar finalidade, requisitos, limitações e necessidade de validação antes da utilização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p874"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p875"", ""section"": ""9.0"", ""first_paragraph"": 875, ""last_paragraph"": 875, ""text"": ""Para efeitos do guia societário e do comparador de forma jurídica, a fonte-base é o Código Comercial aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio. As denominações, formas societárias, representações comerciais, actos constitutivos, regras de responsabilidade e modelos contratuais devem ser reconciliados com a versão republicada do Código Comercial e com a legislação especial vigente antes de serem apresentados como regra automática ou conteúdo validado."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p875"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p877"", ""section"": ""9.1"", ""first_paragraph"": 877, ""last_paragraph"": 877, ""text"": ""Uma sociedade comercial resulta da associação de pessoas ou entidades para exercer uma actividade económica nos termos da legislação aplicável, com funções, responsabilidades, participações e obrigações definidas no acto constitutivo. A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital e os requisitos legais vigentes em Moçambique. O empresário em nome individual deve ser apresentado separadamente das formas societárias. A classificação e a terminologia publicadas no portal dependem de validação jurídica e da identificação das respectivas fontes e datas de actualização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p877"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p878"", ""section"": ""9.1"", ""first_paragraph"": 878, ""last_paragraph"": 878, ""text"": ""Contar com um sócio cujos objectivos e interesses estejam alinhados com os seus é um elemento essencial para o êxito de qualquer empreendimento. A relação societária deve promover sinergia, confiança e colaboração, factores imprescindíveis para enfrentar os desafios inerentes ao mundo dos negócios. Empreender exige dedicação, resiliência e compromisso — qualidades que se fortalecem quando partilhadas por uma equipa com visão comum."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p878"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p879"", ""section"": ""9.1"", ""first_paragraph"": 879, ""last_paragraph"": 879, ""text"": ""Existem diferentes tipos de sociedades empresariais, cada um regulamentando a participação de seus membros de acordo com características e responsabilidades específicas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p879"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p881"", ""section"": ""9.2"", ""first_paragraph"": 881, ""last_paragraph"": 881, ""text"": ""Empresário individual — categoria distinta das formas societárias."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p881"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p882"", ""section"": ""9.2"", ""first_paragraph"": 882, ""last_paragraph"": 882, ""text"": ""Sociedade em Nome Colectivo — designação sujeita a confirmação na legislação vigente antes da publicação no comparador."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p882"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p883"", ""section"": ""9.2"", ""first_paragraph"": 883, ""last_paragraph"": 883, ""text"": ""Sociedade em Comandita — forma a validar quanto às modalidades e requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p883"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p884"", ""section"": ""9.2"", ""first_paragraph"": 884, ""last_paragraph"": 884, ""text"": ""Sociedade de Capital e Indústria — forma a validar quanto à vigência e aos requisitos aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p884"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p885"", ""section"": ""9.2"", ""first_paragraph"": 885, ""last_paragraph"": 885, ""text"": ""Sociedade por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p885"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p886"", ""section"": ""9.2"", ""first_paragraph"": 886, ""last_paragraph"": 886, ""text"": ""Sociedade Unipessoal por Quotas."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p886"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p887"", ""section"": ""9.2"", ""first_paragraph"": 887, ""last_paragraph"": 887, ""text"": ""Sociedade Anónima."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p887"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p888"", ""section"": ""9.2"", ""first_paragraph"": 888, ""last_paragraph"": 888, ""text"": ""Sucursal, agência e delegação — formas de representação comercial, não tipos autónomos de sociedade."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p888"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p889"", ""section"": ""9.2"", ""first_paragraph"": 889, ""last_paragraph"": 889, ""text"": ""Sociedades coligadas e relações de domínio — matérias de ligação ou controlo entre sociedades, não formas autónomas de constituição."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p889"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p890"", ""section"": ""9.2"", ""first_paragraph"": 890, ""last_paragraph"": 890, ""text"": ""Consórcio — instrumento de cooperação sujeito a enquadramento próprio, não forma societária."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p890"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p892"", ""section"": ""9.3"", ""first_paragraph"": 892, ""last_paragraph"": 892, ""text"": ""Modelo de contrato de sociedade por quotas — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p892"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p893"", ""section"": ""9.3"", ""first_paragraph"": 893, ""last_paragraph"": 893, ""text"": ""Modelo de contrato de sociedade anónima — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p893"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p894"", ""section"": ""9.3"", ""first_paragraph"": 894, ""last_paragraph"": 894, ""text"": ""Modelo de contrato de sociedade unipessoal por quotas — sujeito a validação jurídica, indicação da fonte e controlo de versão."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p894"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p895"", ""section"": ""9.3"", ""first_paragraph"": 895, ""last_paragraph"": 895, ""text"": ""Outros modelos societários — só devem ser publicados depois de confirmada a forma jurídica, a vigência legal, a finalidade e as limitações de utilização."", ""requirements"": [""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p895"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p897"", ""section"": ""9.4"", ""first_paragraph"": 897, ""last_paragraph"": 897, ""text"": ""A participação, a responsabilidade, os direitos económicos e os poderes de gestão dependem da forma societária, do contrato de sociedade, da legislação aplicável e das deliberações válidas. As contribuições dos sócios podem assumir formas diferentes, de acordo com o regime jurídico e o acto constitutivo. A maior participação no capital não deve ser apresentada como sinónimo de principal proprietário, nem se deve presumir que a distribuição de quotas determina, por si só, a responsabilidade perante terceiros ou a participação nos lucros. O contrato de sociedade deve definir a estrutura de capital, os órgãos, os poderes, as regras de deliberação, os direitos e as obrigações aplicáveis."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p897"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p899"", ""section"": ""9.5"", ""first_paragraph"": 899, ""last_paragraph"": 899, ""text"": ""A escolha da forma jurídica deve considerar o número de participantes, o regime de responsabilidade, a estrutura de gestão, as necessidades de capital, a actividade e os requisitos legais aplicáveis. A empresa em nome individual e a sociedade unipessoal possuem estruturas distintas e devem ser avaliadas separadamente. A entrada posterior de sócios, a transformação da forma jurídica e as alterações do capital ou do contrato dependem da legislação vigente, dos actos societários aplicáveis e do respectivo registo; por isso, o portal não deve apresentar estas modalidades como definitivamente fechadas à evolução da estrutura."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p899"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p901"", ""section"": ""9.6"", ""first_paragraph"": 901, ""last_paragraph"": 901, ""text"": ""A principal vantagem de ter sócios é a possibilidade de reunir pessoas com interesses e objectivos semelhantes em torno de uma finalidade comum, o que fortalece o desenvolvimento e a execução do projecto. Essa união permite complementar competências, partilhar responsabilidades e ampliar a capacidade de resposta às necessidades do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p901"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p902"", ""section"": ""9.6"", ""first_paragraph"": 902, ""last_paragraph"": 902, ""text"": ""No entanto, uma sociedade empresarial segue regras específicas e deve ser estruturada de forma estratégica. Falhas de alinhamento ou mal-entendidos entre os sócios podem gerar conflitos e comprometer o funcionamento da organização. Por isso, é essencial escolher cuidadosamente o modelo societário e estabelecer acordos claros desde o início."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p902"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p903"", ""section"": ""9.6"", ""first_paragraph"": 903, ""last_paragraph"": 903, ""text"": ""Existem diversos formatos de sociedade empresarial, com características e formas de participação próprias, permitindo ao empreendedor escolher o modelo mais adequado à realidade e aos objectivos do negócio."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p903"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p905"", ""section"": ""9.6.1"", ""first_paragraph"": 905, ""last_paragraph"": 905, ""text"": ""Não existe um tipo de sociedade empresarial universalmente melhor ou pior. O essencial é identificar o modelo alinhado ao propósito do negócio e à relação entre os sócios, preferencialmente com orientação profissional especializada."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p905"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p906"", ""section"": ""9.6.1"", ""first_paragraph"": 906, ""last_paragraph"": 906, ""text"": ""Também devem ser considerados formatos específicos para determinadas áreas de actuação, como a sociedade de advogados, que apenas pode ser composta por profissionais legalmente habilitados a exercer actividades na área do Direito."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p906"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p907"", ""section"": ""9.6.1"", ""first_paragraph"": 907, ""last_paragraph"": 907, ""text"": ""Uma avaliação cuidadosa do planeamento do negócio é indispensável para determinar a viabilidade da sociedade e identificar as alternativas jurídicas adequadas à sua formalização."", ""requirements"": [""AUD-COMPANY-01"", ""AUD-COMPANY-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p907"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 16: Implementar perguntas recuperáveis, alternativas fundamentadas e modelos exactos versionados. Exemplares ausentes permanecem lacuna de conteúdo.","Modelos societários específicos ainda sem exemplares/URLs recuperáveis identificados; não confundir biblioteca genérica com entrega destes modelos.
+[RECONCILIACAO-43-20261019] 16: Implementar perguntas recuperáveis, alternativas fundamentadas e modelos exactos versionados. Exemplares ausentes permanecem lacuna de conteúdo.","Saldo 02/11/2026: formulário factual e respectivo histórico disponíveis localmente; faltam os exemplares exactos dos sete modelos, ingestão/versionamento na biblioteca, vinculação ao modelo, geração de derivadas contratuais, catálogo de actividades/licenciamento integrado, revisão profissional e percursos de assinatura/submissão/registo. Sem prova visual/login real ou instalação no destino. A ficha de preparação não é um contrato social. Histórico anterior: Modelos societários específicos ainda sem exemplares/URLs recuperáveis identificados; não confundir biblioteca genérica com entrega destes modelos.
-[UTILIZACAO-HOMOLOGACAO-20261019] 16: Desenvolvimento restante + documentos — Ramo comparativo societário e modelos identificados/recuperáveis ainda em falta.",Biblioteca/versionamento/documentos originais,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Localizar modelos, preservar versão/finalidade, recuperar por perfil e demonstrar ausência de perda do original.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Comparador societário e modelos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Comparador societário e modelos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 16: Desenvolvimento restante + documentos — Ramo comparativo societário e modelos identificados/recuperáveis ainda em falta.","Biblioteca/versionamento/documentos originais; VirtualDesk, snapshots/autorização/versionamento/cifragem/eventos do dossier e formas/fontes de CompanyComparison; biblioteca documental existente conservada para os exemplares futuros","02/11/2026: proprietário respondeu «nao tenho neste momento a url» à localização dos sete modelos. Inventário nas pastas fonte e complemento fornecido não identificou os exemplares; sem nova pergunta repetida. A falta não bloqueia a preparação factual independente. Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Localizar modelos, preservar versão/finalidade, recuperar por perfil e demonstrar ausência de perda do original.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolha técnica: nenhuma cláusula inventada, identidade inferida ou aprovação atribuída. Ficha incompleta é guardável; validações aritméticas não certificam pagamentos. Limites de tamanho/precisão são técnicos e não alçadas ou mínimos legais. O cadastro futuro não reescreve os valores de origem já utilizados.","Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Comparador societário e modelos=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Comparador societário e modelos=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"A secção6.1 afirma disponibilidade ativa parcial, mas não identifica exemplares e URLs. A biblioteca genérica não comprova estes modelos; não marcar ativos sem localizar os ficheiros e verificar recuperação/permissões.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar documents/portal_resources/revisions e links, sem outro repositório; conservar original, hash, origem, versão, tipo, finalidade e adaptação separada.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,8–16 h de reconciliação documental; estimar adaptação só depois de localizar os exemplares.,,,
-AUD-CAPITAL-01,"Orientação sobre private equity e capitalização, preparação, riscos, documentos e percurso",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental CAP-001; SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p702,CAP-001 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.",Biblioteca e passos existentes do percurso. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.,"Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento.,Não implementado,Guião estruturado de capitalização não implementado.,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Guião com opções, riscos, preparação/documentos e fonte aplicável; sem promessa de retorno. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Consulta pública com fontes/versões, instrumentos distinguidos, riscos/documentos e próxima ação; guardar referência no dossier correto; sem recomendar sucesso nem assumir compromisso.",P2,"Código CAP-001 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p702,4,"[{""id"": ""SEG-bf26caee-p153"", ""section"": ""1.4"", ""first_paragraph"": 153, ""last_paragraph"": 153, ""text"": ""Reforçar a componente de oferta e procura de activos, incluindo empresas e empreendimentos, e tratar os direitos e contratos fundiários apenas nas modalidades e autorizações já definidas nos documentos submetidos."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p153"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p154"", ""section"": ""1.4"", ""first_paragraph"": 154, ""last_paragraph"": 154, ""text"": ""Incorporar regras e orientações sobre private equity e outras formas de capitalização, tornando as oportunidades mais claras e atractivas."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p154"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p155"", ""section"": ""1.4"", ""first_paragraph"": 155, ""last_paragraph"": 155, ""text"": ""Criar um guião com requisitos e regras para admissão à Bolsa de Valores de Moçambique."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p155"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p702"", ""section"": ""6.1"", ""first_paragraph"": 702, ""last_paragraph"": 708, ""text"": ""§1.4 | Private equity e capitalização | CAP-001 | Sim | Sem demonstração suficiente | — | Publicar orientação estruturada sobre preparação, elegibilidade, riscos, documentação, fontes e percurso."", ""requirements"": [""AUD-CAPITAL-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p702"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [COMPANY-PREPARATION-20261102] Estrutura privada de preparação factual implementada no dossier existente: sete secções, papéis explícitos/acumuláveis, reutilização de snapshots autorizados do proponente/empresa, capital/subscrições/realizações/acções com aritmética decimal exacta e desconhecidos conservados como nulos. Rascunhos incompletos são permitidos e inconsistências visíveis. Ficha, fontes/definição/conferência e autoria são cifradas e versionadas em desk_cases/desk_events, sem cadastro ou workflow paralelo. Guardas de acesso/versão, repetição/no-op e histórico paginado; recuperação de conflito conserva a edição no formulário. 18 Feature/343 asserções,12 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo company_preparation_increment_20261102. Não contém as sete minutas, cláusulas aprovadas, derivadas contratuais ou registo externo; fonte dos exemplares pendente conforme resposta do proprietário.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"A secção6.1 afirma disponibilidade ativa parcial, mas não identifica exemplares e URLs. A biblioteca genérica não comprova estes modelos; não marcar ativos sem localizar os ficheiros e verificar recuperação/permissões.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,"Reutilizar documents/portal_resources/revisions e links, sem outro repositório; conservar original, hash, origem, versão, tipo, finalidade e adaptação separada.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,8–16 h de reconciliação documental; estimar adaptação só depois de localizar os exemplares.,,,
+AUD-CAPITAL-01,"Orientação sobre private equity e capitalização, preparação, riscos, documentos e percurso",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental CAP-001; SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p702,CAP-001 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca e passos existentes do percurso. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [CAPITAL-GUIDANCE-20261102] Guia público /guias-investimento/capitalizacao implementado: quatro instrumentos, riscos/preparação, elegibilidade por entidade sem pontuação, documentação, fontes/edições/data/hash e próximos passos. Escolha explícita de dossier conserva códigos e edição através da autenticação; nota só no percurso privado. Referência cifrada com guia integral, fontes, escolhas, nota, autor/data e revisão/hash do contexto; histórico paginado, correcção, replay/no-op, controlo de versão/acesso e recuperação de conflitos. Edições antigas/retiradas continuam consultáveis; nova edição é explícita, com aviso de instrumentos retirados. 21 Feature/524 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo capital_guidance_increment_20261102. Sem financiamento, intermediação, decisão externa, cálculo fiscal/financeiro ou nova IA. AUD-CAPITAL-02 permanece separado.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [CAPITAL-GUIDANCE-20261102] Guia público /guias-investimento/capitalizacao implementado: quatro instrumentos, riscos/preparação, elegibilidade por entidade sem pontuação, documentação, fontes/edições/data/hash e próximos passos. Escolha explícita de dossier conserva códigos e edição através da autenticação; nota só no percurso privado. Referência cifrada com guia integral, fontes, escolhas, nota, autor/data e revisão/hash do contexto; histórico paginado, correcção, replay/no-op, controlo de versão/acesso e recuperação de conflitos. Edições antigas/retiradas continuam consultáveis; nova edição é explícita, com aviso de instrumentos retirados. 21 Feature/524 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo capital_guidance_increment_20261102. Sem financiamento, intermediação, decisão externa, cálculo fiscal/financeiro ou nova IA. AUD-CAPITAL-02 permanece separado.","Implementado parcialmente","Saldo 02/11/2026: guia base de capitalização e referências no dossier implementados/ensaiados localmente. Restam observação visual/login real e disponibilização; condições particulares, disponibilidade de produtos e decisões dependem de cada contraparte. Guião da Bolsa por segmento/interveniente/artigo/prazo é AUD-CAPITAL-02, ainda pendente. Histórico anterior: Guião estruturado de capitalização não implementado.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Guião com opções, riscos, preparação/documentos e fonte aplicável; sem promessa de retorno. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Consulta pública com fontes/versões, instrumentos distinguidos, riscos/documentos e próxima ação; guardar referência no dossier correto; sem recomendar sucesso nem assumir compromisso.",P2,"Código CAP-001 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p702,4,"[{""id"": ""SEG-bf26caee-p153"", ""section"": ""1.4"", ""first_paragraph"": 153, ""last_paragraph"": 153, ""text"": ""Reforçar a componente de oferta e procura de activos, incluindo empresas e empreendimentos, e tratar os direitos e contratos fundiários apenas nas modalidades e autorizações já definidas nos documentos submetidos."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p153"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p154"", ""section"": ""1.4"", ""first_paragraph"": 154, ""last_paragraph"": 154, ""text"": ""Incorporar regras e orientações sobre private equity e outras formas de capitalização, tornando as oportunidades mais claras e atractivas."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p154"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p155"", ""section"": ""1.4"", ""first_paragraph"": 155, ""last_paragraph"": 155, ""text"": ""Criar um guião com requisitos e regras para admissão à Bolsa de Valores de Moçambique."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p155"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p702"", ""section"": ""6.1"", ""first_paragraph"": 702, ""last_paragraph"": 708, ""text"": ""§1.4 | Private equity e capitalização | CAP-001 | Sim | Sem demonstração suficiente | — | Publicar orientação estruturada sobre preparação, elegibilidade, riscos, documentação, fontes e percurso."", ""requirements"": [""AUD-CAPITAL-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p702"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 17: Implementar guiões private equity/capitalização/Bolsa com etapas, intervenientes, riscos/fontes e referência recuperável no dossier.","Guião estruturado de capitalização não implementado.
+[RECONCILIACAO-43-20261019] 17: Implementar guiões private equity/capitalização/Bolsa com etapas, intervenientes, riscos/fontes e referência recuperável no dossier.","Saldo 02/11/2026: guia base de capitalização e referências no dossier implementados/ensaiados localmente. Restam observação visual/login real e disponibilização; condições particulares, disponibilidade de produtos e decisões dependem de cada contraparte. Guião da Bolsa por segmento/interveniente/artigo/prazo é AUD-CAPITAL-02, ainda pendente. Histórico anterior: Guião estruturado de capitalização não implementado.
-[UTILIZACAO-HOMOLOGACAO-20261019] 17: Desenvolvimento restante + documentos — Guiões de capitalização/private equity/Bolsa e cobertura documental ainda em falta.",Biblioteca e passos existentes do percurso,"Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Guião com opções, riscos, preparação/documentos e fonte aplicável; sem promessa de retorno.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Capitalização/private equity e Bolsa=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Capitalização/private equity e Bolsa=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 17: Desenvolvimento restante + documentos — Guiões de capitalização/private equity/Bolsa e cobertura documental ainda em falta.","Biblioteca e passos existentes do percurso; VirtualDesk/desk_cases/desk_events cifrados, InvestorPath.contexts, InvestorContext e documentos/etapas financeiras existentes; sem workflow, cadastro ou motor de cálculo paralelo","02/11/2026: exemplares de cinco fontes primárias recuperados e conservados por hash (BNI, IFC Equity/Loans/How to Apply, Chase educativo). Edição/data não inventadas: páginas sem data editorial identificam exemplar e consulta. Produtos/condições de uma instituição não são regras gerais. Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Guião com opções, riscos, preparação/documentos e fonte aplicável; sem promessa de retorno.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolha técnica: guia informativo e referência no dossier, sem classificação automática, submissão, financiamento, procuração ou obrigação. O artigo educativo dos EUA suporta apenas conceitos gerais; não importa regras fiscais/legais para Moçambique. Nota privada não passa na querystring; fontes/guia guardados não seguem silenciosamente edições futuras. Mínimos bolsistas expirados não são apresentados como actuais.","Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Capitalização/private equity e Bolsa=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Capitalização/private equity e Bolsa=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Não foi demonstrado guia estruturado de capitalização. O pedido não autoriza custódia, intermediação, promessa de retorno ou aprovação dos módulos de oferta.",Reutilizar componentes/contratos; definição funcional própria e nenhuma nova ativação.,"Reutilizar biblioteca/guia público, dossier e parceiros autorizados; manter separado de ofertas experimentais. RF-CRM-009 e regras de facilitação são relações existentes, sem equivalência automática com este guia.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–24 h após conteúdo/âmbito definidos; não inclui intermediação.,,,
-AUD-CAPITAL-02,"Guião de admissão à Bolsa de Valores de Moçambique, distinguindo Bolsa, regulador e operadores",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental CAP-002; SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p709,CAP-002 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca, checklist e percurso existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento.,Não implementado,"Guião da Bolsa por segmento, intervenientes e requisitos não implementado.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fonte por requisito, condições/períodos identificados e decisões externas separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Etapas, entidade, base/artigo/redação, documentos, requisitos por segmento e lacunas explícitas; recuperação no dossier e encaminhamento permitido, sem integração externa simulada.",P2,"Código CAP-002 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p709,4,"[{""id"": ""SEG-bf26caee-p153"", ""section"": ""1.4"", ""first_paragraph"": 153, ""last_paragraph"": 153, ""text"": ""Reforçar a componente de oferta e procura de activos, incluindo empresas e empreendimentos, e tratar os direitos e contratos fundiários apenas nas modalidades e autorizações já definidas nos documentos submetidos."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p153"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p154"", ""section"": ""1.4"", ""first_paragraph"": 154, ""last_paragraph"": 154, ""text"": ""Incorporar regras e orientações sobre private equity e outras formas de capitalização, tornando as oportunidades mais claras e atractivas."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p154"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p155"", ""section"": ""1.4"", ""first_paragraph"": 155, ""last_paragraph"": 155, ""text"": ""Criar um guião com requisitos e regras para admissão à Bolsa de Valores de Moçambique."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p155"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p709"", ""section"": ""6.1"", ""first_paragraph"": 709, ""last_paragraph"": 715, ""text"": ""§1.4 | Guião de admissão à Bolsa de Valores de Moçambique | CAP-002 | Sim | Sem demonstração suficiente | — | Distinguir bolsa, autoridade reguladora e intermediários; demonstrar requisitos, fontes, documentos e etapas."", ""requirements"": [""AUD-CAPITAL-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p709"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [CAPITAL-GUIDANCE-20261102] Guia público /guias-investimento/capitalizacao implementado: quatro instrumentos, riscos/preparação, elegibilidade por entidade sem pontuação, documentação, fontes/edições/data/hash e próximos passos. Escolha explícita de dossier conserva códigos e edição através da autenticação; nota só no percurso privado. Referência cifrada com guia integral, fontes, escolhas, nota, autor/data e revisão/hash do contexto; histórico paginado, correcção, replay/no-op, controlo de versão/acesso e recuperação de conflitos. Edições antigas/retiradas continuam consultáveis; nova edição é explícita, com aviso de instrumentos retirados. 21 Feature/524 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo capital_guidance_increment_20261102. Sem financiamento, intermediação, decisão externa, cálculo fiscal/financeiro ou nova IA. AUD-CAPITAL-02 permanece separado.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Não foi demonstrado guia estruturado de capitalização. O pedido não autoriza custódia, intermediação, promessa de retorno ou aprovação dos módulos de oferta.",Reutilizar componentes/contratos; definição funcional própria e nenhuma nova ativação.,"Reutilizar biblioteca/guia público, dossier e parceiros autorizados; manter separado de ofertas experimentais. RF-CRM-009 e regras de facilitação são relações existentes, sem equivalência automática com este guia.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–24 h após conteúdo/âmbito definidos; não inclui intermediação.,,,
+AUD-CAPITAL-02,"Guião de admissão à Bolsa de Valores de Moçambique, distinguindo Bolsa, regulador e operadores",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental CAP-002; SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p709,CAP-002 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Biblioteca, checklist e percurso existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [BVM-ADMISSION-20261103] Guião /guias-investimento/bolsa implementado no mecanismo InvestmentGuides já entregue: cinco percursos (acções/obrigações MCO e Segundo; acções Terceiro), seis etapas/intervenientes, requisitos e dispensas com artigo/redacção/página por item, documentação comum uma vez e específica por percurso. Sete fontes PDF preservadas por hash, seis novas e Código Comercial republicado já aceite reutilizado; leitura textual e visual dos pontos críticos. Regime de2021 do Terceiro substitui referências de2019; montantes anuais e encargos actuais ficam indeterminados, sem reaplicar mínimos expirados em31/03/2025. Referência privada usa dossier/histórico cifrado e edição/contexto existentes; dois guias no mesmo dossier não misturam revisões/replay/paginação. 14 Feature/474 asserções e18 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo bvm_admission_increment_20261103. Encaminhamento é consulta dos canais oficiais, sem envio, oferta, registo, negociação ou admissão simulados.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. [BVM-ADMISSION-20261103] Guião /guias-investimento/bolsa implementado no mecanismo InvestmentGuides já entregue: cinco percursos (acções/obrigações MCO e Segundo; acções Terceiro), seis etapas/intervenientes, requisitos e dispensas com artigo/redacção/página por item, documentação comum uma vez e específica por percurso. Sete fontes PDF preservadas por hash, seis novas e Código Comercial republicado já aceite reutilizado; leitura textual e visual dos pontos críticos. Regime de2021 do Terceiro substitui referências de2019; montantes anuais e encargos actuais ficam indeterminados, sem reaplicar mínimos expirados em31/03/2025. Referência privada usa dossier/histórico cifrado e edição/contexto existentes; dois guias no mesmo dossier não misturam revisões/replay/paginação. 14 Feature/474 asserções e18 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo bvm_admission_increment_20261103. Encaminhamento é consulta dos canais oficiais, sem envio, oferta, registo, negociação ou admissão simulados.","Implementado parcialmente","Saldo 03/11/2026: guião base de cinco percursos e referência recuperável implementados/ensaiados localmente. Restam regulamento anual de montantes para o período actual, preçário/encargos actuais, procedimentos operacionais completos da CVM (referência a2025 identificada mas não codificada), regimes especiais/valores não empresariais, alterações posteriores não abrangidas, observação visual/login real e disponibilização. Informação indeterminada não é zero nem motivo para bloquear a preparação privada. Histórico anterior: Guião da Bolsa por segmento, intervenientes e requisitos não implementado.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fonte por requisito, condições/períodos identificados e decisões externas separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Etapas, entidade, base/artigo/redação, documentos, requisitos por segmento e lacunas explícitas; recuperação no dossier e encaminhamento permitido, sem integração externa simulada.",P2,"Código CAP-002 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p153; SEG-bf26caee-p154; SEG-bf26caee-p155; SEG-bf26caee-p709,4,"[{""id"": ""SEG-bf26caee-p153"", ""section"": ""1.4"", ""first_paragraph"": 153, ""last_paragraph"": 153, ""text"": ""Reforçar a componente de oferta e procura de activos, incluindo empresas e empreendimentos, e tratar os direitos e contratos fundiários apenas nas modalidades e autorizações já definidas nos documentos submetidos."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p153"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p154"", ""section"": ""1.4"", ""first_paragraph"": 154, ""last_paragraph"": 154, ""text"": ""Incorporar regras e orientações sobre private equity e outras formas de capitalização, tornando as oportunidades mais claras e atractivas."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p154"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p155"", ""section"": ""1.4"", ""first_paragraph"": 155, ""last_paragraph"": 155, ""text"": ""Criar um guião com requisitos e regras para admissão à Bolsa de Valores de Moçambique."", ""requirements"": [""AUD-CAPITAL-01"", ""AUD-CAPITAL-02"", ""AUD-OP-03"", ""AUD-PROFILE-28""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p155"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p709"", ""section"": ""6.1"", ""first_paragraph"": 709, ""last_paragraph"": 715, ""text"": ""§1.4 | Guião de admissão à Bolsa de Valores de Moçambique | CAP-002 | Sim | Sem demonstração suficiente | — | Distinguir bolsa, autoridade reguladora e intermediários; demonstrar requisitos, fontes, documentos e etapas."", ""requirements"": [""AUD-CAPITAL-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p709"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",não implementado,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 17: Implementar guiões private equity/capitalização/Bolsa com etapas, intervenientes, riscos/fontes e referência recuperável no dossier.","Guião da Bolsa por segmento, intervenientes e requisitos não implementado.
+[RECONCILIACAO-43-20261019] 17: Implementar guiões private equity/capitalização/Bolsa com etapas, intervenientes, riscos/fontes e referência recuperável no dossier.","Saldo 03/11/2026: guião base de cinco percursos e referência recuperável implementados/ensaiados localmente. Restam regulamento anual de montantes para o período actual, preçário/encargos actuais, procedimentos operacionais completos da CVM (referência a2025 identificada mas não codificada), regimes especiais/valores não empresariais, alterações posteriores não abrangidas, observação visual/login real e disponibilização. Informação indeterminada não é zero nem motivo para bloquear a preparação privada. Histórico anterior: Guião da Bolsa por segmento, intervenientes e requisitos não implementado.
-[UTILIZACAO-HOMOLOGACAO-20261019] 17: Desenvolvimento restante + documentos — Guiões de capitalização/private equity/Bolsa e cobertura documental ainda em falta.","Biblioteca, checklist e percurso existentes","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fonte por requisito, condições/períodos identificados e decisões externas separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Capitalização/private equity e Bolsa=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Capitalização/private equity e Bolsa=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 17: Desenvolvimento restante + documentos — Guiões de capitalização/private equity/Bolsa e cobertura documental ainda em falta.","Biblioteca, checklist e percurso existentes; InvestmentGuides/guia público e referências cifradas, VirtualDesk/desk_cases/desk_events, contexto/percurso/documentos e controlos já existentes; sem segundo workflow ou tabela de contratação/admissão","03/11/2026: exemplares BVM recuperados por HTTP após timeout do leitor web. Os mínimos2024 têm período terminado; regime Terceiro04/2021 revoga04/2019. Alteração expressa do CMVM pelos arts.8/52 no DL1/2022 e limitação SAS/art444 conferidas no exemplar republicado já aceite. A autenticidade oficial não foi novamente submetida a aprovação genérica. Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Fonte por requisito, condições/períodos identificados e decisões externas separadas.","Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Aplicação de fontes: a página informativa histórica não substitui o regulamento de2021; dispensas de entrada não são permanentes, extensão não é automática e portadores não são confundidos com nominativos após2022. BVM, Banco de Moçambique, CVM e operador têm papéis distintos. Investidor estrangeiro não é automaticamente emitente estrangeiro. Nenhum preçário, alçada, responsável nominal ou integração externa inventado.","Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Capitalização/private equity e Bolsa=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Capitalização/private equity e Bolsa=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Guião por segmento, documentos, condições e fonte aplicável ainda não demonstrado. Não inferir valores, prazos, prospectos, taxas ou aprovação pelos artigos1–3.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,Reutilizar guia/biblioteca/dossier/checklists. Relacionar pedido de admissão e patrocínio às referências específicas; separar ação interna do portal e ato de entidade competente.,Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–32 h após correspondências normativas; não preencher taxas/prazos ausentes.,,,
-AUD-CHECKLIST-01,"Editor de checklists e formulários configuráveis, publicação de versões e preservação de submissões anteriores",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-007; SEG-bf26caee-p14; SEG-bf26caee-p15; SEG-bf26caee-p20; SEG-bf26caee-p23; SEG-bf26caee-p26; SEG-bf26caee-p29; SEG-bf26caee-p32; SEG-bf26caee-p35; SEG-bf26caee-p38; SEG-bf26caee-p41; SEG-bf26caee-p44; SEG-bf26caee-p47; SEG-bf26caee-p50; SEG-bf26caee-p53; SEG-bf26caee-p56; SEG-bf26caee-p59; SEG-bf26caee-p62; SEG-bf26caee-p65; SEG-bf26caee-p68; SEG-bf26caee-p71; SEG-bf26caee-p74; SEG-bf26caee-p77; SEG-bf26caee-p80; SEG-bf26caee-p83; SEG-bf26caee-p87; SEG-bf26caee-p104; SEG-bf26caee-p109; SEG-bf26caee-p114; SEG-bf26caee-p119; SEG-bf26caee-p124; SEG-bf26caee-p129; SEG-bf26caee-p134; SEG-bf26caee-p140; SEG-bf26caee-p144; SEG-bf26caee-p145; SEG-bf26caee-p146; SEG-bf26caee-p147; SEG-bf26caee-p160; SEG-bf26caee-p161; SEG-bf26caee-p163; SEG-bf26caee-p164; SEG-bf26caee-p165; SEG-bf26caee-p166; SEG-bf26caee-p167; SEG-bf26caee-p168; SEG-bf26caee-p169; SEG-bf26caee-p170; SEG-bf26caee-p176; SEG-bf26caee-p180; SEG-bf26caee-p184; SEG-bf26caee-p188; SEG-bf26caee-p192; SEG-bf26caee-p196; SEG-bf26caee-p200; SEG-bf26caee-p204; SEG-bf26caee-p208; SEG-bf26caee-p212; SEG-bf26caee-p216; SEG-bf26caee-p220; SEG-bf26caee-p226; SEG-bf26caee-p227; SEG-bf26caee-p228; SEG-bf26caee-p229; SEG-bf26caee-p230; SEG-bf26caee-p231; SEG-bf26caee-p232; SEG-bf26caee-p233; SEG-bf26caee-p234; SEG-bf26caee-p237; SEG-bf26caee-p242; SEG-bf26caee-p247; SEG-bf26caee-p252; SEG-bf26caee-p257; SEG-bf26caee-p262; SEG-bf26caee-p267; SEG-bf26caee-p272; SEG-bf26caee-p277; SEG-bf26caee-p282; SEG-bf26caee-p289; SEG-bf26caee-p293; SEG-bf26caee-p297; SEG-bf26caee-p301; SEG-bf26caee-p305; SEG-bf26caee-p309; SEG-bf26caee-p313; SEG-bf26caee-p317; SEG-bf26caee-p321; SEG-bf26caee-p325; SEG-bf26caee-p329; SEG-bf26caee-p338; SEG-bf26caee-p342; SEG-bf26caee-p346; SEG-bf26caee-p350; SEG-bf26caee-p354; SEG-bf26caee-p358; SEG-bf26caee-p362; SEG-bf26caee-p366; SEG-bf26caee-p370; SEG-bf26caee-p374; SEG-bf26caee-p378; SEG-bf26caee-p382; SEG-bf26caee-p386; SEG-bf26caee-p390; SEG-bf26caee-p394; SEG-bf26caee-p398; SEG-bf26caee-p402; SEG-bf26caee-p407; SEG-bf26caee-p410; SEG-bf26caee-p481; SEG-bf26caee-p565; SEG-bf26caee-p648; SEG-bf26caee-p681; SEG-bf26caee-p756; SEG-bf26caee-p759; SEG-bf26caee-p762; SEG-bf26caee-p765; SEG-bf26caee-p768; SEG-bf26caee-p771; SEG-bf26caee-p787; SEG-bf26caee-p788; SEG-bf26caee-p789; SEG-bf26caee-p790; SEG-bf26caee-p791; SEG-bf26caee-p792,INV-007 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Configurações existentes, schema, biblioteca e auditoria. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. Continuidade 02/11/2026: DeskServiceEditor, histórico administrativo, versões imutáveis e validação comum dos pedidos do Balcão; configuração por interface demonstrada em QA isolada.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | 02/11/2026: editor local /management/balcao/servicos reutiliza desk_service_versions e competencias administrativas existentes; comparacao anterior/nova, campos/opcoes/condicoes, publicacao com motivo/base_version, idempotencia, conflito e auditoria. Pedidos submetidos e snapshots v1 conservados apos v2; validacao do campo novo no servidor. 18 Feature/325 assercoes iniciais e 1 teste frontend passaram; provas finais e limites no manual. Sem migracoes, instalacao ou prova visual; cobertura parcial dos tipos de checklist. Continuidade 02/11/2026: historico administrativo paginado das definicoes do Balcao, incluindo codigos retirados para consulta; sem respostas dos requerentes ou republicacao. Quatro Feature/91 assercoes e tres frontend aprovados; PHPStan, tipos e lint passaram. Provas no manual; visual e instalacao pendentes, requisito transversal parcial. [DESK-ANALYSIS-SCOPE-20261102] Verificações usam a versão e as perguntas aplicáveis: sem financiamento inexistente ou bloqueio por valores de ramos ocultos; diferenças financeiras aplicáveis continuam recusadas. Recibo distingue respostas conservadas e preserva rótulos da versão, original técnico e permissões. Publicação valida que a fonte da localização não fica indisponível quando a localização se aplica, reutilizando a exigência existente. 25 testes conjuntos/467 asserções e dois específicos/11 asserções aprovados; PHPStan e Pint passaram. Recibo desk_analysis_scope_increment_20261102 em local-validation-20261029.json; manual de 02/11. Sem instalação ou conferência visual; requisito transversal parcial.",Implementado parcialmente,"02/11/2026: editor local dos formulários do Balcão implementado com prévia, publicação versionada, histórico paginado e preservação dos pedidos anteriores. Restam conferência visual e disponibilização; a adaptação de outras checklists/contextos ainda não foi demonstrada. Não se declara parametrização transversal concluída. Histórico preservado: Checklists existem em configuração; editor/versionamento administrativo sem código e adaptação de submissões antigas não demonstrados.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Publicar versão autorizada, novas submissões usam-na e anteriores preservam a versão aplicada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Gestor autorizado configura/previsualiza/publica versão, investidor recebe versão aplicável ao contexto/data, guarda incompleto e recupera; nova versão não modifica submissão anterior nem trata decisão interna como licença.",P2,"Código INV-007 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p14; SEG-bf26caee-p15; SEG-bf26caee-p20; SEG-bf26caee-p23; SEG-bf26caee-p26; SEG-bf26caee-p29; SEG-bf26caee-p32; SEG-bf26caee-p35; SEG-bf26caee-p38; SEG-bf26caee-p41; SEG-bf26caee-p44; SEG-bf26caee-p47; SEG-bf26caee-p50; SEG-bf26caee-p53; SEG-bf26caee-p56; SEG-bf26caee-p59; SEG-bf26caee-p62; SEG-bf26caee-p65; SEG-bf26caee-p68; SEG-bf26caee-p71; SEG-bf26caee-p74; SEG-bf26caee-p77; SEG-bf26caee-p80; SEG-bf26caee-p83; SEG-bf26caee-p87; SEG-bf26caee-p104; SEG-bf26caee-p109; SEG-bf26caee-p114; SEG-bf26caee-p119; SEG-bf26caee-p124; SEG-bf26caee-p129; SEG-bf26caee-p134; SEG-bf26caee-p140; SEG-bf26caee-p144; SEG-bf26caee-p145; SEG-bf26caee-p146; SEG-bf26caee-p147; SEG-bf26caee-p160; SEG-bf26caee-p161; SEG-bf26caee-p163; SEG-bf26caee-p164; SEG-bf26caee-p165; SEG-bf26caee-p166; SEG-bf26caee-p167; SEG-bf26caee-p168; SEG-bf26caee-p169; SEG-bf26caee-p170; SEG-bf26caee-p176; SEG-bf26caee-p180; SEG-bf26caee-p184; SEG-bf26caee-p188; SEG-bf26caee-p192; SEG-bf26caee-p196; SEG-bf26caee-p200; SEG-bf26caee-p204; SEG-bf26caee-p208; SEG-bf26caee-p212; SEG-bf26caee-p216; SEG-bf26caee-p220; SEG-bf26caee-p226; SEG-bf26caee-p227; SEG-bf26caee-p228; SEG-bf26caee-p229; SEG-bf26caee-p230; SEG-bf26caee-p231; SEG-bf26caee-p232; SEG-bf26caee-p233; SEG-bf26caee-p234; SEG-bf26caee-p237; SEG-bf26caee-p242; SEG-bf26caee-p247; SEG-bf26caee-p252; SEG-bf26caee-p257; SEG-bf26caee-p262; SEG-bf26caee-p267; SEG-bf26caee-p272; SEG-bf26caee-p277; SEG-bf26caee-p282; SEG-bf26caee-p289; SEG-bf26caee-p293; SEG-bf26caee-p297; SEG-bf26caee-p301; SEG-bf26caee-p305; SEG-bf26caee-p309; SEG-bf26caee-p313; SEG-bf26caee-p317; SEG-bf26caee-p321; SEG-bf26caee-p325; SEG-bf26caee-p329; SEG-bf26caee-p338; SEG-bf26caee-p342; SEG-bf26caee-p346; SEG-bf26caee-p350; SEG-bf26caee-p354; SEG-bf26caee-p358; SEG-bf26caee-p362; SEG-bf26caee-p366; SEG-bf26caee-p370; SEG-bf26caee-p374; SEG-bf26caee-p378; SEG-bf26caee-p382; SEG-bf26caee-p386; SEG-bf26caee-p390; SEG-bf26caee-p394; SEG-bf26caee-p398; SEG-bf26caee-p402; SEG-bf26caee-p407; SEG-bf26caee-p410; SEG-bf26caee-p481; SEG-bf26caee-p565; SEG-bf26caee-p648; SEG-bf26caee-p681; SEG-bf26caee-p756; SEG-bf26caee-p759; SEG-bf26caee-p762; SEG-bf26caee-p765; SEG-bf26caee-p768; SEG-bf26caee-p771; SEG-bf26caee-p787; SEG-bf26caee-p788; SEG-bf26caee-p789; SEG-bf26caee-p790; SEG-bf26caee-p791; SEG-bf26caee-p792,124,"[{""id"": ""SEG-bf26caee-p14"", ""section"": ""1.0"", ""first_paragraph"": 14, ""last_paragraph"": 14, ""text"": ""O Código Comercial, aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio, constitui o enquadramento geral e transversal da actividade empresarial: define o objecto do regime comercial, a actividade empresarial, o empresário, a empresa, a capacidade empresarial e as obrigações comerciais. Este enquadramento aplica-se à organização e ao exercício da actividade empresarial, mas não substitui as exigências administrativas próprias de sectores regulados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p14"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p15"", ""section"": ""1.0"", ""first_paragraph"": 15, ""last_paragraph"": 15, ""text"": ""Os regimes sectoriais especiais aplicam-se cumulativamente quando a lei sujeita determinada actividade, operação, operador, localização ou instrumento a licença, autorização, registo regulatório, parecer, vistoria, comunicação ou supervisão. O Código Comercial disciplina o estatuto e a organização da actividade empresarial; não emite licença administrativa nem elimina requisitos sectoriais. Por sua vez, a licença sectorial habilita ou controla a actividade no âmbito do diploma especial, mas não substitui firma, registo comercial, escrituração, contas, actos societários e demais obrigações empresariais gerais que sejam aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p15"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p20"", ""section"": ""1.0.1"", ""first_paragraph"": 20, ""last_paragraph"": 22, ""text"": ""Artigo 1 | Objecto | Delimita a actividade empresarial, os sujeitos que a exercem e as relações jurídicas abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p20"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p23"", ""section"": ""1.0.1"", ""first_paragraph"": 23, ""last_paragraph"": 25, ""text"": ""Artigo 2 | Actividade empresarial | Qualifica a prática organizada de actos de produção ou circulação de bens ou prestação de serviços com finalidade lucrativa."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p23"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p26"", ""section"": ""1.0.1"", ""first_paragraph"": 26, ""last_paragraph"": 28, ""text"": ""Artigo 3 | Empresário | Distingue empresário individual e sociedade empresarial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p26"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p29"", ""section"": ""1.0.1"", ""first_paragraph"": 29, ""last_paragraph"": 31, ""text"": ""Artigo 4 | Noção de empresa | Enquadra a organização dos factores de produção e as actividades abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p29"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p32"", ""section"": ""1.0.1"", ""first_paragraph"": 32, ""last_paragraph"": 34, ""text"": ""Artigos 5 a 10 | Classificação da empresa, critérios especiais, prevalência e actualização | Exigem parametrização por finalidade, versão e vigência."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p32"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p35"", ""section"": ""1.0.1"", ""first_paragraph"": 35, ""last_paragraph"": 37, ""text"": ""Artigos 11 e 12 | Norma de conflitos e direito subsidiário | Orientam a lei aplicável e a integração de lacunas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p35"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p38"", ""section"": ""1.0.1"", ""first_paragraph"": 38, ""last_paragraph"": 40, ""text"": ""Artigos 13 a 18 | Capacidade empresarial e situações especiais | Suportam validações relativas à capacidade, cônjuges, menor e exercício por não empresário."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p38"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p41"", ""section"": ""1.0.1"", ""first_paragraph"": 41, ""last_paragraph"": 43, ""text"": ""Artigo 19 | Obrigações especiais do empresário | Consolida as obrigações de adoptar firma, escriturar em ordem uniforme as operações, inscrever os actos sujeitos a registo comercial e prestar contas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p41"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p44"", ""section"": ""1.0.1"", ""first_paragraph"": 44, ""last_paragraph"": 46, ""text"": ""Artigo 20 | Obrigatoriedade da firma | Exige nome empresarial no exercício da actividade e assinatura dos documentos correspondentes."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p44"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p47"", ""section"": ""1.0.1"", ""first_paragraph"": 47, ""last_paragraph"": 49, ""text"": ""Artigo 21 | Composição de firma | Define os elementos admissíveis na composição da firma."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p47"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p50"", ""section"": ""1.0.1"", ""first_paragraph"": 50, ""last_paragraph"": 52, ""text"": ""Artigo 22 | Princípio da verdade | Impede elementos falsos ou susceptíveis de induzir em erro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p50"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p53"", ""section"": ""1.0.1"", ""first_paragraph"": 53, ""last_paragraph"": 55, ""text"": ""Artigo 23 | Princípio da novidade | Exige distinção da firma relativamente às já registadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p53"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p56"", ""section"": ""1.0.1"", ""first_paragraph"": 56, ""last_paragraph"": 58, ""text"": ""Artigos 24 e 25 | Uso da língua oficial e outros requisitos da firma | Controlam a língua e requisitos adicionais da firma, conforme a versão oficial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p56"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p59"", ""section"": ""1.0.1"", ""first_paragraph"": 59, ""last_paragraph"": 61, ""text"": ""Artigo 26 | Uso exclusivo de firma | Vincula a exclusividade ao registo pelo titular."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p59"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p62"", ""section"": ""1.0.1"", ""first_paragraph"": 62, ""last_paragraph"": 64, ""text"": ""Artigo 27 | Uso ilegal de firma | Prevê proibição e responsabilidade decorrente do uso ilegal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p62"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p65"", ""section"": ""1.0.1"", ""first_paragraph"": 65, ""last_paragraph"": 67, ""text"": ""Artigo 28 | Transmissão de firma | Relaciona a transmissão da firma com a transmissão da empresa."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p65"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p68"", ""section"": ""1.0.1"", ""first_paragraph"": 68, ""last_paragraph"": 70, ""text"": ""Artigo 29 | Saída ou falecimento de sócio ou accionista | Regula os efeitos sobre a firma quando o nome conste da mesma."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p68"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p71"", ""section"": ""1.0.1"", ""first_paragraph"": 71, ""last_paragraph"": 73, ""text"": ""Artigo 30 | Anulação de firma | Regula a anulação por violação de direito de terceiro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p71"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p74"", ""section"": ""1.0.1"", ""first_paragraph"": 74, ""last_paragraph"": 76, ""text"": ""Artigo 31 | Caducidade da firma | Define causas de caducidade."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p74"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p77"", ""section"": ""1.0.1"", ""first_paragraph"": 77, ""last_paragraph"": 79, ""text"": ""Artigo 32 | Declaração de caducidade da firma | Define competência, contraditório, decisão e recurso."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p77"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p80"", ""section"": ""1.0.1"", ""first_paragraph"": 80, ""last_paragraph"": 82, ""text"": ""Artigo 33 | Renúncia à firma | Regula a declaração de renúncia perante a entidade competente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p80"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p83"", ""section"": ""1.0.1"", ""first_paragraph"": 83, ""last_paragraph"": 85, ""text"": ""Secções III a V do Capítulo II | Escrituração mercantil; registo comercial; balanço e prestação de contas | A estrutura está confirmada na fonte oficial; a numeração artigo a artigo permanece bloqueada no portal até conferência integral das páginas correspondentes da republicação oficial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p83"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p87"", ""section"": ""1.0.1"", ""first_paragraph"": 87, ""last_paragraph"": 87, ""text"": ""Fonte oficial e vigência: Decreto-Lei n.º 1/2022, de 25 de Maio, republicado no 3.º Suplemento ao Boletim da República, I Série, n.º 99, de 25 de Maio de 2022. A Imprensa Nacional de Moçambique regista que a publicação inicial ficou sem efeito e que o texto válido foi republicado no 3.º Suplemento. O diploma entrou em vigor 120 dias após a publicação, em 22 de Setembro de 2022. Consultar a publicação oficial da Imprensa Nacional de Moçambique. Para cada requisito do portal, deve ser citado o artigo específico da versão republicada e, quando exista, o diploma sectorial aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p87"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p104"", ""section"": ""1.0.2"", ""first_paragraph"": 104, ""last_paragraph"": 108, ""text"": ""Artigos 11 e 12 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Norma de conflitos e direito subsidiário | INV-001; INV-007; §§1.6, 3.2.2 e 6.5 | Regra aplicável documentada quando houver elemento estrangeiro, lacuna ou articulação com diploma especial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p104"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p109"", ""section"": ""1.0.2"", ""first_paragraph"": 109, ""last_paragraph"": 113, ""text"": ""Artigos 13 a 18 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Capacidade empresarial e situações especiais | INV-001; INV-007; SOC-001; §§3.1.1, 3.2.2 e 9.5 | Validações de capacidade e representação nos formulários e no comparador, sem decisão automática quando for necessária análise jurídica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p109"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p114"", ""section"": ""1.0.2"", ""first_paragraph"": 114, ""last_paragraph"": 118, ""text"": ""Artigo 19 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Obrigações especiais do empresário | INV-001; INV-002; INV-007; §§1.6, 3.2 e 6.1 | Checklist transversal que distingue firma, escrituração, registo e prestação de contas das licenças sectoriais."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p114"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p124"", ""section"": ""1.0.2"", ""first_paragraph"": 124, ""last_paragraph"": 128, ""text"": ""Secção III do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Escrituração mercantil | INV-002; INV-007; §§1.6, 6.1 e 7.3 | Requisito documental e de governação ligado à organização da actividade; a numeração artigo a artigo permanece dependente de conferência integral."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p124"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p129"", ""section"": ""1.0.2"", ""first_paragraph"": 129, ""last_paragraph"": 133, ""text"": ""Secção IV do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Registo comercial | INV-001; INV-002; INV-007; §§1.6, 1.8 e 6.1 | Formalidade de registo e publicidade tratada separadamente do licenciamento sectorial, com entidade, acto e competência territorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p129"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p134"", ""section"": ""1.0.2"", ""first_paragraph"": 134, ""last_paragraph"": 138, ""text"": ""Secção V do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Balanço e prestação de contas | INV-002; INV-007; §§1.6, 6.1 e 7.3 | Obrigação empresarial geral ligada ao checklist e à governação documental; não constitui autorização de actividade."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p134"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p140"", ""section"": ""1.0.2"", ""first_paragraph"": 140, ""last_paragraph"": 140, ""text"": ""Estas referências complementam os requisitos existentes e devem ser registadas na matriz de rastreabilidade. Não criam novas histórias, não alteram a numeração do backlog e não substituem os diplomas sectoriais aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p140"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p144"", ""section"": ""1.2"", ""first_paragraph"": 144, ""last_paragraph"": 144, ""text"": ""Converter a matriz de requisitos por fase num guia interactivo, passo a passo, em vez de a apresentar como prompt."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p144"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p145"", ""section"": ""1.2"", ""first_paragraph"": 145, ""last_paragraph"": 145, ""text"": ""Estruturar a jornada do investidor desde a concepção do projecto até à entrada em operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p145"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p146"", ""section"": ""1.2"", ""first_paragraph"": 146, ""last_paragraph"": 146, ""text"": ""Disponibilizar formulários nos pontos necessários e gerar documentos para preenchimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p146"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p147"", ""section"": ""1.2"", ""first_paragraph"": 147, ""last_paragraph"": 147, ""text"": ""Criar checklists por entidade, incluindo APIEX, INTIC, Banco de Moçambique e demais instituições licenciadoras."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p147"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p160"", ""section"": ""1.6"", ""first_paragraph"": 160, ""last_paragraph"": 160, ""text"": ""Criar checklists e, quando disponíveis, formulários para licenciamentos financeiros, sectoriais e de actividades económicas junto das entidades competentes."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p160"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p161"", ""section"": ""1.6"", ""first_paragraph"": 161, ""last_paragraph"": 161, ""text"": ""Os checklists devem ser organizados em três camadas independentes: (1) obrigações empresariais gerais do Código Comercial; (2) formalidades de registo e publicidade perante a entidade de registo competente; e (3) licenças, autorizações e controlos sectoriais especiais. A conclusão de uma camada não comprova automaticamente o cumprimento das outras. Por exemplo, o registo ou licenciamento pelo INTIC ao abrigo do Decreto n.º 59/2023 não substitui o cumprimento das obrigações comerciais gerais nem outros actos sectoriais aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p161"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p163"", ""section"": ""1.7"", ""first_paragraph"": 163, ""last_paragraph"": 163, ""text"": ""APIEX, I.P. — registo, aprovação e acompanhamento de projectos de investimento privado, segundo a competência e o fluxo confirmados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p163"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p164"", ""section"": ""1.7"", ""first_paragraph"": 164, ""last_paragraph"": 164, ""text"": ""Autoridade Tributária de Moçambique — NUIT, obrigações fiscais, benefícios fiscais e procedimentos aduaneiros aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p164"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p165"", ""section"": ""1.7"", ""first_paragraph"": 165, ""last_paragraph"": 165, ""text"": ""Banco de Moçambique — autorizações, registos e controlos aplicáveis a instituições financeiras, operações cambiais, entrada de capital, transferência de lucros, dividendos e desinvestimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p165"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p166"", ""section"": ""1.7"", ""first_paragraph"": 166, ""last_paragraph"": 166, ""text"": ""BAU, I.P. — facilitação de procedimentos de licenciamento de actividades económicas e encaminhamento para a entidade competente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p166"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p167"", ""section"": ""1.7"", ""first_paragraph"": 167, ""last_paragraph"": 167, ""text"": ""Instituto Nacional de Tecnologias de Informação e Comunicação, I.P. (INTIC, I.P.), na qualidade de Autoridade Reguladora de TIC — entidade competente para o registo e licenciamento de Provedores Intermediários de Serviços Electrónicos e de Operadores de Plataformas Digitais, nos termos do Decreto n.º 59/2023, de 27 de Outubro. O âmbito inclui certificado de registo, licença por classe ou licença unificada, alteração, transmissão, renovação, cancelamento, vistoria e fiscalização, conforme o processo aplicável. Outros serviços, pareceres, homologações ou autorizações só devem ser incluídos quando comprovados por diploma ou fonte oficial específica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p167"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p168"", ""section"": ""1.7"", ""first_paragraph"": 168, ""last_paragraph"": 168, ""text"": ""Bolsa de Valores de Moçambique — informação sobre mercados, instrumentos e percurso de admissão, mantendo separadas as competências da bolsa, da autoridade reguladora e dos intermediários legalmente autorizados. Cada requisito, documento ou decisão deve indicar a entidade competente e a respectiva fonte antes de ser publicado no portal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p168"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p169"", ""section"": ""1.7"", ""first_paragraph"": 169, ""last_paragraph"": 169, ""text"": ""Conservatória competente — constituição, registo e actos societários aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p169"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p170"", ""section"": ""1.7"", ""first_paragraph"": 170, ""last_paragraph"": 170, ""text"": ""Ministérios, institutos públicos, municípios e demais autoridades sectoriais — licenças, pareceres, inspecções e autorizações conforme a actividade, localização e diploma aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p170"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p176"", ""section"": ""1.8"", ""first_paragraph"": 176, ""last_paragraph"": 179, ""text"": ""Código Comercial — Decreto-Lei n.º 1/2022, de 25 de Maio | Enquadramento e obrigações empresariais gerais | Deveres e actos comerciais ou societários; não constitui licença sectorial | Publicação oficial da Imprensa Nacional; vigente desde 22 de Setembro de 2022."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p176"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p180"", ""section"": ""1.8"", ""first_paragraph"": 180, ""last_paragraph"": 183, ""text"": ""APIEX, I.P. | Promoção, facilitação e acompanhamento do investimento e das exportações, segundo o estatuto orgânico; tramitação dos projectos ao abrigo do regime de investimento privado | Acto exacto previsto na Lei de Investimento e no respectivo regulamento; não tratar registo, aprovação e certificado como equivalentes | Resolução n.º 43/2019 — Estatuto Orgânico da APIEX, I.P.; Lei n.º 8/2023, de 9 de Junho — Lei de Investimento Privado; Decreto n.º 8/2024, de 7 de Março — Regulamento da Lei de Investimento. Aplicar a redacção vigente e o acto exacto de cada fluxo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p180"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p184"", ""section"": ""1.8"", ""first_paragraph"": 184, ""last_paragraph"": 187, ""text"": ""Autoridade Tributária de Moçambique | Administração tributária e aduaneira, cadastro fiscal, declarações, liquidação, cobrança e fiscalização segundo cada imposto ou procedimento | NUIT, declaração, liquidação, comprovativo, decisão, benefício ou acto aduaneiro conforme o diploma aplicável | Portal oficial da Autoridade Tributária — impostos, legislação e procedimentos; serviço oficial de NUIT. A fonte legal deve ser ligada por imposto, benefício ou procedimento; o portal institucional não substitui o diploma específico."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p184"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p188"", ""section"": ""1.8"", ""first_paragraph"": 188, ""last_paragraph"": 191, ""text"": ""Banco de Moçambique — instituições financeiras | Autorização para constituição de instituições de crédito e sociedades financeiras | Autorização concedida caso a caso pelo Governador do Banco de Moçambique | Lei n.º 20/2020, de 31 de Dezembro, artigo 16, e informação oficial de licenciamento; Regulamento aprovado pelo Decreto n.º 50/2024, de 11 de Julho. Aplicar apenas às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p188"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p192"", ""section"": ""1.8"", ""first_paragraph"": 192, ""last_paragraph"": 195, ""text"": ""Banco de Moçambique — operações cambiais | Autorização, registo e controlo de operações cambiais | Autorização ou registo cambial conforme a operação, o sujeito e a redacção vigente | Informação oficial de licenciamento e controlo cambial; Lei n.º 28/2022, de 29 de Dezembro — Lei Cambial. Os avisos e procedimentos aplicáveis devem ser ligados por operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p192"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p196"", ""section"": ""1.8"", ""first_paragraph"": 196, ""last_paragraph"": 199, ""text"": ""BAU, I.P. | Licenciar e monitorar actividades económicas nos termos dos regulamentos aplicáveis; simplificar, harmonizar e operacionalizar serviços integrados | Licença, alvará, certidão de mera comunicação prévia, registo ou encaminhamento, conforme o regime da actividade | Decreto n.º 29/2023, de 24 de Maio — criação do BAU, I.P.; Resolução n.º 3/2024, de 9 de Abril — Estatuto Orgânico; legislação oficial do BAU. Cada checklist deve indicar o regulamento de licenciamento aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p196"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p200"", ""section"": ""1.8"", ""first_paragraph"": 200, ""last_paragraph"": 203, ""text"": ""INTIC, I.P. — competências reguladas | Registo e licenciamento de provedores intermediários de serviços electrónicos e operadores de plataformas digitais; vistoria e fiscalização | Certificado de registo; licença por classe ou unificada; gestão do certificado ou da licença | Decreto n.º 59/2023, com redacção vigente após o Decreto n.º 44/2025; aplicar apenas às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p200"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p204"", ""section"": ""1.8"", ""first_paragraph"": 204, ""last_paragraph"": 207, ""text"": ""INTIC, I.P. — atribuições adicionais | Pareceres, homologações, certificações ou autorizações fora do regime identificado | Nenhum resultado confirmado sem fonte própria | Sem fonte oficial específica ligada; não configurar competência ou acto até identificação do diploma aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p204"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p208"", ""section"": ""1.8"", ""first_paragraph"": 208, ""last_paragraph"": 211, ""text"": ""Registo de Entidades Legais | Registo e publicidade dos actos relativos a entidades legais | Inscrição, certidão, averbamento, publicação ou outro acto registal previsto | Decreto-Lei n.º 1/2024, de 8 de Março — Regulamento do Registo de Entidades Legais. A conservatória e a competência territorial devem coincidir com o processo aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p208"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p212"", ""section"": ""1.8"", ""first_paragraph"": 212, ""last_paragraph"": 215, ""text"": ""Bolsa de Valores de Moçambique — admissão à cotação | Instrução, tramitação e decisão dos pedidos de admissão à cotação, nos termos do regulamento da bolsa | Admissão à cotação, através de pedido patrocinado por operador de bolsa | Regulamento n.º 1/GPCABVM/2010, artigos 1 a 3, emitido ao abrigo do Código do Mercado de Valores Mobiliários, aprovado pelo Decreto-Lei n.º 4/2009."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p212"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p216"", ""section"": ""1.8"", ""first_paragraph"": 216, ""last_paragraph"": 219, ""text"": ""Banco de Moçambique — autoridade do mercado de valores mobiliários | Regulação e supervisão do mercado de valores mobiliários no âmbito das competências legais | Avisos, autorizações, supervisão e demais actos regulatórios aplicáveis | Aviso n.º 3/GBM/2026 e fonte oficial do Banco de Moçambique, emitido ao abrigo do artigo 4 do Código do Mercado de Valores Mobiliários. Distinguir da decisão de admissão praticada pela Bolsa e da intermediação exercida por operadores autorizados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p216"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p220"", ""section"": ""1.8"", ""first_paragraph"": 220, ""last_paragraph"": 223, ""text"": ""Outras autoridades sectoriais | Licenciamento, parecer, autorização, vistoria, comunicação ou supervisão conforme o sector | Título ou decisão sectorial | Fonte variável por sector; relacionar cada acto com diploma oficial, artigo, entidade, vigência, documentos e canal antes da configuração."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p220"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p226"", ""section"": ""1.8.1"", ""first_paragraph"": 226, ""last_paragraph"": 226, ""text"": ""Fonte legal vigente: Decreto n.º 59/2023, de 27 de Outubro — publicação oficial da Imprensa Nacional de Moçambique, que aprova o Regulamento de Registo e Licenciamento de Provedores Intermediários de Serviços Electrónicos e de Operadores de Plataformas Digitais, conjugado com as alterações introduzidas pelo Decreto n.º 44/2025, de 28 de Novembro — Boletim da República, I Série, n.º 229."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p226"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p227"", ""section"": ""1.8.1"", ""first_paragraph"": 227, ""last_paragraph"": 227, ""text"": ""Artigos 9 a 16 do Decreto n.º 59/2023: registo, certificado de registo, alteração, transmissão, renovação e cancelamento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p227"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p228"", ""section"": ""1.8.1"", ""first_paragraph"": 228, ""last_paragraph"": 228, ""text"": ""Artigo 17 do Decreto n.º 59/2023: competência da Autoridade Reguladora de TIC para conceder licença."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p228"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p229"", ""section"": ""1.8.1"", ""first_paragraph"": 229, ""last_paragraph"": 229, ""text"": ""Artigos 18 a 30 do Decreto n.º 59/2023: licenciamento, tipos de licença, pedido, requisitos, validade, alteração, transmissão, renovação e cancelamento, com leitura da redacção vigente após o Decreto n.º 44/2025."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p229"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p230"", ""section"": ""1.8.1"", ""first_paragraph"": 230, ""last_paragraph"": 230, ""text"": ""Artigo 31 do Decreto n.º 59/2023: organização e direcção da vistoria."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p230"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p231"", ""section"": ""1.8.1"", ""first_paragraph"": 231, ""last_paragraph"": 231, ""text"": ""Artigo 49 do Decreto n.º 59/2023: fiscalização das actividades abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p231"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p232"", ""section"": ""1.8.1"", ""first_paragraph"": 232, ""last_paragraph"": 232, ""text"": ""Glossário do Regulamento: a expressão “Autoridade Reguladora de TIC” refere-se ao Instituto Nacional de Tecnologias de Informação e Comunicação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p232"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p233"", ""section"": ""1.8.1"", ""first_paragraph"": 233, ""last_paragraph"": 233, ""text"": ""Decreto n.º 44/2025, artigos 1 e 2: altera o âmbito, o artigo 18, as taxas e o regime transitório e revoga disposições específicas do Decreto n.º 59/2023; os requisitos do portal devem usar a redacção vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p233"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p234"", ""section"": ""1.8.1"", ""first_paragraph"": 234, ""last_paragraph"": 234, ""text"": ""A prova legal confirma as competências do INTIC apenas no âmbito dos provedores intermediários de serviços electrónicos e operadores de plataformas digitais abrangidos pelo regulamento. Outras atribuições permanecem sem prova documental específica até à identificação de fonte própria."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p234"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p237"", ""section"": ""1.8.2"", ""first_paragraph"": 237, ""last_paragraph"": 241, ""text"": ""Entidade ou regime | Diploma e artigo confirmados | Competência ou acto comprovado | Fonte oficial verificável | Vigência e âmbito"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p237"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p242"", ""section"": ""1.8.2"", ""first_paragraph"": 242, ""last_paragraph"": 246, ""text"": ""Código Comercial | Decreto-Lei n.º 1/2022, de 25 de Maio; artigos 1 a 19 e 20 a 33; Título II, Capítulo II, Secções III a V | Enquadramento geral da actividade empresarial, empresário, empresa, capacidade, firma, obrigações especiais, escrituração, registo comercial e prestação de contas | Imprensa Nacional de Moçambique — Boletim da República n.º 99, 3.º Suplemento | Vigente desde 22 de Setembro de 2022; regime geral, não licença sectorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p242"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p247"", ""section"": ""1.8.2"", ""first_paragraph"": 247, ""last_paragraph"": 251, ""text"": ""APIEX, I.P. | Resolução n.º 43/2019; Lei n.º 8/2023, artigos 21 a 24; Decreto n.º 8/2024, artigos 2 e 3 do diploma aprovador | Base institucional; coordenação, recepção e tramitação de procedimentos de investimento; monitoria, acompanhamento e assistência aos projectos abrangidos | Resolução n.º 43/2019 — Imprensa Nacional; Lei n.º 8/2023 — Imprensa Nacional; Decreto n.º 8/2024 — Imprensa Nacional | Confirmado apenas no âmbito institucional e procedimental indicado; aplicar a redacção vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p247"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p252"", ""section"": ""1.8.2"", ""first_paragraph"": 252, ""last_paragraph"": 256, ""text"": ""Banco de Moçambique — instituições de crédito e sociedades financeiras | Lei n.º 20/2020, artigo 16; Decreto n.º 50/2024, artigos 1 a 4 e regime específico aplicável | Autorização, caso a caso, para constituição das instituições abrangidas; procedimentos gerais de instrução dos pedidos | Lei n.º 20/2020 — fonte oficial do Banco de Moçambique; Decreto n.º 50/2024 — fonte oficial do Banco de Moçambique; página oficial de licenciamento | Lei vigente desde a sua entrada em vigor; Regulamento publicado em 11 de Julho de 2024. Confirma constituição e procedimento geral, não todos os actos posteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p252"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p257"", ""section"": ""1.8.2"", ""first_paragraph"": 257, ""last_paragraph"": 261, ""text"": ""Banco de Moçambique — matéria cambial | Lei n.º 28/2022, artigos 8, 9, 11 e 27 a 30; Decreto n.º 56/2023, artigos 1 a 4 | Autoridade cambial, competência regulamentar, autorização, registo e controlo das operações abrangidas | Lei n.º 28/2022 — fonte oficial do Banco de Moçambique; Decreto n.º 56/2023 — fonte oficial do Banco de Moçambique | Aplicar a redacção vigente e o aviso ou procedimento específico de cada operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p257"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p262"", ""section"": ""1.8.2"", ""first_paragraph"": 262, ""last_paragraph"": 266, ""text"": ""BAU, I.P. | Decreto n.º 29/2023; Resolução n.º 3/2024; regulamentos sectoriais publicados no portal oficial | Criação, organização institucional, simplificação e disponibilização integrada de serviços; licenciamento ou encaminhamento apenas nos termos do regulamento da actividade | Decreto n.º 29/2023 — Imprensa Nacional; Resolução n.º 3/2024 — Imprensa Nacional; legislação oficial do BAU | Base institucional confirmada. O acto decisório depende do regulamento sectorial aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p262"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p267"", ""section"": ""1.8.2"", ""first_paragraph"": 267, ""last_paragraph"": 271, ""text"": ""INTIC, I.P. — Autoridade Reguladora de TIC | Decreto n.º 59/2023, artigos 9 a 16, 17, 18 a 31 e 49; Decreto n.º 44/2025, artigos 1 e 2 | Registo, licenciamento, gestão de certificados e licenças, vistoria e fiscalização de provedores intermediários de serviços electrónicos e operadores de plataformas digitais | Decreto n.º 59/2023 — Imprensa Nacional; Decreto n.º 44/2025 — Boletim da República | Usar a redacção vigente após a alteração de 2025; limitado às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p267"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p272"", ""section"": ""1.8.2"", ""first_paragraph"": 272, ""last_paragraph"": 276, ""text"": ""Registo de Entidades Legais | Decreto-Lei n.º 1/2024, artigo 1 do diploma aprovador; Regulamento, artigos 1, 2 e 11 a 18 | Registo e publicidade de actos relativos a entidades legais; organização dos serviços; identificação e declaração do beneficiário efectivo | Decreto-Lei n.º 1/2024 — Imprensa Nacional; texto do Regulamento — Tribunal Supremo | Vigente desde a data definida no diploma; actos individuais dependem do artigo próprio e da competência territorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p272"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p277"", ""section"": ""1.8.2"", ""first_paragraph"": 277, ""last_paragraph"": 281, ""text"": ""Bolsa de Valores de Moçambique — admissão à cotação | Código do Mercado de Valores Mobiliários, artigo 67, n.º 2; Regulamento n.º 1/GPCABVM/2010, artigos 1 a 3 | Instrução, tramitação e decisão dos pedidos de admissão; patrocínio por operador de bolsa; apresentação do requerimento | Regulamento n.º 1/GPCABVM/2010 — Bolsa de Valores de Moçambique; página oficial do processo de listagem | Confirmado para os artigos 1 a 3 e para o fundamento do artigo 67, n.º 2; demais requisitos dependem da versão regulamentar vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p277"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p282"", ""section"": ""1.8.2"", ""first_paragraph"": 282, ""last_paragraph"": 286, ""text"": ""Banco de Moçambique — mercado de valores mobiliários | Decreto-Lei n.º 4/2009, Código do Mercado de Valores Mobiliários, artigo 4 | Autoridade reguladora e supervisora do mercado, no âmbito das competências previstas no artigo 4 | Código do Mercado de Valores Mobiliários — fonte oficial do Banco de Moçambique | Competência-base confirmada; cada autorização, oferta, intermediário ou acto de supervisão exige norma específica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p282"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p289"", ""section"": ""1.8.3"", ""first_paragraph"": 289, ""last_paragraph"": 292, ""text"": ""Entidade | Competência, acto ou parâmetro pendente | Prova necessária | Estado"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p289"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p293"", ""section"": ""1.8.3"", ""first_paragraph"": 293, ""last_paragraph"": 296, ""text"": ""APIEX, I.P. | Limiar e decisor por valor do projecto; designação exacta de mero registo, autorização, aprovação, certificado, alteração, cessão e revogação | Artigo regulamentar vigente, formulário, acto emitido e fluxo aprovado por tipo e valor de projecto | Parcialmente confirmado; parcela pendente separada"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p293"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p297"", ""section"": ""1.8.3"", ""first_paragraph"": 297, ""last_paragraph"": 300, ""text"": ""Autoridade Tributária de Moçambique | Base legal individual de NUIT, IRPC, IVA, ISPC, benefícios, isenções, taxas, declarações, cobrança, fiscalização e actos aduaneiros usados pelo portal | Diploma oficial, artigo, taxa ou fórmula, vigência, entidade decisora, formulário e canal para cada regra | Sem prova específica por regra; os portais institucionais confirmam o canal, não o fundamento jurídico individual"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p297"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p301"", ""section"": ""1.8.3"", ""first_paragraph"": 301, ""last_paragraph"": 304, ""text"": ""Banco de Moçambique — instituições financeiras | Documentos, prazos, alteração, fusão, transmissão, sucursais, revogação e requisitos próprios de cada categoria | Artigo da Lei n.º 20/2020, do Decreto n.º 50/2024 ou aviso específico | Parcialmente confirmado; constituição confirmada"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p301"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p305"", ""section"": ""1.8.3"", ""first_paragraph"": 305, ""last_paragraph"": 308, ""text"": ""Banco de Moçambique — operações cambiais | Procedimento exacto para entrada de capital, empréstimo externo, transferência de lucros e dividendos, desinvestimento e contas no exterior | Artigo do regulamento ou aviso específico, formulário, prazo, documentos e canal | Parcialmente confirmado por operação"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p305"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p309"", ""section"": ""1.8.3"", ""first_paragraph"": 309, ""last_paragraph"": 312, ""text"": ""BAU, I.P. | Competência decisória e acto exacto por actividade: licença, alvará, certidão, mera comunicação, registo ou encaminhamento | Artigo do regulamento comercial, industrial, simplificado ou de mera comunicação aplicável à actividade | Base institucional confirmada; acto sectorial pendente por processo"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p309"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p313"", ""section"": ""1.8.3"", ""first_paragraph"": 313, ""last_paragraph"": 316, ""text"": ""INTIC, I.P. | Pareceres, homologações, certificações ou autorizações fora dos Decretos n.º 59/2023 e n.º 44/2025 | Diploma e artigo próprios | Sem prova específica fora do regime confirmado"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p313"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p317"", ""section"": ""1.8.3"", ""first_paragraph"": 317, ""last_paragraph"": 320, ""text"": ""Registo de Entidades Legais | Reserva de denominação, constituição, alteração, certidão, averbamento, publicação, cancelamento e emolumentos por acto | Artigo exacto do Decreto-Lei n.º 1/2024, tabela aplicável e conservatória territorialmente competente | Parcialmente confirmado; base e beneficiário efectivo confirmados"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p317"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p321"", ""section"": ""1.8.3"", ""first_paragraph"": 321, ""last_paragraph"": 324, ""text"": ""Bolsa de Valores de Moçambique | Requisitos por segmento, montantes mínimos, prospecto, documentos, prazos, taxas e decisão final além dos artigos 1 a 3 | Artigo da versão regulamentar vigente e acto complementar aplicável | Parcialmente confirmado; artigos 1 a 3 confirmados"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p321"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p325"", ""section"": ""1.8.3"", ""first_paragraph"": 325, ""last_paragraph"": 328, ""text"": ""Banco de Moçambique — mercado de valores mobiliários | Autorizações, ofertas, intermediários e actos de supervisão específicos | Artigo do Código do Mercado de Valores Mobiliários e aviso ou regulamento aplicável | Competência-base confirmada; actos específicos pendentes"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p325"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p329"", ""section"": ""1.8.3"", ""first_paragraph"": 329, ""last_paragraph"": 332, ""text"": ""Outras autoridades sectoriais | Todas as competências ainda não individualizadas | Diploma, artigo, fonte oficial, vigência, entidade decisora, documentos, prazo, canal e resultado | Sem prova específica"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p329"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p338"", ""section"": ""1.8.4"", ""first_paragraph"": 338, ""last_paragraph"": 341, ""text"": ""Decreto-Lei n.º 1/2022 — Código Comercial | Referência oficial da Imprensa Nacional preservada. Estado: acesso técnico à referência pendente, porque a pesquisa directa redireccionou para o portal geral. | Não foi localizada revogação posterior na pesquisa documental registada. | Usar a versão republicada no 3.º Suplemento ao Boletim da República, I Série, n.º 99, e a data de entrada em vigor já aceite. A pendência técnica do link não reabre a aceitação da fonte."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p338"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p342"", ""section"": ""1.8.4"", ""first_paragraph"": 342, ""last_paragraph"": 345, ""text"": ""Resolução n.º 43/2019 — Estatuto Orgânico da APIEX, I.P. | Acesso oficial confirmado na Imprensa Nacional. | Foi localizada rectificação de 13 de Abril de 2020; não foi localizada revogação posterior. | Aplicar a Resolução com a rectificação incorporada."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p342"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p346"", ""section"": ""1.8.4"", ""first_paragraph"": 346, ""last_paragraph"": 349, ""text"": ""Lei n.º 8/2023 — Lei de Investimento Privado | Acesso oficial confirmado na Imprensa Nacional. | Não foi localizada revogação posterior na pesquisa documental registada. | Aplicar conjuntamente com o Decreto n.º 8/2024 e com alterações posteriores que venham a ser identificadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p346"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p350"", ""section"": ""1.8.4"", ""first_paragraph"": 350, ""last_paragraph"": 353, ""text"": ""Decreto n.º 8/2024 — Regulamento da Lei de Investimento | Acesso oficial confirmado na Imprensa Nacional. | O diploma revoga os Decretos n.º 43/2009 e n.º 20/2021; não foi localizada revogação posterior do Decreto n.º 8/2024. | Usar como referência regulamentar dos fluxos abrangidos, confirmando o artigo específico de cada procedimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p350"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p354"", ""section"": ""1.8.4"", ""first_paragraph"": 354, ""last_paragraph"": 357, ""text"": ""Lei n.º 20/2020 — Instituições de Crédito e Sociedades Financeiras | Acesso oficial confirmado no Banco de Moçambique. | Não foi localizada revogação posterior na pesquisa documental registada. | Aplicar o artigo 16 e as demais disposições relevantes em conjunto com o Decreto n.º 50/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p354"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p358"", ""section"": ""1.8.4"", ""first_paragraph"": 358, ""last_paragraph"": 361, ""text"": ""Decreto n.º 50/2024 — Regulamento da Lei n.º 20/2020 | Acesso oficial confirmado no Banco de Moçambique. | Revoga os Decretos n.º 56/2004, 57/2004, 31/2006, 30/2014 e 99/2019 e normas contrárias; não foi localizada revogação posterior. | Usar este regulamento nos procedimentos abrangidos e não os diplomas revogados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p358"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p362"", ""section"": ""1.8.4"", ""first_paragraph"": 362, ""last_paragraph"": 365, ""text"": ""Página oficial de licenciamento de instituições | Acesso institucional confirmado no Banco de Moçambique. | Conteúdo institucional activo; a página, por si só, não demonstra vigência normativa. | Usar como canal e apoio de navegação; fundamentar cada regra na Lei n.º 20/2020 e no Decreto n.º 50/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p362"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p366"", ""section"": ""1.8.4"", ""first_paragraph"": 366, ""last_paragraph"": 369, ""text"": ""Lei n.º 28/2022 — Lei Cambial | Acesso oficial confirmado no Banco de Moçambique. | Revoga a Lei n.º 11/2009; não foi localizada revogação posterior. | Aplicar em conjunto com o Decreto n.º 56/2023 e com o aviso específico de cada operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p366"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p370"", ""section"": ""1.8.4"", ""first_paragraph"": 370, ""last_paragraph"": 373, ""text"": ""Decreto n.º 56/2023 — Regulamento da Lei Cambial | Acesso oficial confirmado no Banco de Moçambique. | Revoga o Decreto n.º 49/2017; não foi localizada revogação posterior. | Aplicar a redacção do regulamento juntamente com os avisos vigentes por operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p370"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p374"", ""section"": ""1.8.4"", ""first_paragraph"": 374, ""last_paragraph"": 377, ""text"": ""Decreto n.º 29/2023 — criação do BAU, I.P. | Acesso oficial confirmado na Imprensa Nacional. | Revoga parcialmente o Decreto n.º 14/2007 quanto ao estatuto anterior dos BAU; não foi localizada revogação posterior. | Usar como base de criação; as competências e actos dependem do Estatuto e dos regulamentos sectoriais."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p374"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p378"", ""section"": ""1.8.4"", ""first_paragraph"": 378, ""last_paragraph"": 381, ""text"": ""Resolução n.º 3/2024 — Estatuto Orgânico do BAU, I.P. | Referência oficial identificada na Imprensa Nacional. Estado: acesso técnico à referência pendente para conferência integral dos artigos. | Não foi localizada revogação posterior na pesquisa documental registada. | Preservar a aceitação do documento oficial; não automatizar competências sem conferir o artigo aplicável no texto integral."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p378"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p382"", ""section"": ""1.8.4"", ""first_paragraph"": 382, ""last_paragraph"": 385, ""text"": ""Portal de legislação do BAU | Referência institucional preservada. Estado: acesso técnico à referência pendente na pesquisa autónoma. | O portal é conteúdo variável e não constitui, por si só, pesquisa conclusiva de revogações. | Usar como índice documental; fundamentar cada regra no diploma e artigo específicos."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p382"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p386"", ""section"": ""1.8.4"", ""first_paragraph"": 386, ""last_paragraph"": 389, ""text"": ""Decreto n.º 59/2023 — licenciamento de plataformas digitais | Acesso oficial confirmado na Imprensa Nacional. | Foi localizada alteração pelo Decreto n.º 44/2025. | Aplicar apenas a redacção resultante das alterações e revogações introduzidas em 2025."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p386"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p390"", ""section"": ""1.8.4"", ""first_paragraph"": 390, ""last_paragraph"": 393, ""text"": ""Decreto n.º 44/2025 — alteração do Decreto n.º 59/2023 | Referência oficial preservada no domínio do INTIC. Estado: acesso técnico à referência pendente no índice de pesquisa. | O documento oficial de 2025 altera e revoga disposições do Decreto n.º 59/2023; não foi localizada alteração posterior. | Preservar a aceitação do Boletim da República n.º 229 e aplicar as alterações de 2025. A pendência técnica do URL não reabre a validação documental."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p390"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p394"", ""section"": ""1.8.4"", ""first_paragraph"": 394, ""last_paragraph"": 397, ""text"": ""Decreto-Lei n.º 1/2024 — Registo de Entidades Legais | Acesso oficial confirmado na Imprensa Nacional; cópia institucional do Tribunal Supremo. | Revoga o Decreto n.º 1/2006, excepto o artigo 1 que cria o Registo de Entidades Legais; não foi localizada revogação posterior. | Usar a Imprensa Nacional como fonte primária e a cópia do Tribunal Supremo como acesso complementar."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p394"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p398"", ""section"": ""1.8.4"", ""first_paragraph"": 398, ""last_paragraph"": 401, ""text"": ""Regulamento n.º 1/GPCABVM/2010 — admissão à cotação | Acesso oficial confirmado no domínio da Bolsa de Valores de Moçambique. | Não foi localizada revogação integral; permanecem por confirmar alterações ou regulamentos posteriores por segmento e matéria. | Aplicar os artigos confirmados e conferir a versão regulamentar específica antes de automatizar requisitos posteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p398"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p402"", ""section"": ""1.8.4"", ""first_paragraph"": 402, ""last_paragraph"": 405, ""text"": ""Decreto-Lei n.º 4/2009 — Código do Mercado de Valores Mobiliários | Acesso oficial confirmado no Banco de Moçambique. | Não foi localizada revogação integral; alterações posteriores devem ser pesquisadas por artigo. | Usar o artigo aplicável com a redacção confirmada para a regra concreta, sem inferir vigência integral apenas pelo acesso ao ficheiro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p402"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p407"", ""section"": ""1.8.4"", ""first_paragraph"": 407, ""last_paragraph"": 407, ""text"": ""Critério de validação: os resultados devem ser registados separadamente em três dimensões: (1) acesso à fonte, que confirma apenas a disponibilidade técnica da referência; (2) pesquisa de alterações ou revogações, que regista o que foi ou não localizado no período de verificação; e (3) redacção aplicável à regra, que identifica o texto normativo que deve fundamentar o requisito. Um link acessível não demonstra, por si só, vigência. Quando uma ligação não for recuperada tecnicamente, o estado deve ser “acesso técnico à referência pendente”, preservando a aceitação do documento oficial e sem reabrir validações já concluídas. Esta classificação não substitui consolidação legislativa oficial nem conferência jurídica artigo a artigo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p407"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p410"", ""section"": ""1.8.4"", ""first_paragraph"": 410, ""last_paragraph"": 410, ""text"": ""O procedimento é uniforme para todas as entidades: a matriz de competências confirmadas contém apenas referências sustentadas por diploma e artigo identificados; a matriz de pendências contém, separadamente, os actos, parâmetros e procedimentos que ainda exigem prova específica. Nenhuma referência parcial deve ser promovida a regra automática antes da identificação da fonte oficial, vigência, entidade decisora e resultado aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p410"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p481"", ""section"": ""3.2.2"", ""first_paragraph"": 481, ""last_paragraph"": 481, ""text"": ""Os formulários devem suportar campos de texto, números, datas, listas, selecção múltipla, localização, anexos e declarações de consentimento. Cada formulário deve possuir versão, período de vigência, regras condicionais, campos obrigatórios, limites de ficheiro, validação de formato, mensagens de erro, gravação automática, recuperação de rascunho e associação ao requisito correspondente. Alterações publicadas não devem modificar retroactivamente submissões já efectuadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-25""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p481"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p565"", ""section"": ""4.4"", ""first_paragraph"": 565, ""last_paragraph"": 565, ""text"": ""O modelo deve incluir organizações, utilizadores, papéis, permissões, entidades públicas, localizações administrativas, sectores económicos, actividades, formulários, campos, versões, checklists, itens, submissões, evidências, tarefas, notificações, consentimentos, fontes, importações, conflitos de correspondência e eventos de auditoria. As classificações e regras devem possuir vigência temporal para permitir reproduzir uma decisão ou simulação com os dados aplicáveis à data."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OPS-03"", ""AUD-PROFILE-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p565"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p648"", ""section"": ""6"", ""first_paragraph"": 648, ""last_paragraph"": 653, ""text"": ""INV-007 | Configurar checklists e formulários sem alteração de código | Sim | Parcial | QA | Demonstrar editor, publicação de versões e preservação de submissões anteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p648"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p681"", ""section"": ""6.1"", ""first_paragraph"": 681, ""last_paragraph"": 687, ""text"": ""§1.2; §1.6–1.8 | Checklists e formulários por entidade competente | INV-007 e INV-009 | Sim | Sem demonstração suficiente por entidade | — | Demonstrar checklist, formulário, base legal, responsável, versão, canal e resultado por entidade, sem reabrir fontes oficiais já aceites."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p681"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p756"", ""section"": ""6.2"", ""first_paragraph"": 756, ""last_paragraph"": 758, ""text"": ""Entidade | Designação canónica e aliases documentados | Preservar designações e fontes já aceites; divergências novas são relacionadas com a correspondência documental em falta."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p756"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p759"", ""section"": ""6.2"", ""first_paragraph"": 759, ""last_paragraph"": 761, ""text"": ""Autorização ou acto | Registo, aprovação, licença, autorização, parecer, comunicação, vistoria, certificado, benefício ou decisão | Não usar os termos como equivalentes; cada acto mantém entidade competente, base, vigência e resultado."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p759"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p762"", ""section"": ""6.2"", ""first_paragraph"": 762, ""last_paragraph"": 764, ""text"": ""Categoria, modalidade e objectivo | Categorias, códigos e versões dos contratos existentes; agrupamentos funcionais do update | O agrupamento funcional não substitui a taxonomia canónica. Mapear sem renumerar, fundir ou converter automaticamente registos, incluindo imobiliário, fundiário e franquia."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p762"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p765"", ""section"": ""6.2"", ""first_paragraph"": 765, ""last_paragraph"": 767, ""text"": ""Acção e autorização | Preparação privada, submissão, encaminhamento restrito e publicação pública | Aplicar a autorização à acção correspondente. A falta de autorização de divulgação impede a publicação pública, não a preparação privada ou o pedido de apoio permitido."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p765"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p768"", ""section"": ""6.2"", ""first_paragraph"": 768, ""last_paragraph"": 770, ""text"": ""Ambiente | QA, Ativo, Ativo e QA ou — | QA não equivale a Ativo; “Ativo e QA” distingue capacidade instalada de evolução ainda em homologação; — indica ausência de demonstração suficiente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p768"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p771"", ""section"": ""6.2"", ""first_paragraph"": 771, ""last_paragraph"": 773, ""text"": ""Evidência | Documento, ecrã, teste, registo, resposta institucional ou ligação operacional | “Sem demonstração suficiente” não significa ausência de código; significa evidência insuficiente para conclusão."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p771"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p787"", ""section"": ""6.3.1"", ""first_paragraph"": 787, ""last_paragraph"": 787, ""text"": ""As designações institucionais já confirmadas devem ser preservadas. Permanecem sujeitos a prova específica apenas os actos, artigos, limites, procedimentos ou competências assinalados nas secções 1.8.2 e 1.8.3."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p787"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p788"", ""section"": ""6.3.1"", ""first_paragraph"": 788, ""last_paragraph"": 788, ""text"": ""APIEX, I.P.: a designação canónica “Agência para a Promoção de Investimento e Exportações, I.P.” está confirmada pela Resolução n.º 43/2019. Permanecem sujeitos a confirmação por fluxo o acto exacto, o artigo aplicável e o resultado emitido nos termos da Lei n.º 8/2023 e do Decreto n.º 8/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p788"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p789"", ""section"": ""6.3.1"", ""first_paragraph"": 789, ""last_paragraph"": 789, ""text"": ""BAU, I.P.: a designação “Balcões de Atendimento Único, Instituto Público — BAU, I.P.” e as competências institucionais estão confirmadas pelo Decreto n.º 29/2023 e pela Resolução n.º 3/2024. O acto exacto — licença, alvará, certidão, registo, comunicação ou encaminhamento — deve ser confirmado no regulamento da actividade correspondente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p789"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p790"", ""section"": ""6.3.1"", ""first_paragraph"": 790, ""last_paragraph"": 790, ""text"": ""INTIC, I.P.: a designação e a competência como Autoridade Reguladora de TIC para o registo e licenciamento abrangidos pelo Decreto n.º 59/2023 estão confirmadas. Permanecem sem prova documental específica apenas os serviços, pareceres, homologações, certificações ou autorizações fora desse âmbito."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p790"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p791"", ""section"": ""6.3.1"", ""first_paragraph"": 791, ""last_paragraph"": 791, ""text"": ""Registo de Entidades Legais: a base nacional e a designação do regime estão confirmadas pelo Decreto-Lei n.º 1/2024. A conservatória territorialmente competente e o artigo aplicável a cada acto — reserva, constituição, alteração, certidão, averbamento, publicação ou cancelamento — devem ser confirmados por processo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p791"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p792"", ""section"": ""6.3.1"", ""first_paragraph"": 792, ""last_paragraph"": 792, ""text"": ""Enquanto faltar identificar a correspondência documental, o checklist deve conservar a designação encontrada como variante, registar o documento de origem e impedir apenas a sua promoção automática a valor canónico. Esta regra não reabre fontes oficiais, nomenclaturas ou validações já aceites."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p792"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",parcial,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. [BVM-ADMISSION-20261103] Guião /guias-investimento/bolsa implementado no mecanismo InvestmentGuides já entregue: cinco percursos (acções/obrigações MCO e Segundo; acções Terceiro), seis etapas/intervenientes, requisitos e dispensas com artigo/redacção/página por item, documentação comum uma vez e específica por percurso. Sete fontes PDF preservadas por hash, seis novas e Código Comercial republicado já aceite reutilizado; leitura textual e visual dos pontos críticos. Regime de2021 do Terceiro substitui referências de2019; montantes anuais e encargos actuais ficam indeterminados, sem reaplicar mínimos expirados em31/03/2025. Referência privada usa dossier/histórico cifrado e edição/contexto existentes; dois guias no mesmo dossier não misturam revisões/replay/paginação. 14 Feature/474 asserções e18 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo bvm_admission_increment_20261103. Encaminhamento é consulta dos canais oficiais, sem envio, oferta, registo, negociação ou admissão simulados.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Guião por segmento, documentos, condições e fonte aplicável ainda não demonstrado. Não inferir valores, prazos, prospectos, taxas ou aprovação pelos artigos1–3.",Identificar fontes/dados/âmbito/período concretos; não reabrir aceitação oficial.,Reutilizar guia/biblioteca/dossier/checklists. Relacionar pedido de admissão e patrocínio às referências específicas; separar ação interna do portal e ato de entidade competente.,Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,16–32 h após correspondências normativas; não preencher taxas/prazos ausentes.,,,
+AUD-CHECKLIST-01,"Editor de checklists e formulários configuráveis, publicação de versões e preservação de submissões anteriores",[Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] Alias documental INV-007; SEG-bf26caee-p14; SEG-bf26caee-p15; SEG-bf26caee-p20; SEG-bf26caee-p23; SEG-bf26caee-p26; SEG-bf26caee-p29; SEG-bf26caee-p32; SEG-bf26caee-p35; SEG-bf26caee-p38; SEG-bf26caee-p41; SEG-bf26caee-p44; SEG-bf26caee-p47; SEG-bf26caee-p50; SEG-bf26caee-p53; SEG-bf26caee-p56; SEG-bf26caee-p59; SEG-bf26caee-p62; SEG-bf26caee-p65; SEG-bf26caee-p68; SEG-bf26caee-p71; SEG-bf26caee-p74; SEG-bf26caee-p77; SEG-bf26caee-p80; SEG-bf26caee-p83; SEG-bf26caee-p87; SEG-bf26caee-p104; SEG-bf26caee-p109; SEG-bf26caee-p114; SEG-bf26caee-p119; SEG-bf26caee-p124; SEG-bf26caee-p129; SEG-bf26caee-p134; SEG-bf26caee-p140; SEG-bf26caee-p144; SEG-bf26caee-p145; SEG-bf26caee-p146; SEG-bf26caee-p147; SEG-bf26caee-p160; SEG-bf26caee-p161; SEG-bf26caee-p163; SEG-bf26caee-p164; SEG-bf26caee-p165; SEG-bf26caee-p166; SEG-bf26caee-p167; SEG-bf26caee-p168; SEG-bf26caee-p169; SEG-bf26caee-p170; SEG-bf26caee-p176; SEG-bf26caee-p180; SEG-bf26caee-p184; SEG-bf26caee-p188; SEG-bf26caee-p192; SEG-bf26caee-p196; SEG-bf26caee-p200; SEG-bf26caee-p204; SEG-bf26caee-p208; SEG-bf26caee-p212; SEG-bf26caee-p216; SEG-bf26caee-p220; SEG-bf26caee-p226; SEG-bf26caee-p227; SEG-bf26caee-p228; SEG-bf26caee-p229; SEG-bf26caee-p230; SEG-bf26caee-p231; SEG-bf26caee-p232; SEG-bf26caee-p233; SEG-bf26caee-p234; SEG-bf26caee-p237; SEG-bf26caee-p242; SEG-bf26caee-p247; SEG-bf26caee-p252; SEG-bf26caee-p257; SEG-bf26caee-p262; SEG-bf26caee-p267; SEG-bf26caee-p272; SEG-bf26caee-p277; SEG-bf26caee-p282; SEG-bf26caee-p289; SEG-bf26caee-p293; SEG-bf26caee-p297; SEG-bf26caee-p301; SEG-bf26caee-p305; SEG-bf26caee-p309; SEG-bf26caee-p313; SEG-bf26caee-p317; SEG-bf26caee-p321; SEG-bf26caee-p325; SEG-bf26caee-p329; SEG-bf26caee-p338; SEG-bf26caee-p342; SEG-bf26caee-p346; SEG-bf26caee-p350; SEG-bf26caee-p354; SEG-bf26caee-p358; SEG-bf26caee-p362; SEG-bf26caee-p366; SEG-bf26caee-p370; SEG-bf26caee-p374; SEG-bf26caee-p378; SEG-bf26caee-p382; SEG-bf26caee-p386; SEG-bf26caee-p390; SEG-bf26caee-p394; SEG-bf26caee-p398; SEG-bf26caee-p402; SEG-bf26caee-p407; SEG-bf26caee-p410; SEG-bf26caee-p481; SEG-bf26caee-p565; SEG-bf26caee-p648; SEG-bf26caee-p681; SEG-bf26caee-p756; SEG-bf26caee-p759; SEG-bf26caee-p762; SEG-bf26caee-p765; SEG-bf26caee-p768; SEG-bf26caee-p771; SEG-bf26caee-p787; SEG-bf26caee-p788; SEG-bf26caee-p789; SEG-bf26caee-p790; SEG-bf26caee-p791; SEG-bf26caee-p792,INV-007 / incremento posterior ao workflow das seis categorias,"Consumidor específico ainda por delimitar; reutilizar rotas de biblioteca/Balcão/negócios/simulador pertinentes, sem atribuir existência fictícia.","Configurações existentes, schema, biblioteca e auditoria. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. Continuidade 02/11/2026: DeskServiceEditor, histórico administrativo, versões imutáveis e validação comum dos pedidos do Balcão; configuração por interface demonstrada em QA isolada. [DESK-EFFECTIVE-DATES-20261102] Editor do Balcão permite entrada em vigor por data; catálogo/dossier/percurso e criação de pedidos reutilizam DeskServiceAvailability. Apenas datas já atingidas, a mais recente e maior versão na mesma data; legados sem data permanecem fallback, sem reescrita. Edições futuras visíveis na gestão; pedidos antigos/repetições mantêm FK, respostas e snapshots. Corrigida duplicação na publicação inicial por ordem de chaves JSONB; comparação canónica reutilizada. 21 Feature/314 asserções e nove frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo desk_effective_dates_increment_20261102. Parcial: outros contextos, visual e destino pendentes; sem alteração no activo. [DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo. [DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa. [DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa. [DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.","segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | 02/11/2026: editor local /management/balcao/servicos reutiliza desk_service_versions e competencias administrativas existentes; comparacao anterior/nova, campos/opcoes/condicoes, publicacao com motivo/base_version, idempotencia, conflito e auditoria. Pedidos submetidos e snapshots v1 conservados apos v2; validacao do campo novo no servidor. 18 Feature/325 assercoes iniciais e 1 teste frontend passaram; provas finais e limites no manual. Sem migracoes, instalacao ou prova visual; cobertura parcial dos tipos de checklist. Continuidade 02/11/2026: historico administrativo paginado das definicoes do Balcao, incluindo codigos retirados para consulta; sem respostas dos requerentes ou republicacao. Quatro Feature/91 assercoes e tres frontend aprovados; PHPStan, tipos e lint passaram. Provas no manual; visual e instalacao pendentes, requisito transversal parcial. [DESK-ANALYSIS-SCOPE-20261102] Verificações usam a versão e as perguntas aplicáveis: sem financiamento inexistente ou bloqueio por valores de ramos ocultos; diferenças financeiras aplicáveis continuam recusadas. Recibo distingue respostas conservadas e preserva rótulos da versão, original técnico e permissões. Publicação valida que a fonte da localização não fica indisponível quando a localização se aplica, reutilizando a exigência existente. 25 testes conjuntos/467 asserções e dois específicos/11 asserções aprovados; PHPStan e Pint passaram. Recibo desk_analysis_scope_increment_20261102 em local-validation-20261029.json; manual de 02/11. Sem instalação ou conferência visual; requisito transversal parcial. [DESK-EFFECTIVE-DATES-20261102] Editor do Balcão permite entrada em vigor por data; catálogo/dossier/percurso e criação de pedidos reutilizam DeskServiceAvailability. Apenas datas já atingidas, a mais recente e maior versão na mesma data; legados sem data permanecem fallback, sem reescrita. Edições futuras visíveis na gestão; pedidos antigos/repetições mantêm FK, respostas e snapshots. Corrigida duplicação na publicação inicial por ordem de chaves JSONB; comparação canónica reutilizada. 21 Feature/314 asserções e nove frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo desk_effective_dates_increment_20261102. Parcial: outros contextos, visual e destino pendentes; sem alteração no activo. [DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo. [DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa. [DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa. [DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa.","Implementado parcialmente","03/11/2026: selector geral do dossier, anexos por pergunta e suporte da etapa já não exigem UUID manual. Catálogo entre dossiers corresponde à autoridade existente, sem alargar o acesso a fontes de outras organizações. Continuam pendentes outros consumidores/formulários e a parametrização transversal de limites/formatos/mensagens, camadas de obrigações/registo/licenciamento por fonte/âmbito, conferência visual/login real e disponibilização no destino. Não é parametrização integral, homologação ou aceitação real. Histórico anterior: 03/11/2026: Balcão tem editor/histórico/vigência, tipos múltiplos/declarações/anexos, recuperação automática e limites de ficheiro por pergunta demonstrados localmente. Restam outros consumidores/contextos p481, limites/formatos/mensagens parametrizados transversalmente, catálogo/selector legado geral e reutilização entre dossiers sem UUID manual, camadas de obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização/migração no destino. Os quatro MIME e tectos técnicos existentes (10MiB/100 ficheiros por dossier) não são parametrização integral da aplicação. Não é homologação, aprovação documental ou aceitação real. Histórico preservado: 03/11/2026: Balcão tem editor/histórico/vigência/tipos múltiplos/declarações e gravação automática/recuperação privada demonstrados em QA. Restam outros consumidores/contextos de checklist e respectivos critérios p481, configuração transversal de limites/anexos/formatos/mensagens, camadas de obrigações gerais/registo/licenciamento por fonte e âmbito, observação visual/login real e disponibilização/migração no destino. Não é homologação nem parametrização integral. Histórico preservado: 03/11/2026: editor, histórico, vigência, selecção múltipla e declarações de consentimento do Balcão implementados/ensaiados localmente. Restam outros consumidores/contextos de checklist, cobertura transversal dos tipos/regras/limites/anexos, autosave/recuperação nos contextos ainda não demonstrados, três camadas de obrigações/registo/licenciamento por fonte e âmbito, visual/login real e disponibilização. Não equivale a homologação, licença ou parametrização integral. Histórico preservado: 02/11/2026: editor local do Balcão, histórico e publicação por data com recuperação da edição aplicável implementados e ensaiados. Restam extensão a outras checklists/contextos, observação visual e disponibilização no destino; não é parametrização integral nem formulário oficial homologado. Histórico: 02/11/2026: editor local dos formulários do Balcão implementado com prévia, publicação versionada, histórico paginado e preservação dos pedidos anteriores. Restam conferência visual e disponibilização; a adaptação de outras checklists/contextos ainda não foi demonstrada. Não se declara parametrização transversal concluída. Histórico preservado: Checklists existem em configuração; editor/versionamento administrativo sem código e adaptação de submissões antigas não demonstrados.","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Publicar versão autorizada, novas submissões usam-na e anteriores preservam a versão aplicada. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","Gestor autorizado configura/previsualiza/publica versão, investidor recebe versão aplicável ao contexto/data, guarda incompleto e recupera; nova versão não modifica submissão anterior nem trata decisão interna como licença.",P2,"Código INV-007 é alias deste documento, não renumeração do roteiro/backlog. Conteúdo/regras pendentes não se tornam aprovados pela importação.",SEG-bf26caee-p14; SEG-bf26caee-p15; SEG-bf26caee-p20; SEG-bf26caee-p23; SEG-bf26caee-p26; SEG-bf26caee-p29; SEG-bf26caee-p32; SEG-bf26caee-p35; SEG-bf26caee-p38; SEG-bf26caee-p41; SEG-bf26caee-p44; SEG-bf26caee-p47; SEG-bf26caee-p50; SEG-bf26caee-p53; SEG-bf26caee-p56; SEG-bf26caee-p59; SEG-bf26caee-p62; SEG-bf26caee-p65; SEG-bf26caee-p68; SEG-bf26caee-p71; SEG-bf26caee-p74; SEG-bf26caee-p77; SEG-bf26caee-p80; SEG-bf26caee-p83; SEG-bf26caee-p87; SEG-bf26caee-p104; SEG-bf26caee-p109; SEG-bf26caee-p114; SEG-bf26caee-p119; SEG-bf26caee-p124; SEG-bf26caee-p129; SEG-bf26caee-p134; SEG-bf26caee-p140; SEG-bf26caee-p144; SEG-bf26caee-p145; SEG-bf26caee-p146; SEG-bf26caee-p147; SEG-bf26caee-p160; SEG-bf26caee-p161; SEG-bf26caee-p163; SEG-bf26caee-p164; SEG-bf26caee-p165; SEG-bf26caee-p166; SEG-bf26caee-p167; SEG-bf26caee-p168; SEG-bf26caee-p169; SEG-bf26caee-p170; SEG-bf26caee-p176; SEG-bf26caee-p180; SEG-bf26caee-p184; SEG-bf26caee-p188; SEG-bf26caee-p192; SEG-bf26caee-p196; SEG-bf26caee-p200; SEG-bf26caee-p204; SEG-bf26caee-p208; SEG-bf26caee-p212; SEG-bf26caee-p216; SEG-bf26caee-p220; SEG-bf26caee-p226; SEG-bf26caee-p227; SEG-bf26caee-p228; SEG-bf26caee-p229; SEG-bf26caee-p230; SEG-bf26caee-p231; SEG-bf26caee-p232; SEG-bf26caee-p233; SEG-bf26caee-p234; SEG-bf26caee-p237; SEG-bf26caee-p242; SEG-bf26caee-p247; SEG-bf26caee-p252; SEG-bf26caee-p257; SEG-bf26caee-p262; SEG-bf26caee-p267; SEG-bf26caee-p272; SEG-bf26caee-p277; SEG-bf26caee-p282; SEG-bf26caee-p289; SEG-bf26caee-p293; SEG-bf26caee-p297; SEG-bf26caee-p301; SEG-bf26caee-p305; SEG-bf26caee-p309; SEG-bf26caee-p313; SEG-bf26caee-p317; SEG-bf26caee-p321; SEG-bf26caee-p325; SEG-bf26caee-p329; SEG-bf26caee-p338; SEG-bf26caee-p342; SEG-bf26caee-p346; SEG-bf26caee-p350; SEG-bf26caee-p354; SEG-bf26caee-p358; SEG-bf26caee-p362; SEG-bf26caee-p366; SEG-bf26caee-p370; SEG-bf26caee-p374; SEG-bf26caee-p378; SEG-bf26caee-p382; SEG-bf26caee-p386; SEG-bf26caee-p390; SEG-bf26caee-p394; SEG-bf26caee-p398; SEG-bf26caee-p402; SEG-bf26caee-p407; SEG-bf26caee-p410; SEG-bf26caee-p481; SEG-bf26caee-p565; SEG-bf26caee-p648; SEG-bf26caee-p681; SEG-bf26caee-p756; SEG-bf26caee-p759; SEG-bf26caee-p762; SEG-bf26caee-p765; SEG-bf26caee-p768; SEG-bf26caee-p771; SEG-bf26caee-p787; SEG-bf26caee-p788; SEG-bf26caee-p789; SEG-bf26caee-p790; SEG-bf26caee-p791; SEG-bf26caee-p792,124,"[{""id"": ""SEG-bf26caee-p14"", ""section"": ""1.0"", ""first_paragraph"": 14, ""last_paragraph"": 14, ""text"": ""O Código Comercial, aprovado pelo Decreto-Lei n.º 1/2022, de 25 de Maio, constitui o enquadramento geral e transversal da actividade empresarial: define o objecto do regime comercial, a actividade empresarial, o empresário, a empresa, a capacidade empresarial e as obrigações comerciais. Este enquadramento aplica-se à organização e ao exercício da actividade empresarial, mas não substitui as exigências administrativas próprias de sectores regulados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p14"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p15"", ""section"": ""1.0"", ""first_paragraph"": 15, ""last_paragraph"": 15, ""text"": ""Os regimes sectoriais especiais aplicam-se cumulativamente quando a lei sujeita determinada actividade, operação, operador, localização ou instrumento a licença, autorização, registo regulatório, parecer, vistoria, comunicação ou supervisão. O Código Comercial disciplina o estatuto e a organização da actividade empresarial; não emite licença administrativa nem elimina requisitos sectoriais. Por sua vez, a licença sectorial habilita ou controla a actividade no âmbito do diploma especial, mas não substitui firma, registo comercial, escrituração, contas, actos societários e demais obrigações empresariais gerais que sejam aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p15"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p20"", ""section"": ""1.0.1"", ""first_paragraph"": 20, ""last_paragraph"": 22, ""text"": ""Artigo 1 | Objecto | Delimita a actividade empresarial, os sujeitos que a exercem e as relações jurídicas abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p20"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p23"", ""section"": ""1.0.1"", ""first_paragraph"": 23, ""last_paragraph"": 25, ""text"": ""Artigo 2 | Actividade empresarial | Qualifica a prática organizada de actos de produção ou circulação de bens ou prestação de serviços com finalidade lucrativa."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p23"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p26"", ""section"": ""1.0.1"", ""first_paragraph"": 26, ""last_paragraph"": 28, ""text"": ""Artigo 3 | Empresário | Distingue empresário individual e sociedade empresarial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p26"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p29"", ""section"": ""1.0.1"", ""first_paragraph"": 29, ""last_paragraph"": 31, ""text"": ""Artigo 4 | Noção de empresa | Enquadra a organização dos factores de produção e as actividades abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p29"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p32"", ""section"": ""1.0.1"", ""first_paragraph"": 32, ""last_paragraph"": 34, ""text"": ""Artigos 5 a 10 | Classificação da empresa, critérios especiais, prevalência e actualização | Exigem parametrização por finalidade, versão e vigência."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p32"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p35"", ""section"": ""1.0.1"", ""first_paragraph"": 35, ""last_paragraph"": 37, ""text"": ""Artigos 11 e 12 | Norma de conflitos e direito subsidiário | Orientam a lei aplicável e a integração de lacunas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p35"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p38"", ""section"": ""1.0.1"", ""first_paragraph"": 38, ""last_paragraph"": 40, ""text"": ""Artigos 13 a 18 | Capacidade empresarial e situações especiais | Suportam validações relativas à capacidade, cônjuges, menor e exercício por não empresário."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p38"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p41"", ""section"": ""1.0.1"", ""first_paragraph"": 41, ""last_paragraph"": 43, ""text"": ""Artigo 19 | Obrigações especiais do empresário | Consolida as obrigações de adoptar firma, escriturar em ordem uniforme as operações, inscrever os actos sujeitos a registo comercial e prestar contas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p41"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p44"", ""section"": ""1.0.1"", ""first_paragraph"": 44, ""last_paragraph"": 46, ""text"": ""Artigo 20 | Obrigatoriedade da firma | Exige nome empresarial no exercício da actividade e assinatura dos documentos correspondentes."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p44"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p47"", ""section"": ""1.0.1"", ""first_paragraph"": 47, ""last_paragraph"": 49, ""text"": ""Artigo 21 | Composição de firma | Define os elementos admissíveis na composição da firma."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p47"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p50"", ""section"": ""1.0.1"", ""first_paragraph"": 50, ""last_paragraph"": 52, ""text"": ""Artigo 22 | Princípio da verdade | Impede elementos falsos ou susceptíveis de induzir em erro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p50"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p53"", ""section"": ""1.0.1"", ""first_paragraph"": 53, ""last_paragraph"": 55, ""text"": ""Artigo 23 | Princípio da novidade | Exige distinção da firma relativamente às já registadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p53"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p56"", ""section"": ""1.0.1"", ""first_paragraph"": 56, ""last_paragraph"": 58, ""text"": ""Artigos 24 e 25 | Uso da língua oficial e outros requisitos da firma | Controlam a língua e requisitos adicionais da firma, conforme a versão oficial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p56"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p59"", ""section"": ""1.0.1"", ""first_paragraph"": 59, ""last_paragraph"": 61, ""text"": ""Artigo 26 | Uso exclusivo de firma | Vincula a exclusividade ao registo pelo titular."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p59"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p62"", ""section"": ""1.0.1"", ""first_paragraph"": 62, ""last_paragraph"": 64, ""text"": ""Artigo 27 | Uso ilegal de firma | Prevê proibição e responsabilidade decorrente do uso ilegal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p62"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p65"", ""section"": ""1.0.1"", ""first_paragraph"": 65, ""last_paragraph"": 67, ""text"": ""Artigo 28 | Transmissão de firma | Relaciona a transmissão da firma com a transmissão da empresa."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p65"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p68"", ""section"": ""1.0.1"", ""first_paragraph"": 68, ""last_paragraph"": 70, ""text"": ""Artigo 29 | Saída ou falecimento de sócio ou accionista | Regula os efeitos sobre a firma quando o nome conste da mesma."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p68"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p71"", ""section"": ""1.0.1"", ""first_paragraph"": 71, ""last_paragraph"": 73, ""text"": ""Artigo 30 | Anulação de firma | Regula a anulação por violação de direito de terceiro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p71"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p74"", ""section"": ""1.0.1"", ""first_paragraph"": 74, ""last_paragraph"": 76, ""text"": ""Artigo 31 | Caducidade da firma | Define causas de caducidade."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p74"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p77"", ""section"": ""1.0.1"", ""first_paragraph"": 77, ""last_paragraph"": 79, ""text"": ""Artigo 32 | Declaração de caducidade da firma | Define competência, contraditório, decisão e recurso."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p77"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p80"", ""section"": ""1.0.1"", ""first_paragraph"": 80, ""last_paragraph"": 82, ""text"": ""Artigo 33 | Renúncia à firma | Regula a declaração de renúncia perante a entidade competente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p80"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p83"", ""section"": ""1.0.1"", ""first_paragraph"": 83, ""last_paragraph"": 85, ""text"": ""Secções III a V do Capítulo II | Escrituração mercantil; registo comercial; balanço e prestação de contas | A estrutura está confirmada na fonte oficial; a numeração artigo a artigo permanece bloqueada no portal até conferência integral das páginas correspondentes da republicação oficial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p83"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p87"", ""section"": ""1.0.1"", ""first_paragraph"": 87, ""last_paragraph"": 87, ""text"": ""Fonte oficial e vigência: Decreto-Lei n.º 1/2022, de 25 de Maio, republicado no 3.º Suplemento ao Boletim da República, I Série, n.º 99, de 25 de Maio de 2022. A Imprensa Nacional de Moçambique regista que a publicação inicial ficou sem efeito e que o texto válido foi republicado no 3.º Suplemento. O diploma entrou em vigor 120 dias após a publicação, em 22 de Setembro de 2022. Consultar a publicação oficial da Imprensa Nacional de Moçambique. Para cada requisito do portal, deve ser citado o artigo específico da versão republicada e, quando exista, o diploma sectorial aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p87"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p104"", ""section"": ""1.0.2"", ""first_paragraph"": 104, ""last_paragraph"": 108, ""text"": ""Artigos 11 e 12 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Norma de conflitos e direito subsidiário | INV-001; INV-007; §§1.6, 3.2.2 e 6.5 | Regra aplicável documentada quando houver elemento estrangeiro, lacuna ou articulação com diploma especial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p104"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p109"", ""section"": ""1.0.2"", ""first_paragraph"": 109, ""last_paragraph"": 113, ""text"": ""Artigos 13 a 18 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Capacidade empresarial e situações especiais | INV-001; INV-007; SOC-001; §§3.1.1, 3.2.2 e 9.5 | Validações de capacidade e representação nos formulários e no comparador, sem decisão automática quando for necessária análise jurídica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p109"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p114"", ""section"": ""1.0.2"", ""first_paragraph"": 114, ""last_paragraph"": 118, ""text"": ""Artigo 19 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Obrigações especiais do empresário | INV-001; INV-002; INV-007; §§1.6, 3.2 e 6.1 | Checklist transversal que distingue firma, escrituração, registo e prestação de contas das licenças sectoriais."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p114"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p119"", ""section"": ""1.0.2"", ""first_paragraph"": 119, ""last_paragraph"": 123, ""text"": ""Artigos 20 a 33 | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Regime da firma | INV-001; INV-007; SOC-001; SOC-002; §§3.2.2, 6.1, 9.2 e 9.3 | Validação da designação, composição, verdade, novidade, uso, transmissão, caducidade e renúncia, com fonte e evidência registal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-COMPANY-01"", ""AUD-COMPANY-02"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p119"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p124"", ""section"": ""1.0.2"", ""first_paragraph"": 124, ""last_paragraph"": 128, ""text"": ""Secção III do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Escrituração mercantil | INV-002; INV-007; §§1.6, 6.1 e 7.3 | Requisito documental e de governação ligado à organização da actividade; a numeração artigo a artigo permanece dependente de conferência integral."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p124"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p129"", ""section"": ""1.0.2"", ""first_paragraph"": 129, ""last_paragraph"": 133, ""text"": ""Secção IV do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Registo comercial | INV-001; INV-002; INV-007; §§1.6, 1.8 e 6.1 | Formalidade de registo e publicidade tratada separadamente do licenciamento sectorial, com entidade, acto e competência territorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p129"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p134"", ""section"": ""1.0.2"", ""first_paragraph"": 134, ""last_paragraph"": 138, ""text"": ""Secção V do Título II, Capítulo II | Decreto-Lei n.º 1/2022 — publicação oficial da Imprensa Nacional de Moçambique | Balanço e prestação de contas | INV-002; INV-007; §§1.6, 6.1 e 7.3 | Obrigação empresarial geral ligada ao checklist e à governação documental; não constitui autorização de actividade."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-CRM-01"", ""AUD-DESK-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p134"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p140"", ""section"": ""1.0.2"", ""first_paragraph"": 140, ""last_paragraph"": 140, ""text"": ""Estas referências complementam os requisitos existentes e devem ser registadas na matriz de rastreabilidade. Não criam novas histórias, não alteram a numeração do backlog e não substituem os diplomas sectoriais aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p140"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p144"", ""section"": ""1.2"", ""first_paragraph"": 144, ""last_paragraph"": 144, ""text"": ""Converter a matriz de requisitos por fase num guia interactivo, passo a passo, em vez de a apresentar como prompt."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p144"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p145"", ""section"": ""1.2"", ""first_paragraph"": 145, ""last_paragraph"": 145, ""text"": ""Estruturar a jornada do investidor desde a concepção do projecto até à entrada em operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p145"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p146"", ""section"": ""1.2"", ""first_paragraph"": 146, ""last_paragraph"": 146, ""text"": ""Disponibilizar formulários nos pontos necessários e gerar documentos para preenchimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p146"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p147"", ""section"": ""1.2"", ""first_paragraph"": 147, ""last_paragraph"": 147, ""text"": ""Criar checklists por entidade, incluindo APIEX, INTIC, Banco de Moçambique e demais instituições licenciadoras."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-DESK-02"", ""MASTER-1f0a4cde-0001"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p147"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p160"", ""section"": ""1.6"", ""first_paragraph"": 160, ""last_paragraph"": 160, ""text"": ""Criar checklists e, quando disponíveis, formulários para licenciamentos financeiros, sectoriais e de actividades económicas junto das entidades competentes."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p160"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p161"", ""section"": ""1.6"", ""first_paragraph"": 161, ""last_paragraph"": 161, ""text"": ""Os checklists devem ser organizados em três camadas independentes: (1) obrigações empresariais gerais do Código Comercial; (2) formalidades de registo e publicidade perante a entidade de registo competente; e (3) licenças, autorizações e controlos sectoriais especiais. A conclusão de uma camada não comprova automaticamente o cumprimento das outras. Por exemplo, o registo ou licenciamento pelo INTIC ao abrigo do Decreto n.º 59/2023 não substitui o cumprimento das obrigações comerciais gerais nem outros actos sectoriais aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p161"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p163"", ""section"": ""1.7"", ""first_paragraph"": 163, ""last_paragraph"": 163, ""text"": ""APIEX, I.P. — registo, aprovação e acompanhamento de projectos de investimento privado, segundo a competência e o fluxo confirmados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p163"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p164"", ""section"": ""1.7"", ""first_paragraph"": 164, ""last_paragraph"": 164, ""text"": ""Autoridade Tributária de Moçambique — NUIT, obrigações fiscais, benefícios fiscais e procedimentos aduaneiros aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p164"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p165"", ""section"": ""1.7"", ""first_paragraph"": 165, ""last_paragraph"": 165, ""text"": ""Banco de Moçambique — autorizações, registos e controlos aplicáveis a instituições financeiras, operações cambiais, entrada de capital, transferência de lucros, dividendos e desinvestimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p165"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p166"", ""section"": ""1.7"", ""first_paragraph"": 166, ""last_paragraph"": 166, ""text"": ""BAU, I.P. — facilitação de procedimentos de licenciamento de actividades económicas e encaminhamento para a entidade competente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p166"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p167"", ""section"": ""1.7"", ""first_paragraph"": 167, ""last_paragraph"": 167, ""text"": ""Instituto Nacional de Tecnologias de Informação e Comunicação, I.P. (INTIC, I.P.), na qualidade de Autoridade Reguladora de TIC — entidade competente para o registo e licenciamento de Provedores Intermediários de Serviços Electrónicos e de Operadores de Plataformas Digitais, nos termos do Decreto n.º 59/2023, de 27 de Outubro. O âmbito inclui certificado de registo, licença por classe ou licença unificada, alteração, transmissão, renovação, cancelamento, vistoria e fiscalização, conforme o processo aplicável. Outros serviços, pareceres, homologações ou autorizações só devem ser incluídos quando comprovados por diploma ou fonte oficial específica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p167"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p168"", ""section"": ""1.7"", ""first_paragraph"": 168, ""last_paragraph"": 168, ""text"": ""Bolsa de Valores de Moçambique — informação sobre mercados, instrumentos e percurso de admissão, mantendo separadas as competências da bolsa, da autoridade reguladora e dos intermediários legalmente autorizados. Cada requisito, documento ou decisão deve indicar a entidade competente e a respectiva fonte antes de ser publicado no portal."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p168"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p169"", ""section"": ""1.7"", ""first_paragraph"": 169, ""last_paragraph"": 169, ""text"": ""Conservatória competente — constituição, registo e actos societários aplicáveis."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p169"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p170"", ""section"": ""1.7"", ""first_paragraph"": 170, ""last_paragraph"": 170, ""text"": ""Ministérios, institutos públicos, municípios e demais autoridades sectoriais — licenças, pareceres, inspecções e autorizações conforme a actividade, localização e diploma aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p170"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p176"", ""section"": ""1.8"", ""first_paragraph"": 176, ""last_paragraph"": 179, ""text"": ""Código Comercial — Decreto-Lei n.º 1/2022, de 25 de Maio | Enquadramento e obrigações empresariais gerais | Deveres e actos comerciais ou societários; não constitui licença sectorial | Publicação oficial da Imprensa Nacional; vigente desde 22 de Setembro de 2022."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p176"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p180"", ""section"": ""1.8"", ""first_paragraph"": 180, ""last_paragraph"": 183, ""text"": ""APIEX, I.P. | Promoção, facilitação e acompanhamento do investimento e das exportações, segundo o estatuto orgânico; tramitação dos projectos ao abrigo do regime de investimento privado | Acto exacto previsto na Lei de Investimento e no respectivo regulamento; não tratar registo, aprovação e certificado como equivalentes | Resolução n.º 43/2019 — Estatuto Orgânico da APIEX, I.P.; Lei n.º 8/2023, de 9 de Junho — Lei de Investimento Privado; Decreto n.º 8/2024, de 7 de Março — Regulamento da Lei de Investimento. Aplicar a redacção vigente e o acto exacto de cada fluxo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p180"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p184"", ""section"": ""1.8"", ""first_paragraph"": 184, ""last_paragraph"": 187, ""text"": ""Autoridade Tributária de Moçambique | Administração tributária e aduaneira, cadastro fiscal, declarações, liquidação, cobrança e fiscalização segundo cada imposto ou procedimento | NUIT, declaração, liquidação, comprovativo, decisão, benefício ou acto aduaneiro conforme o diploma aplicável | Portal oficial da Autoridade Tributária — impostos, legislação e procedimentos; serviço oficial de NUIT. A fonte legal deve ser ligada por imposto, benefício ou procedimento; o portal institucional não substitui o diploma específico."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p184"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p188"", ""section"": ""1.8"", ""first_paragraph"": 188, ""last_paragraph"": 191, ""text"": ""Banco de Moçambique — instituições financeiras | Autorização para constituição de instituições de crédito e sociedades financeiras | Autorização concedida caso a caso pelo Governador do Banco de Moçambique | Lei n.º 20/2020, de 31 de Dezembro, artigo 16, e informação oficial de licenciamento; Regulamento aprovado pelo Decreto n.º 50/2024, de 11 de Julho. Aplicar apenas às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p188"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p192"", ""section"": ""1.8"", ""first_paragraph"": 192, ""last_paragraph"": 195, ""text"": ""Banco de Moçambique — operações cambiais | Autorização, registo e controlo de operações cambiais | Autorização ou registo cambial conforme a operação, o sujeito e a redacção vigente | Informação oficial de licenciamento e controlo cambial; Lei n.º 28/2022, de 29 de Dezembro — Lei Cambial. Os avisos e procedimentos aplicáveis devem ser ligados por operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p192"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p196"", ""section"": ""1.8"", ""first_paragraph"": 196, ""last_paragraph"": 199, ""text"": ""BAU, I.P. | Licenciar e monitorar actividades económicas nos termos dos regulamentos aplicáveis; simplificar, harmonizar e operacionalizar serviços integrados | Licença, alvará, certidão de mera comunicação prévia, registo ou encaminhamento, conforme o regime da actividade | Decreto n.º 29/2023, de 24 de Maio — criação do BAU, I.P.; Resolução n.º 3/2024, de 9 de Abril — Estatuto Orgânico; legislação oficial do BAU. Cada checklist deve indicar o regulamento de licenciamento aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p196"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p200"", ""section"": ""1.8"", ""first_paragraph"": 200, ""last_paragraph"": 203, ""text"": ""INTIC, I.P. — competências reguladas | Registo e licenciamento de provedores intermediários de serviços electrónicos e operadores de plataformas digitais; vistoria e fiscalização | Certificado de registo; licença por classe ou unificada; gestão do certificado ou da licença | Decreto n.º 59/2023, com redacção vigente após o Decreto n.º 44/2025; aplicar apenas às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p200"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p204"", ""section"": ""1.8"", ""first_paragraph"": 204, ""last_paragraph"": 207, ""text"": ""INTIC, I.P. — atribuições adicionais | Pareceres, homologações, certificações ou autorizações fora do regime identificado | Nenhum resultado confirmado sem fonte própria | Sem fonte oficial específica ligada; não configurar competência ou acto até identificação do diploma aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p204"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p208"", ""section"": ""1.8"", ""first_paragraph"": 208, ""last_paragraph"": 211, ""text"": ""Registo de Entidades Legais | Registo e publicidade dos actos relativos a entidades legais | Inscrição, certidão, averbamento, publicação ou outro acto registal previsto | Decreto-Lei n.º 1/2024, de 8 de Março — Regulamento do Registo de Entidades Legais. A conservatória e a competência territorial devem coincidir com o processo aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p208"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p212"", ""section"": ""1.8"", ""first_paragraph"": 212, ""last_paragraph"": 215, ""text"": ""Bolsa de Valores de Moçambique — admissão à cotação | Instrução, tramitação e decisão dos pedidos de admissão à cotação, nos termos do regulamento da bolsa | Admissão à cotação, através de pedido patrocinado por operador de bolsa | Regulamento n.º 1/GPCABVM/2010, artigos 1 a 3, emitido ao abrigo do Código do Mercado de Valores Mobiliários, aprovado pelo Decreto-Lei n.º 4/2009."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p212"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p216"", ""section"": ""1.8"", ""first_paragraph"": 216, ""last_paragraph"": 219, ""text"": ""Banco de Moçambique — autoridade do mercado de valores mobiliários | Regulação e supervisão do mercado de valores mobiliários no âmbito das competências legais | Avisos, autorizações, supervisão e demais actos regulatórios aplicáveis | Aviso n.º 3/GBM/2026 e fonte oficial do Banco de Moçambique, emitido ao abrigo do artigo 4 do Código do Mercado de Valores Mobiliários. Distinguir da decisão de admissão praticada pela Bolsa e da intermediação exercida por operadores autorizados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p216"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p220"", ""section"": ""1.8"", ""first_paragraph"": 220, ""last_paragraph"": 223, ""text"": ""Outras autoridades sectoriais | Licenciamento, parecer, autorização, vistoria, comunicação ou supervisão conforme o sector | Título ou decisão sectorial | Fonte variável por sector; relacionar cada acto com diploma oficial, artigo, entidade, vigência, documentos e canal antes da configuração."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p220"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p226"", ""section"": ""1.8.1"", ""first_paragraph"": 226, ""last_paragraph"": 226, ""text"": ""Fonte legal vigente: Decreto n.º 59/2023, de 27 de Outubro — publicação oficial da Imprensa Nacional de Moçambique, que aprova o Regulamento de Registo e Licenciamento de Provedores Intermediários de Serviços Electrónicos e de Operadores de Plataformas Digitais, conjugado com as alterações introduzidas pelo Decreto n.º 44/2025, de 28 de Novembro — Boletim da República, I Série, n.º 229."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p226"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p227"", ""section"": ""1.8.1"", ""first_paragraph"": 227, ""last_paragraph"": 227, ""text"": ""Artigos 9 a 16 do Decreto n.º 59/2023: registo, certificado de registo, alteração, transmissão, renovação e cancelamento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p227"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p228"", ""section"": ""1.8.1"", ""first_paragraph"": 228, ""last_paragraph"": 228, ""text"": ""Artigo 17 do Decreto n.º 59/2023: competência da Autoridade Reguladora de TIC para conceder licença."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p228"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p229"", ""section"": ""1.8.1"", ""first_paragraph"": 229, ""last_paragraph"": 229, ""text"": ""Artigos 18 a 30 do Decreto n.º 59/2023: licenciamento, tipos de licença, pedido, requisitos, validade, alteração, transmissão, renovação e cancelamento, com leitura da redacção vigente após o Decreto n.º 44/2025."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p229"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p230"", ""section"": ""1.8.1"", ""first_paragraph"": 230, ""last_paragraph"": 230, ""text"": ""Artigo 31 do Decreto n.º 59/2023: organização e direcção da vistoria."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p230"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p231"", ""section"": ""1.8.1"", ""first_paragraph"": 231, ""last_paragraph"": 231, ""text"": ""Artigo 49 do Decreto n.º 59/2023: fiscalização das actividades abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p231"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p232"", ""section"": ""1.8.1"", ""first_paragraph"": 232, ""last_paragraph"": 232, ""text"": ""Glossário do Regulamento: a expressão “Autoridade Reguladora de TIC” refere-se ao Instituto Nacional de Tecnologias de Informação e Comunicação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p232"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p233"", ""section"": ""1.8.1"", ""first_paragraph"": 233, ""last_paragraph"": 233, ""text"": ""Decreto n.º 44/2025, artigos 1 e 2: altera o âmbito, o artigo 18, as taxas e o regime transitório e revoga disposições específicas do Decreto n.º 59/2023; os requisitos do portal devem usar a redacção vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p233"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p234"", ""section"": ""1.8.1"", ""first_paragraph"": 234, ""last_paragraph"": 234, ""text"": ""A prova legal confirma as competências do INTIC apenas no âmbito dos provedores intermediários de serviços electrónicos e operadores de plataformas digitais abrangidos pelo regulamento. Outras atribuições permanecem sem prova documental específica até à identificação de fonte própria."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p234"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p237"", ""section"": ""1.8.2"", ""first_paragraph"": 237, ""last_paragraph"": 241, ""text"": ""Entidade ou regime | Diploma e artigo confirmados | Competência ou acto comprovado | Fonte oficial verificável | Vigência e âmbito"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p237"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p242"", ""section"": ""1.8.2"", ""first_paragraph"": 242, ""last_paragraph"": 246, ""text"": ""Código Comercial | Decreto-Lei n.º 1/2022, de 25 de Maio; artigos 1 a 19 e 20 a 33; Título II, Capítulo II, Secções III a V | Enquadramento geral da actividade empresarial, empresário, empresa, capacidade, firma, obrigações especiais, escrituração, registo comercial e prestação de contas | Imprensa Nacional de Moçambique — Boletim da República n.º 99, 3.º Suplemento | Vigente desde 22 de Setembro de 2022; regime geral, não licença sectorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p242"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p247"", ""section"": ""1.8.2"", ""first_paragraph"": 247, ""last_paragraph"": 251, ""text"": ""APIEX, I.P. | Resolução n.º 43/2019; Lei n.º 8/2023, artigos 21 a 24; Decreto n.º 8/2024, artigos 2 e 3 do diploma aprovador | Base institucional; coordenação, recepção e tramitação de procedimentos de investimento; monitoria, acompanhamento e assistência aos projectos abrangidos | Resolução n.º 43/2019 — Imprensa Nacional; Lei n.º 8/2023 — Imprensa Nacional; Decreto n.º 8/2024 — Imprensa Nacional | Confirmado apenas no âmbito institucional e procedimental indicado; aplicar a redacção vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p247"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p252"", ""section"": ""1.8.2"", ""first_paragraph"": 252, ""last_paragraph"": 256, ""text"": ""Banco de Moçambique — instituições de crédito e sociedades financeiras | Lei n.º 20/2020, artigo 16; Decreto n.º 50/2024, artigos 1 a 4 e regime específico aplicável | Autorização, caso a caso, para constituição das instituições abrangidas; procedimentos gerais de instrução dos pedidos | Lei n.º 20/2020 — fonte oficial do Banco de Moçambique; Decreto n.º 50/2024 — fonte oficial do Banco de Moçambique; página oficial de licenciamento | Lei vigente desde a sua entrada em vigor; Regulamento publicado em 11 de Julho de 2024. Confirma constituição e procedimento geral, não todos os actos posteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p252"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p257"", ""section"": ""1.8.2"", ""first_paragraph"": 257, ""last_paragraph"": 261, ""text"": ""Banco de Moçambique — matéria cambial | Lei n.º 28/2022, artigos 8, 9, 11 e 27 a 30; Decreto n.º 56/2023, artigos 1 a 4 | Autoridade cambial, competência regulamentar, autorização, registo e controlo das operações abrangidas | Lei n.º 28/2022 — fonte oficial do Banco de Moçambique; Decreto n.º 56/2023 — fonte oficial do Banco de Moçambique | Aplicar a redacção vigente e o aviso ou procedimento específico de cada operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p257"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p262"", ""section"": ""1.8.2"", ""first_paragraph"": 262, ""last_paragraph"": 266, ""text"": ""BAU, I.P. | Decreto n.º 29/2023; Resolução n.º 3/2024; regulamentos sectoriais publicados no portal oficial | Criação, organização institucional, simplificação e disponibilização integrada de serviços; licenciamento ou encaminhamento apenas nos termos do regulamento da actividade | Decreto n.º 29/2023 — Imprensa Nacional; Resolução n.º 3/2024 — Imprensa Nacional; legislação oficial do BAU | Base institucional confirmada. O acto decisório depende do regulamento sectorial aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p262"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p267"", ""section"": ""1.8.2"", ""first_paragraph"": 267, ""last_paragraph"": 271, ""text"": ""INTIC, I.P. — Autoridade Reguladora de TIC | Decreto n.º 59/2023, artigos 9 a 16, 17, 18 a 31 e 49; Decreto n.º 44/2025, artigos 1 e 2 | Registo, licenciamento, gestão de certificados e licenças, vistoria e fiscalização de provedores intermediários de serviços electrónicos e operadores de plataformas digitais | Decreto n.º 59/2023 — Imprensa Nacional; Decreto n.º 44/2025 — Boletim da República | Usar a redacção vigente após a alteração de 2025; limitado às categorias abrangidas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p267"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p272"", ""section"": ""1.8.2"", ""first_paragraph"": 272, ""last_paragraph"": 276, ""text"": ""Registo de Entidades Legais | Decreto-Lei n.º 1/2024, artigo 1 do diploma aprovador; Regulamento, artigos 1, 2 e 11 a 18 | Registo e publicidade de actos relativos a entidades legais; organização dos serviços; identificação e declaração do beneficiário efectivo | Decreto-Lei n.º 1/2024 — Imprensa Nacional; texto do Regulamento — Tribunal Supremo | Vigente desde a data definida no diploma; actos individuais dependem do artigo próprio e da competência territorial."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p272"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p277"", ""section"": ""1.8.2"", ""first_paragraph"": 277, ""last_paragraph"": 281, ""text"": ""Bolsa de Valores de Moçambique — admissão à cotação | Código do Mercado de Valores Mobiliários, artigo 67, n.º 2; Regulamento n.º 1/GPCABVM/2010, artigos 1 a 3 | Instrução, tramitação e decisão dos pedidos de admissão; patrocínio por operador de bolsa; apresentação do requerimento | Regulamento n.º 1/GPCABVM/2010 — Bolsa de Valores de Moçambique; página oficial do processo de listagem | Confirmado para os artigos 1 a 3 e para o fundamento do artigo 67, n.º 2; demais requisitos dependem da versão regulamentar vigente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p277"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p282"", ""section"": ""1.8.2"", ""first_paragraph"": 282, ""last_paragraph"": 286, ""text"": ""Banco de Moçambique — mercado de valores mobiliários | Decreto-Lei n.º 4/2009, Código do Mercado de Valores Mobiliários, artigo 4 | Autoridade reguladora e supervisora do mercado, no âmbito das competências previstas no artigo 4 | Código do Mercado de Valores Mobiliários — fonte oficial do Banco de Moçambique | Competência-base confirmada; cada autorização, oferta, intermediário ou acto de supervisão exige norma específica."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p282"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p289"", ""section"": ""1.8.3"", ""first_paragraph"": 289, ""last_paragraph"": 292, ""text"": ""Entidade | Competência, acto ou parâmetro pendente | Prova necessária | Estado"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p289"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p293"", ""section"": ""1.8.3"", ""first_paragraph"": 293, ""last_paragraph"": 296, ""text"": ""APIEX, I.P. | Limiar e decisor por valor do projecto; designação exacta de mero registo, autorização, aprovação, certificado, alteração, cessão e revogação | Artigo regulamentar vigente, formulário, acto emitido e fluxo aprovado por tipo e valor de projecto | Parcialmente confirmado; parcela pendente separada"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p293"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p297"", ""section"": ""1.8.3"", ""first_paragraph"": 297, ""last_paragraph"": 300, ""text"": ""Autoridade Tributária de Moçambique | Base legal individual de NUIT, IRPC, IVA, ISPC, benefícios, isenções, taxas, declarações, cobrança, fiscalização e actos aduaneiros usados pelo portal | Diploma oficial, artigo, taxa ou fórmula, vigência, entidade decisora, formulário e canal para cada regra | Sem prova específica por regra; os portais institucionais confirmam o canal, não o fundamento jurídico individual"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p297"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p301"", ""section"": ""1.8.3"", ""first_paragraph"": 301, ""last_paragraph"": 304, ""text"": ""Banco de Moçambique — instituições financeiras | Documentos, prazos, alteração, fusão, transmissão, sucursais, revogação e requisitos próprios de cada categoria | Artigo da Lei n.º 20/2020, do Decreto n.º 50/2024 ou aviso específico | Parcialmente confirmado; constituição confirmada"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p301"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p305"", ""section"": ""1.8.3"", ""first_paragraph"": 305, ""last_paragraph"": 308, ""text"": ""Banco de Moçambique — operações cambiais | Procedimento exacto para entrada de capital, empréstimo externo, transferência de lucros e dividendos, desinvestimento e contas no exterior | Artigo do regulamento ou aviso específico, formulário, prazo, documentos e canal | Parcialmente confirmado por operação"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p305"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p309"", ""section"": ""1.8.3"", ""first_paragraph"": 309, ""last_paragraph"": 312, ""text"": ""BAU, I.P. | Competência decisória e acto exacto por actividade: licença, alvará, certidão, mera comunicação, registo ou encaminhamento | Artigo do regulamento comercial, industrial, simplificado ou de mera comunicação aplicável à actividade | Base institucional confirmada; acto sectorial pendente por processo"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p309"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p313"", ""section"": ""1.8.3"", ""first_paragraph"": 313, ""last_paragraph"": 316, ""text"": ""INTIC, I.P. | Pareceres, homologações, certificações ou autorizações fora dos Decretos n.º 59/2023 e n.º 44/2025 | Diploma e artigo próprios | Sem prova específica fora do regime confirmado"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p313"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p317"", ""section"": ""1.8.3"", ""first_paragraph"": 317, ""last_paragraph"": 320, ""text"": ""Registo de Entidades Legais | Reserva de denominação, constituição, alteração, certidão, averbamento, publicação, cancelamento e emolumentos por acto | Artigo exacto do Decreto-Lei n.º 1/2024, tabela aplicável e conservatória territorialmente competente | Parcialmente confirmado; base e beneficiário efectivo confirmados"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p317"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p321"", ""section"": ""1.8.3"", ""first_paragraph"": 321, ""last_paragraph"": 324, ""text"": ""Bolsa de Valores de Moçambique | Requisitos por segmento, montantes mínimos, prospecto, documentos, prazos, taxas e decisão final além dos artigos 1 a 3 | Artigo da versão regulamentar vigente e acto complementar aplicável | Parcialmente confirmado; artigos 1 a 3 confirmados"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p321"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p325"", ""section"": ""1.8.3"", ""first_paragraph"": 325, ""last_paragraph"": 328, ""text"": ""Banco de Moçambique — mercado de valores mobiliários | Autorizações, ofertas, intermediários e actos de supervisão específicos | Artigo do Código do Mercado de Valores Mobiliários e aviso ou regulamento aplicável | Competência-base confirmada; actos específicos pendentes"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p325"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p329"", ""section"": ""1.8.3"", ""first_paragraph"": 329, ""last_paragraph"": 332, ""text"": ""Outras autoridades sectoriais | Todas as competências ainda não individualizadas | Diploma, artigo, fonte oficial, vigência, entidade decisora, documentos, prazo, canal e resultado | Sem prova específica"", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p329"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p338"", ""section"": ""1.8.4"", ""first_paragraph"": 338, ""last_paragraph"": 341, ""text"": ""Decreto-Lei n.º 1/2022 — Código Comercial | Referência oficial da Imprensa Nacional preservada. Estado: acesso técnico à referência pendente, porque a pesquisa directa redireccionou para o portal geral. | Não foi localizada revogação posterior na pesquisa documental registada. | Usar a versão republicada no 3.º Suplemento ao Boletim da República, I Série, n.º 99, e a data de entrada em vigor já aceite. A pendência técnica do link não reabre a aceitação da fonte."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p338"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p342"", ""section"": ""1.8.4"", ""first_paragraph"": 342, ""last_paragraph"": 345, ""text"": ""Resolução n.º 43/2019 — Estatuto Orgânico da APIEX, I.P. | Acesso oficial confirmado na Imprensa Nacional. | Foi localizada rectificação de 13 de Abril de 2020; não foi localizada revogação posterior. | Aplicar a Resolução com a rectificação incorporada."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p342"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p346"", ""section"": ""1.8.4"", ""first_paragraph"": 346, ""last_paragraph"": 349, ""text"": ""Lei n.º 8/2023 — Lei de Investimento Privado | Acesso oficial confirmado na Imprensa Nacional. | Não foi localizada revogação posterior na pesquisa documental registada. | Aplicar conjuntamente com o Decreto n.º 8/2024 e com alterações posteriores que venham a ser identificadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p346"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p350"", ""section"": ""1.8.4"", ""first_paragraph"": 350, ""last_paragraph"": 353, ""text"": ""Decreto n.º 8/2024 — Regulamento da Lei de Investimento | Acesso oficial confirmado na Imprensa Nacional. | O diploma revoga os Decretos n.º 43/2009 e n.º 20/2021; não foi localizada revogação posterior do Decreto n.º 8/2024. | Usar como referência regulamentar dos fluxos abrangidos, confirmando o artigo específico de cada procedimento."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p350"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p354"", ""section"": ""1.8.4"", ""first_paragraph"": 354, ""last_paragraph"": 357, ""text"": ""Lei n.º 20/2020 — Instituições de Crédito e Sociedades Financeiras | Acesso oficial confirmado no Banco de Moçambique. | Não foi localizada revogação posterior na pesquisa documental registada. | Aplicar o artigo 16 e as demais disposições relevantes em conjunto com o Decreto n.º 50/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p354"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p358"", ""section"": ""1.8.4"", ""first_paragraph"": 358, ""last_paragraph"": 361, ""text"": ""Decreto n.º 50/2024 — Regulamento da Lei n.º 20/2020 | Acesso oficial confirmado no Banco de Moçambique. | Revoga os Decretos n.º 56/2004, 57/2004, 31/2006, 30/2014 e 99/2019 e normas contrárias; não foi localizada revogação posterior. | Usar este regulamento nos procedimentos abrangidos e não os diplomas revogados."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p358"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p362"", ""section"": ""1.8.4"", ""first_paragraph"": 362, ""last_paragraph"": 365, ""text"": ""Página oficial de licenciamento de instituições | Acesso institucional confirmado no Banco de Moçambique. | Conteúdo institucional activo; a página, por si só, não demonstra vigência normativa. | Usar como canal e apoio de navegação; fundamentar cada regra na Lei n.º 20/2020 e no Decreto n.º 50/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p362"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p366"", ""section"": ""1.8.4"", ""first_paragraph"": 366, ""last_paragraph"": 369, ""text"": ""Lei n.º 28/2022 — Lei Cambial | Acesso oficial confirmado no Banco de Moçambique. | Revoga a Lei n.º 11/2009; não foi localizada revogação posterior. | Aplicar em conjunto com o Decreto n.º 56/2023 e com o aviso específico de cada operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p366"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p370"", ""section"": ""1.8.4"", ""first_paragraph"": 370, ""last_paragraph"": 373, ""text"": ""Decreto n.º 56/2023 — Regulamento da Lei Cambial | Acesso oficial confirmado no Banco de Moçambique. | Revoga o Decreto n.º 49/2017; não foi localizada revogação posterior. | Aplicar a redacção do regulamento juntamente com os avisos vigentes por operação."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p370"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p374"", ""section"": ""1.8.4"", ""first_paragraph"": 374, ""last_paragraph"": 377, ""text"": ""Decreto n.º 29/2023 — criação do BAU, I.P. | Acesso oficial confirmado na Imprensa Nacional. | Revoga parcialmente o Decreto n.º 14/2007 quanto ao estatuto anterior dos BAU; não foi localizada revogação posterior. | Usar como base de criação; as competências e actos dependem do Estatuto e dos regulamentos sectoriais."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p374"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p378"", ""section"": ""1.8.4"", ""first_paragraph"": 378, ""last_paragraph"": 381, ""text"": ""Resolução n.º 3/2024 — Estatuto Orgânico do BAU, I.P. | Referência oficial identificada na Imprensa Nacional. Estado: acesso técnico à referência pendente para conferência integral dos artigos. | Não foi localizada revogação posterior na pesquisa documental registada. | Preservar a aceitação do documento oficial; não automatizar competências sem conferir o artigo aplicável no texto integral."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p378"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p382"", ""section"": ""1.8.4"", ""first_paragraph"": 382, ""last_paragraph"": 385, ""text"": ""Portal de legislação do BAU | Referência institucional preservada. Estado: acesso técnico à referência pendente na pesquisa autónoma. | O portal é conteúdo variável e não constitui, por si só, pesquisa conclusiva de revogações. | Usar como índice documental; fundamentar cada regra no diploma e artigo específicos."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p382"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p386"", ""section"": ""1.8.4"", ""first_paragraph"": 386, ""last_paragraph"": 389, ""text"": ""Decreto n.º 59/2023 — licenciamento de plataformas digitais | Acesso oficial confirmado na Imprensa Nacional. | Foi localizada alteração pelo Decreto n.º 44/2025. | Aplicar apenas a redacção resultante das alterações e revogações introduzidas em 2025."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p386"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p390"", ""section"": ""1.8.4"", ""first_paragraph"": 390, ""last_paragraph"": 393, ""text"": ""Decreto n.º 44/2025 — alteração do Decreto n.º 59/2023 | Referência oficial preservada no domínio do INTIC. Estado: acesso técnico à referência pendente no índice de pesquisa. | O documento oficial de 2025 altera e revoga disposições do Decreto n.º 59/2023; não foi localizada alteração posterior. | Preservar a aceitação do Boletim da República n.º 229 e aplicar as alterações de 2025. A pendência técnica do URL não reabre a validação documental."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p390"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p394"", ""section"": ""1.8.4"", ""first_paragraph"": 394, ""last_paragraph"": 397, ""text"": ""Decreto-Lei n.º 1/2024 — Registo de Entidades Legais | Acesso oficial confirmado na Imprensa Nacional; cópia institucional do Tribunal Supremo. | Revoga o Decreto n.º 1/2006, excepto o artigo 1 que cria o Registo de Entidades Legais; não foi localizada revogação posterior. | Usar a Imprensa Nacional como fonte primária e a cópia do Tribunal Supremo como acesso complementar."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p394"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p398"", ""section"": ""1.8.4"", ""first_paragraph"": 398, ""last_paragraph"": 401, ""text"": ""Regulamento n.º 1/GPCABVM/2010 — admissão à cotação | Acesso oficial confirmado no domínio da Bolsa de Valores de Moçambique. | Não foi localizada revogação integral; permanecem por confirmar alterações ou regulamentos posteriores por segmento e matéria. | Aplicar os artigos confirmados e conferir a versão regulamentar específica antes de automatizar requisitos posteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p398"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p402"", ""section"": ""1.8.4"", ""first_paragraph"": 402, ""last_paragraph"": 405, ""text"": ""Decreto-Lei n.º 4/2009 — Código do Mercado de Valores Mobiliários | Acesso oficial confirmado no Banco de Moçambique. | Não foi localizada revogação integral; alterações posteriores devem ser pesquisadas por artigo. | Usar o artigo aplicável com a redacção confirmada para a regra concreta, sem inferir vigência integral apenas pelo acesso ao ficheiro."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p402"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p407"", ""section"": ""1.8.4"", ""first_paragraph"": 407, ""last_paragraph"": 407, ""text"": ""Critério de validação: os resultados devem ser registados separadamente em três dimensões: (1) acesso à fonte, que confirma apenas a disponibilidade técnica da referência; (2) pesquisa de alterações ou revogações, que regista o que foi ou não localizado no período de verificação; e (3) redacção aplicável à regra, que identifica o texto normativo que deve fundamentar o requisito. Um link acessível não demonstra, por si só, vigência. Quando uma ligação não for recuperada tecnicamente, o estado deve ser “acesso técnico à referência pendente”, preservando a aceitação do documento oficial e sem reabrir validações já concluídas. Esta classificação não substitui consolidação legislativa oficial nem conferência jurídica artigo a artigo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p407"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p410"", ""section"": ""1.8.4"", ""first_paragraph"": 410, ""last_paragraph"": 410, ""text"": ""O procedimento é uniforme para todas as entidades: a matriz de competências confirmadas contém apenas referências sustentadas por diploma e artigo identificados; a matriz de pendências contém, separadamente, os actos, parâmetros e procedimentos que ainda exigem prova específica. Nenhuma referência parcial deve ser promovida a regra automática antes da identificação da fonte oficial, vigência, entidade decisora e resultado aplicável."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01"", ""AUD-SIM-02""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p410"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p481"", ""section"": ""3.2.2"", ""first_paragraph"": 481, ""last_paragraph"": 481, ""text"": ""Os formulários devem suportar campos de texto, números, datas, listas, selecção múltipla, localização, anexos e declarações de consentimento. Cada formulário deve possuir versão, período de vigência, regras condicionais, campos obrigatórios, limites de ficheiro, validação de formato, mensagens de erro, gravação automática, recuperação de rascunho e associação ao requisito correspondente. Alterações publicadas não devem modificar retroactivamente submissões já efectuadas."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-25""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p481"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p565"", ""section"": ""4.4"", ""first_paragraph"": 565, ""last_paragraph"": 565, ""text"": ""O modelo deve incluir organizações, utilizadores, papéis, permissões, entidades públicas, localizações administrativas, sectores económicos, actividades, formulários, campos, versões, checklists, itens, submissões, evidências, tarefas, notificações, consentimentos, fontes, importações, conflitos de correspondência e eventos de auditoria. As classificações e regras devem possuir vigência temporal para permitir reproduzir uma decisão ou simulação com os dados aplicáveis à data."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OPS-03"", ""AUD-PROFILE-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p565"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p648"", ""section"": ""6"", ""first_paragraph"": 648, ""last_paragraph"": 653, ""text"": ""INV-007 | Configurar checklists e formulários sem alteração de código | Sim | Parcial | QA | Demonstrar editor, publicação de versões e preservação de submissões anteriores."", ""requirements"": [""AUD-CHECKLIST-01"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p648"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p681"", ""section"": ""6.1"", ""first_paragraph"": 681, ""last_paragraph"": 687, ""text"": ""§1.2; §1.6–1.8 | Checklists e formulários por entidade competente | INV-007 e INV-009 | Sim | Sem demonstração suficiente por entidade | — | Demonstrar checklist, formulário, base legal, responsável, versão, canal e resultado por entidade, sem reabrir fontes oficiais já aceites."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-PROFILE-11"", ""AUD-PROFILE-19"", ""AUD-PROFILE-21"", ""MASTER-9dee08d0-0049""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p681"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p756"", ""section"": ""6.2"", ""first_paragraph"": 756, ""last_paragraph"": 758, ""text"": ""Entidade | Designação canónica e aliases documentados | Preservar designações e fontes já aceites; divergências novas são relacionadas com a correspondência documental em falta."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p756"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p759"", ""section"": ""6.2"", ""first_paragraph"": 759, ""last_paragraph"": 761, ""text"": ""Autorização ou acto | Registo, aprovação, licença, autorização, parecer, comunicação, vistoria, certificado, benefício ou decisão | Não usar os termos como equivalentes; cada acto mantém entidade competente, base, vigência e resultado."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p759"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p762"", ""section"": ""6.2"", ""first_paragraph"": 762, ""last_paragraph"": 764, ""text"": ""Categoria, modalidade e objectivo | Categorias, códigos e versões dos contratos existentes; agrupamentos funcionais do update | O agrupamento funcional não substitui a taxonomia canónica. Mapear sem renumerar, fundir ou converter automaticamente registos, incluindo imobiliário, fundiário e franquia."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p762"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p765"", ""section"": ""6.2"", ""first_paragraph"": 765, ""last_paragraph"": 767, ""text"": ""Acção e autorização | Preparação privada, submissão, encaminhamento restrito e publicação pública | Aplicar a autorização à acção correspondente. A falta de autorização de divulgação impede a publicação pública, não a preparação privada ou o pedido de apoio permitido."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p765"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p768"", ""section"": ""6.2"", ""first_paragraph"": 768, ""last_paragraph"": 770, ""text"": ""Ambiente | QA, Ativo, Ativo e QA ou — | QA não equivale a Ativo; “Ativo e QA” distingue capacidade instalada de evolução ainda em homologação; — indica ausência de demonstração suficiente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p768"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p771"", ""section"": ""6.2"", ""first_paragraph"": 771, ""last_paragraph"": 773, ""text"": ""Evidência | Documento, ecrã, teste, registo, resposta institucional ou ligação operacional | “Sem demonstração suficiente” não significa ausência de código; significa evidência insuficiente para conclusão."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-OP-02"", ""AUD-PROFILE-08""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p771"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p787"", ""section"": ""6.3.1"", ""first_paragraph"": 787, ""last_paragraph"": 787, ""text"": ""As designações institucionais já confirmadas devem ser preservadas. Permanecem sujeitos a prova específica apenas os actos, artigos, limites, procedimentos ou competências assinalados nas secções 1.8.2 e 1.8.3."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p787"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p788"", ""section"": ""6.3.1"", ""first_paragraph"": 788, ""last_paragraph"": 788, ""text"": ""APIEX, I.P.: a designação canónica “Agência para a Promoção de Investimento e Exportações, I.P.” está confirmada pela Resolução n.º 43/2019. Permanecem sujeitos a confirmação por fluxo o acto exacto, o artigo aplicável e o resultado emitido nos termos da Lei n.º 8/2023 e do Decreto n.º 8/2024."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p788"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p789"", ""section"": ""6.3.1"", ""first_paragraph"": 789, ""last_paragraph"": 789, ""text"": ""BAU, I.P.: a designação “Balcões de Atendimento Único, Instituto Público — BAU, I.P.” e as competências institucionais estão confirmadas pelo Decreto n.º 29/2023 e pela Resolução n.º 3/2024. O acto exacto — licença, alvará, certidão, registo, comunicação ou encaminhamento — deve ser confirmado no regulamento da actividade correspondente."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p789"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p790"", ""section"": ""6.3.1"", ""first_paragraph"": 790, ""last_paragraph"": 790, ""text"": ""INTIC, I.P.: a designação e a competência como Autoridade Reguladora de TIC para o registo e licenciamento abrangidos pelo Decreto n.º 59/2023 estão confirmadas. Permanecem sem prova documental específica apenas os serviços, pareceres, homologações, certificações ou autorizações fora desse âmbito."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p790"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p791"", ""section"": ""6.3.1"", ""first_paragraph"": 791, ""last_paragraph"": 791, ""text"": ""Registo de Entidades Legais: a base nacional e a designação do regime estão confirmadas pelo Decreto-Lei n.º 1/2024. A conservatória territorialmente competente e o artigo aplicável a cada acto — reserva, constituição, alteração, certidão, averbamento, publicação ou cancelamento — devem ser confirmados por processo."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p791"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}, {""id"": ""SEG-bf26caee-p792"", ""section"": ""6.3.1"", ""first_paragraph"": 792, ""last_paragraph"": 792, ""text"": ""Enquanto faltar identificar a correspondência documental, o checklist deve conservar a designação encontrada como variante, registar o documento de origem e impedir apenas a sua promoção automática a valor canónico. Esta regra não reabre fontes oficiais, nomenclaturas ou validações já aceites."", ""requirements"": [""AUD-CHECKLIST-01"", ""AUD-LIB-01""], ""source_sha256"": ""bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5"", ""locator"": ""word/document.xml#p792"", ""declared_document_state_is_not_functional_evidence"": true, ""exact_requested_exemplar_confirmed"": true}]",Consumidor específico não demonstrado.,Contrato específico não demonstrado.,Nenhuma entidade/regra criada para este módulo.,"A recuperação do original da especificação é prova do acervo, não deste percurso.",Pendente de implementação/prova própria.,"Novo ID apenas após pesquisa de correspondência: os requisitos relacionados são componentes a reutilizar, não equivalências. [Segmentação bf26caeee043 — identidade confirmada; nome local v1.docx] ",parcial,Não demonstrada para este requisito específico; nenhum pacote ativado por esta incorporação. COUNTRY02ON preservado.,"Diagnóstico específico anterior de ausência/cobertura conservado; inventário atual não demonstra entrega posterior deste incremento. Nenhuma nova implementação iniciada nesta auditoria.
-[RECONCILIACAO-43-20261019] 18: Falta editor administrativo sem código para preparar/publicarv2 preservando respostasv1. Registar serviços existentes não equivale a entregar esse editor.","02/11/2026: editor local dos formulários do Balcão implementado com prévia, publicação versionada, histórico paginado e preservação dos pedidos anteriores. Restam conferência visual e disponibilização; a adaptação de outras checklists/contextos ainda não foi demonstrada. Não se declara parametrização transversal concluída.
+[RECONCILIACAO-43-20261019] 18: Falta editor administrativo sem código para preparar/publicarv2 preservando respostasv1. Registar serviços existentes não equivale a entregar esse editor.","03/11/2026: selector geral do dossier, anexos por pergunta e suporte da etapa já não exigem UUID manual. Catálogo entre dossiers corresponde à autoridade existente, sem alargar o acesso a fontes de outras organizações. Continuam pendentes outros consumidores/formulários e a parametrização transversal de limites/formatos/mensagens, camadas de obrigações/registo/licenciamento por fonte/âmbito, conferência visual/login real e disponibilização no destino. Não é parametrização integral, homologação ou aceitação real. Histórico anterior: 03/11/2026: Balcão tem editor/histórico/vigência, tipos múltiplos/declarações/anexos, recuperação automática e limites de ficheiro por pergunta demonstrados localmente. Restam outros consumidores/contextos p481, limites/formatos/mensagens parametrizados transversalmente, catálogo/selector legado geral e reutilização entre dossiers sem UUID manual, camadas de obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização/migração no destino. Os quatro MIME e tectos técnicos existentes (10MiB/100 ficheiros por dossier) não são parametrização integral da aplicação. Não é homologação, aprovação documental ou aceitação real. Histórico preservado: 03/11/2026: Balcão tem editor/histórico/vigência/tipos múltiplos/declarações e gravação automática/recuperação privada demonstrados em QA. Restam outros consumidores/contextos de checklist e respectivos critérios p481, configuração transversal de limites/anexos/formatos/mensagens, camadas de obrigações gerais/registo/licenciamento por fonte e âmbito, observação visual/login real e disponibilização/migração no destino. Não é homologação nem parametrização integral. Histórico preservado: 03/11/2026: editor, histórico, vigência, selecção múltipla e declarações de consentimento do Balcão implementados/ensaiados localmente. Restam outros consumidores/contextos de checklist, cobertura transversal dos tipos/regras/limites/anexos, autosave/recuperação nos contextos ainda não demonstrados, três camadas de obrigações/registo/licenciamento por fonte e âmbito, visual/login real e disponibilização. Não equivale a homologação, licença ou parametrização integral. Histórico preservado: 02/11/2026: editor local do Balcão, histórico e publicação por data com recuperação da edição aplicável implementados e ensaiados. Restam extensão a outras checklists/contextos, observação visual e disponibilização no destino; não é parametrização integral nem formulário oficial homologado. Histórico: 02/11/2026: editor local dos formulários do Balcão implementado com prévia, publicação versionada, histórico paginado e preservação dos pedidos anteriores. Restam conferência visual e disponibilização; a adaptação de outras checklists/contextos ainda não foi demonstrada. Não se declara parametrização transversal concluída.
Histórico das lacunas anteriores: Checklists existem em configuração; editor/versionamento administrativo sem código e adaptação de submissões antigas não demonstrados.
-[UTILIZACAO-HOMOLOGACAO-20261019] 18: Implementação parcial — Checklists aplicadas existem no fluxo; editor/publicação v2 preservando respostas v1 continua em falta.","Configurações existentes, schema, biblioteca e auditoria; desk_service_versions, desk_requests.service_version_id, VirtualDesk e autorização administrativa existentes","Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Publicar versão autorizada, novas submissões usam-na e anteriores preservam a versão aplicada.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"Desenvolvimento local autorizado pelo pedido de continuidade; editor/histórico do Balcão implementados e validados em QA. Conferência visual, disponibilização e extensão aos restantes consumidores são trabalhos distintos. Histórico da classificação anterior: Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Checklists versionadas=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Checklists versionadas=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
+[UTILIZACAO-HOMOLOGACAO-20261019] 18: Implementação parcial — Checklists aplicadas existem no fluxo; editor/publicação v2 preservando respostas v1 continua em falta.","Configurações existentes, schema, biblioteca e auditoria; desk_service_versions, desk_requests.service_version_id, VirtualDesk e autorização administrativa existentes; DeskServiceAvailability e effective_from do mesmo desk_service_versions; comparação canónica comum às publicações; tipos/opções/condições de DeskServiceEditor e VirtualDesk, campos JSON existentes e snapshots cifrados, sem catálogo paralelo; autoridade/cifra/definição/validação do VirtualDesk, profileJson/CSRF e eventos administrativos existentes; buffer de recuperação não é outro workflow; documents/desk_documents, original/scan/hash/cifra e VerifiedDocumentBinary; vínculo por pedido e origem, sem motor ou armazém documental paralelo; catálogo sobre documents/desk_documents/desk_cases e autoridade de origem existente, mesmo upload/auditoria/scan sem cópia física","Perguntas/anexos/limites já constam de p481. Novos pedidos usam a edição escolhida; o administrador decide limites/obrigatoriedade na publicação, sem restrições institucionais inferidas. Instalação no destino conserva âmbito/backup/restauro próprios. A fonte p481 já exige gravação automática e recuperação. Desenvolvimento/ensaio local não dependem de nova regra; instalar a migração no destino mantém backup/restauro e âmbito próprios. A fonte p481 já especifica estes dois tipos; o incremento reutiliza a competência de configuração actual. Textos reais/obrigatoriedade/contextos são publicados pela administração autorizada, sem consentimentos ou regras organizacionais inventados. Documentos/entidades/fontes/parâmetros próprios antes de implementação; sem novos módulos nesta auditoria. Publicar versão autorizada, novas submissões usam-na e anteriores preservam a versão aplicada.","03/11/2026: o catálogo torna seleccionável a reutilização antes disponível por identificador; não concede acesso a outras organizações. Selecção e pesquisa não equivalem a associação ou submissão. Fonte sem acesso continua privada mesmo para quem enviou o ficheiro. Saldo anterior reconciliado: 03/11/2026: limites de anexos por edição são subconjuntos dos quatro formatos e tectos técnicos já suportados. Reutilizar não amplia automaticamente o âmbito antigo; nova utilização conserva origem/validade declarada e não renova validade nem aprova documentos. Formato/tamanho desconhecidos podem ser medidos no original, sem zero presumido ou alteração retroactiva. Rondas de testes sobrepostas não são somadas como testes únicos. Nota histórica: Actualização 03/11/2026: Balcão conserva automaticamente buffer privado de recuperação; gravar/submeter o pedido principal continua explícito. Pausa de2s é escolha técnica, sem garantia de gravação de caracteres ainda pendentes. Sem armazenamento persistente no navegador, retry automático ilimitado ou aprovação por recuperação. Nota histórica anterior: Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente. Escolha técnica deste incremento: calendário configurado da aplicação; data de início atingida mais recente, maior versão em empate e fallback legado sem data. Publicação existente conserva competências, etapas e valor apenas interno; datas não activam licenças/cálculos. Política apresentada na prévia antes da confirmação. Escolha técnica explícita: multiselect é lista distinta de códigos de texto ordenados como conjunto; contains significa inclusão de uma opção. Consentimento documental usa accepted/declined/null, obrigatório significa escolha explícita e não aceitação. Nenhuma escolha concede outra autorização. Condições dependentes acompanham alteração simples/múltipla na prévia, antes da confirmação. A gravação continua explícita; autosave transversal não foi declarado.","Desenvolvimento local autorizado pelo pedido de continuidade; editor/histórico do Balcão implementados e validados em QA. Conferência visual, disponibilização e extensão aos restantes consumidores são trabalhos distintos. Histórico da classificação anterior: Nova funcionalidade/expansão; preparar execução, não implementar nesta auditoria",Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: incrementos futuros. Esforço de código adicional só após lacuna reproduzida.,"segmentacao-processos-reconciliacao-20261011.md; contratos/rotas inventariados atuais; não há prova de percurso completo deste incremento. | Homologação teste-investidor 19/10/2026: Checklists versionadas=Não demonstrado. Saldo derivado e limites em outputs/investmoz-disponibilizacao-integral-20261019/SALDO-E-ACTUALIZACAO-CONSOLIDADA.md. Não substitui estado/provas do activo; trecho documental encerrado, vínculo dossier aberto. | Proposta integral fdcb31f1b5b9: aplicação activa local completa + R2/DOC01/destino reconciliados; schema/build/recuperação de contexto e reversão de apresentação ensaiados no clone isolado. Não instalado remotamente. Inc. QA territoriais/Inhambane/programas separados. Limites e decisões em outputs/investmoz-disponibilizacao-integral-20261019/PROPOSTA-INTEGRAL-PARA-DECISAO.md. | Execução autorizada fdcb31f1b5b9 concluída em teste-investidor: Checklists versionadas=Não demonstrado. 1080 hashes iguais, schema171/88, custódia/scan/recuperação reais. Sem publicação ou papéis novos. Vínculo dossier legítimo pendente; incrementos QA separados. Limites em outputs/investmoz-disponibilizacao-integral-20261019/RESULTADO-DISPONIBILIZACAO-INTEGRAL.md; não encerra critérios globais não demonstrados.
[UTILIZACAO-HOMOLOGACAO-20261019] Leitura nominal de contas/recursos no destino; saldo18/10; prévia29 sem escrita; comparação de hashes QA separados. outputs/investmoz-disponibilizacao-integral-20261019/UTILIZACAO-EFECTIVA-HOMOLOGACAO.md
[RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário.
-[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. | Continuidade local 02/11/2026: histórico e formulários configuráveis do Balcão; regressões reproduzidas e corrigidas nas condições encadeadas e no preenchimento de campos/opções retirados. Provas e limites no manual existente, secções de 02/11/2026. Sem instalação ou alteração no activo. [DESK-ANALYSIS-SCOPE-20261102] Verificações usam a versão e as perguntas aplicáveis: sem financiamento inexistente ou bloqueio por valores de ramos ocultos; diferenças financeiras aplicáveis continuam recusadas. Recibo distingue respostas conservadas e preserva rótulos da versão, original técnico e permissões. Publicação valida que a fonte da localização não fica indisponível quando a localização se aplica, reutilizando a exigência existente. 25 testes conjuntos/467 asserções e dois específicos/11 asserções aprovados; PHPStan e Pint passaram. Recibo desk_analysis_scope_increment_20261102 em local-validation-20261029.json; manual de 02/11. Sem instalação ou conferência visual; requisito transversal parcial.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Checklists e catálogos configurados existentes; editor sem alterar código/publicação versionada por entidade não demonstrados. Separar obrigações comerciais, registo/publicidade e licença setorial.",Reutilizar componentes/contratos; definição funcional própria e nenhuma nova ativação.,"Reutilizar config/document-requirements.php, requisitos/formulários/documentos/tarefas e serviços do Balcão existentes. Não duplicar motor, tabelas ou as cinco fases/19 etapas.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,"24–40 h após política de alteração; reaproveitar motor, sem catálogo paralelo.",,,
+[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. | Continuidade local 02/11/2026: histórico e formulários configuráveis do Balcão; regressões reproduzidas e corrigidas nas condições encadeadas e no preenchimento de campos/opções retirados. Provas e limites no manual existente, secções de 02/11/2026. Sem instalação ou alteração no activo. [DESK-ANALYSIS-SCOPE-20261102] Verificações usam a versão e as perguntas aplicáveis: sem financiamento inexistente ou bloqueio por valores de ramos ocultos; diferenças financeiras aplicáveis continuam recusadas. Recibo distingue respostas conservadas e preserva rótulos da versão, original técnico e permissões. Publicação valida que a fonte da localização não fica indisponível quando a localização se aplica, reutilizando a exigência existente. 25 testes conjuntos/467 asserções e dois específicos/11 asserções aprovados; PHPStan e Pint passaram. Recibo desk_analysis_scope_increment_20261102 em local-validation-20261029.json; manual de 02/11. Sem instalação ou conferência visual; requisito transversal parcial. [DESK-EFFECTIVE-DATES-20261102] Editor do Balcão permite entrada em vigor por data; catálogo/dossier/percurso e criação de pedidos reutilizam DeskServiceAvailability. Apenas datas já atingidas, a mais recente e maior versão na mesma data; legados sem data permanecem fallback, sem reescrita. Edições futuras visíveis na gestão; pedidos antigos/repetições mantêm FK, respostas e snapshots. Corrigida duplicação na publicação inicial por ordem de chaves JSONB; comparação canónica reutilizada. 21 Feature/314 asserções e nove frontend, PHPStan/tipos/lint/Pint/compilação aprovados; recibo desk_effective_dates_increment_20261102. Parcial: outros contextos, visual e destino pendentes; sem alteração no activo. [DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo. [DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa. [DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa. [DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa.",incrementos futuros,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Checklists e catálogos configurados existentes; editor sem alterar código/publicação versionada por entidade não demonstrados. Separar obrigações comerciais, registo/publicidade e licença setorial.",Reutilizar componentes/contratos; definição funcional própria e nenhuma nova ativação.,"Reutilizar config/document-requirements.php, requisitos/formulários/documentos/tarefas e serviços do Balcão existentes. Não duplicar motor, tabelas ou as cinco fases/19 etapas.",Leitura integral do exemplar local e inventário código/documental; importação/retrieval deste DOCX não comprova a funcionalidade descrita.,Contrato específico não demonstrado.,,,,"24–40 h após política de alteração; reaproveitar motor, sem catálogo paralelo.",,,
AUD-FINTECH-01,"Caracterizar e acompanhar investimento Fintech no mesmo dossier/percurso: modelos tecnológico/financeiro/indeterminado, atividades e documentação condicionais, preparação e revisão por âmbito.","Pedido Tempo anexado em 15/10/2026, SHA-256 d00e8ea77fc7c42acb9b011614513a2b2bec4933ac55275cf87437719bf8c8fa; orientação transversal setorial e AGENTS.md 12/10/2026.",Investimentos / Fintech,/sectores/{slug}; /investimentos; /investimentos/a-partir-do-setor/{sectorSlug}; /investimentos/{id}/fintech,"FintechInvestment no payload cifrado existente; InvestorPath/InvestorGuidanceRules, S01–S19; biblioteca, scan, ferramentas, apoio e tarefas reutilizados. Sem nova categoria ou workflow.","Disponibilizado em 15/10/2026, setores-fintech-QA-d5b4dc354265 DOC01: 16 fontes e compilação; sete entradas setoriais e especialização Fintech no dossier; três artigos publicados (recursos reais 27/28/29), imagem 24 reutilizada por identidade/hash. Flags existentes preservadas; sem migrations/categorias novas. B e COUNTRY02 preservados.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json,Disponibilizado — especialização preparatória; enquadramento regulatório específico pendente,"Disposição, versão, período, licença, capital mínimo, taxa e prazo específicos por atividade ainda por determinar; não bloqueiam preparação independente.","Decisão Tempo para ativo; backup/restauro fresco, conta administrativa autenticada, scan e hashes compatíveis.","Cenários A tecnológico e B com pagamentos declarados: guardar incompleto, recuperar noutra sessão, países/localização/documentos, resultados isolados, apoio/tarefas, revisão seletiva, sem ato externo fictício; teclado/foco/erros/móvel no delta.",Atual — delta autorizado QA,,,,,"Navegador QA: A/B, países MZ/ZA, confirmação e erro com rótulo/foco/campos preservados; móvel 390px sem overflow.",67 serviços/controllers; 38 HTTP; 20 fecho delta; oito recuperação final.,"Payload cifrado existente, versão otimista, replay idempotente e histórico/eventos preservados.","Novos logins HTTP/visual A/B; mesmos documentos, resultados, apoio e tarefas; setor/artigo guardados.","Aplicabilidade preparatória por declaração; situação jurídica específica indeterminada sem taxa, licença ou score inventados.",Especialização preparatória ativa; enquadramento regulatório específico permanece pendente.,,,"Pedido expresso Tempo; só necessidade específica nova recebe novo ID. Limites por fonte/ação. | Disponibilização expressamente autorizada pela Tempo: «Autorizo a disponibilizar». Executada com backup/restauro fresco verificado; apenas conferência operacional, sem repetir aceitação QA. | Correspondência documental 15/10/2026: 14 linhas atividade/requisito/artigo/suporte/etapa/lacuna; cinco diplomas do acervo aceite; sem revalidar proveniência.
[RECONCILIACAO-43-20261019] 7: Faltam parâmetros/fontes aplicáveis por operação e período. Não bloqueiam preparação. Activação de cálculos não decorre de publicação.","Enquadramento regulatório completo mantém-se pendente: qualificar operações e entidades; avisos/capitais/limites por atividade/período; regras de valores mobiliários/BVM; atos reais e vistoria; regulação TIC/câmbio/BCFT complementar. Correspondência textual já disponível na tabela de 14 linhas, sem bloqueio da preparação. Corrigir minutas que misturam consultoria/ativos virtuais; guias com diplomas expressamente revogados não são checklist atual. Reconciliar autorização prévia de constituição (L20 art.16) com preparação S05/S08; não é falha funcional demonstrada. | Recorte QA demonstrado, sem encerrar critérios globais. Histórico económico combinado conservado, fora de novas escolhas; oportunidade6 não inferida como Fintech. Sem fusões por nome. Recuperação existente conferida por leitura e hashes; outra sessão/dispositivo e percursos aceites não reensaiados. Conferência dos anexos pelo utilizador pendente. | Recorte aprovado disponibilizado; requisitos globais permanecem abertos. Atividade historica combinada e oportunidade6 sem reclassificacao. Conferencia dos anexos finais pelo utilizador pendente. Sem repetir testes aceites, formularios ou L1.
diff --git a/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md b/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md
index c2003dcb..5f59cfb5 100644
--- a/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md
+++ b/docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md
@@ -11,6 +11,9 @@ A [consulta por todos os IDs](../../../../outputs/investmoz-saldo-atual-20261018
As faixas são previsões para o **próximo resultado delimitado**, de confiança baixa onde indicadas. Não são horas consumidas, prazo contratado nem soma global. Esperas por dados ou decisões não são convertidas em horas. Trabalhos e critérios partilhados não podem ser somados por ID. Os orçamentos históricos globais, incluindo B25–43 h, não são saldo atual.
+
+Actualização de 02/11/2026: as linhas e secções de Fundos e Educação abaixo incorporam os incrementos locais posteriores. O cabeçalho e as descrições anteriores conservam a sua data histórica; não substituem os recibos actuais nem comprovam instalação do código novo no destino.
+
### Visão para decisão
| Frente e IDs existentes | Situação e próximo resultado verificável | Estimativa restante do próximo recorte |
@@ -27,14 +30,14 @@ As faixas são previsões para o **próximo resultado delimitado**, de confianç
| Percurso B e workflows base — AUD-OP-03, AUD-OP-04, AUD-GUIDE-01, AUD-DESK-02 | Ativo parcial; 12 critérios B aceites preservados. Delimitar uma variante/contrato ainda aberto e a diferença exata para o contrato aceite; decisão §27 só onde material e ainda ausente. | 2–4 h para delimitar o primeiro delta; implementação e QA desse delta só depois. A faixa histórica25–43 h de B não é saldo atual. |
| Fiscal/contributivo e exportações — AUD-SIM-01, AUD-SIM-02 | Parcial; desenvolvimento e parâmetros restantes. Um cenário por tributo/contribuição, com fonte/período/parâmetros explícitos, comportamento indeterminado quando faltar dado e exportação recuperável. | 16–32 h para um lote delimitado com parâmetros disponíveis, faixa histórica mantida como previsão de baixa confiança; cobertura fiscal integral e espera por parâmetros: indeterminadas. |
| Negócios existentes e classificação — AUD-BIZ-01, AUD-DASH-01, AUD-STATS-01 | Ativo parcial; limites fora da entrega preservados. Delimitar a modalidade/consumidor restante e a prova positiva de cadeia disponível; observação UUID quando houver objeto legítimo autorizado. | 2–4 h para delimitar primeiro delta; 4–8 h por modalidade delimitada como previsão inicial. Observação dependente de anúncio próprio legítimo: espera não estimada. |
-| Negócios similares — AUD-MARKET-01 | Desenvolvimento em falta. Consulta QA com um caso positivo e um sem cobertura, sem inventar negócio/localização. | 8–16 h para um primeiro consumidor com coordenadas/classificação disponíveis; cobertura real depende dos dados. |
-| Importação de empresas/empreendimentos — AUD-ESTABLISHMENT-01 | Desenvolvimento em falta e dependência de correspondências. Um lote QA nominal do inventário com recibo, conflitos explícitos e replay sem novas linhas. | 8–16 h por primeiro formato/lote delimitado; não somar mecanismo de duplicados quando partilhado. Restantes formatos dependem do inventário. |
-| Fundos — AUD-FUND-01 | Desenvolvimento em falta e dados. Um fundo documentado com prazo conhecido/desconhecido e limites de elegibilidade sem aprovação automática. | 8–16 h para primeiro lote delimitado com dados, faixa histórica preliminar; atualização de todo o universo não estimada. |
-| Comparador societário e modelos — AUD-COMPANY-01, AUD-COMPANY-02 | Desenvolvimento/documentos restantes. Um ramo comparativo e um modelo identificado/recuperável; alternativas e dados ausentes explícitos. | 8–16 h para primeiro conjunto delimitado com modelos/fontes disponíveis, faixa histórica partilhada pelos dois IDs. Sem exemplares: prazo indeterminado. |
-| Capitalização/private equity e Bolsa — AUD-CAPITAL-01, AUD-CAPITAL-02 | Desenvolvimento/documentação restantes. Um guião documentado por âmbito com percurso, lacunas e ações no dossier. | 8–16 h para primeiro conjunto delimitado, faixa histórica partilhada pelos dois IDs. Cobertura integral depende de fontes/âmbito. |
-| Checklists versionadas — AUD-CHECKLIST-01 | Implementação parcial; editor em falta. Publicar v2 sem alterar respostas/submissões de v1; recuperar ambas em QA. | 8–16 h para um primeiro tipo de checklist, faixa histórica preliminar. |
-| Indicadores de utilização — AUD-HUMAN-03, AUD-STATS-01 | Desenvolvimento e definição de métricas. Um indicador observável com evento/denominador auditáveis e ausência de dados distinta de zero. | 4–8 h após definição do primeiro conjunto, faixa histórica preliminar; espera por decisão não convertida em horas. |
-| Jornadas educativas — AUD-EDU-01 | Implementação parcial; desenvolvimento restante. Um percurso educativo com rascunho, nova sessão e acesso por ator em QA. | 12–24 h para primeiro percurso delimitado, faixa histórica preliminar; variantes adicionais não incluídas. |
+| Negócios similares — AUD-MARKET-01 | Parcial local: raio/sector/classificação e alimentação pelo formulário/publicação normal, fontes/datas/histórico; 28 Feature/677 e 17 frontend. | Restam cobertura real, visual e disponibilização; competências/alterações de anúncios publicados mantidas. |
+| Importação de empresas/empreendimentos — AUD-ESTABLISHMENT-01 | Parcial: lote privado específico entregue em28/10; consulta de fontes/linhas/pendências acrescentada em02/11, sem fundir empresas. | Restam reconciliação de entidades, outros formatos e visual/destino do delta. Faixa anterior não é orçamento novo do lote concluído. |
+| Fundos — AUD-FUND-01 | Parcial local: catálogo/editor versionado, filtros, critérios explicados, guardados/alertas e concorrência implementados. Provas de36 Feature/612 asserções, oito frontend e nove cenários concorrentes preservadas. | Restam fontes/cobertura reais, vínculos sectoriais/cartográficos, visual e disponibilização/agendador; faixas antigas não são novo orçamento do motor concluído. |
+| Comparador societário e modelos — AUD-COMPANY-01, AUD-COMPANY-02 | Parcial local: comparador informativo público/dossier com fontes e história; 14 Feature/385 e seis frontend. Modelos específicos continuam sem entrega demonstrada. | Restam casos especiais, modelos, visual/login real e disponibilização. Faixa anterior não é novo orçamento do comparador concluído localmente. |
+| Capitalização/private equity e Bolsa — AUD-CAPITAL-01, AUD-CAPITAL-02 | Parcial local: guia de capitalização e guião BVM de cinco percursos, fontes/páginas e referências cifradas no mesmo dossier. BVM: 14 Feature/474,18 frontend. | Montantes/encargos actuais, procedimentos CVM recentes completos, casos especiais, visual/login real e disponibilização. Não reorçamentar como ausentes os dois guiões já desenvolvidos. |
+| Checklists versionadas — AUD-CHECKLIST-01 | Parcial local: editor/vigência/tipos/recuperação, anexos com limites e selecção documental pesquisável no âmbito autorizado. | Outros consumidores/parametrização transversal, três camadas por fonte, visual e destino. |
+| Indicadores de utilização — MASTER-e1169a77-0018; AUD-HUMAN-03/AUD-STATS-01 separados | Painel factual, registo manual de experiências e contagens agregadas de pesquisa/zero resultados em nove canais, com edições e cobertura explícitas. | Restantes métricas/fontes, ligação aos editores/eventos e execução de variantes; pesos/pilotos concretos, visual/login e disponibilização. |
+| Jornadas educativas — AUD-EDU-01, AUD-EDU-02, AUD-EDU-03 | Parcial local: rascunhos privados de procura/capacidade, formulários, snapshots e concorrência implementados;14 Feature/333 asserções, cinco frontend e dez cenários concorrentes preservados. | Restam painéis/perfis de AUD-EDU-03/01, visual e disponibilização; não repetir o motor de rascunhos. |
| Partilha documental individual e variantes de sala — AUD-OP-02, AUD-PART-01, AUD-SCAN-01 | Parcial; implementação/prova específicas restantes. Um documento partilhado/revogado por destinatário, nova sessão negada e original/histórico preservados, sem repetir os ramos já aceites. | 8–16 h para primeiro contrato de partilha individual; outras variantes após delimitação, sem somar provas comuns de scanner. |
| Restauro, modalidades e SLA — AUD-OP-01, AUD-PROFILE-18, AUD-PROFILE-22, AUD-PROFILE-32 | Dependência de decisão concreta; trabalho independente pode avançar. Proposta concreta de cada ramo com impacto/dados preservados, seguida da decisão da Tempo. Separar regra organizacional de escolha técnica. | 2–4 h para uma proposta/contrato concreto; implementação após decisão depende do delta. Espera pela decisão: não estimada. |
| Cartografia e consumidores territoriais restantes — AUD-GEO-01, AUD-GEO-02, AUD-GEO-03, AUD-REL-01, AUD-REL-02 | Parcial; desenvolvimento/prova e dados restantes. Um consumidor ainda aberto com seleção, recuperação e legenda coerentes; tabela de correspondências com fonte, sem forçar pares. | 2–8 h por consumidor delimitado, como faixa anterior de reconciliação/ensaio; 173 casos históricos não são todos falhas de código nem multiplicador dessa faixa. Cobertura cartográfica integral indeterminada. |
@@ -217,113 +220,127 @@ Actualizacao local de 02/11/2026 — AUD-CHECKLIST-01: primeiro editor administr
**IDs:** AUD-MARKET-01.
-**Preservado:** Cadastros, território e classificação existentes reutilizáveis; catálogo genérico não é demonstração da pesquisa por raio.
+**Preservado/implementado localmente em 02/11/2026:** mesmo cadastro e classificação pública; área/raio/sector/modalidade/classificação combináveis. Distância geodésica apenas de ponto primário público exacto utilizável, sem centróides/geom privada; fonte/data de registo/cobertura e limites explícitos, filtros recuperáveis. Onze Feature/384 asserções e dez frontend aprovados, com verificações estáticas/compilação.
-**Saldo:** Pesquisa por área/raio/sector/classificação com origem, data, cobertura e limites.
+**Saldo actualizado em02/11/2026:** alimentação do ponto/fonte pelo formulário e publicação normal implementada; restam cobertura real, visual e disponibilização no destino. A data de registo não substitui a data da fonte; catálogo incompleto não significa ausência no mercado. Estado parcial, sem novo cadastro/migração ou publicação automática.
-**Próximo resultado:** Consulta QA com um caso positivo e um sem cobertura, sem inventar negócio/localização.
+**Próximo resultado:** retomar os restantes saldos funcionais da matriz; completar cobertura e observação visual/destino quando os recursos correspondentes estiverem disponíveis.
-**Previsão:** 8–16 h para um primeiro consumidor com coordenadas/classificação disponíveis; cobertura real depende dos dados. Base: Desdobramento novo do orçamento histórico12–24 h partilhado com importação; não somar sem retirar reutilização.
+**Previsão histórica:** 8–16 h para o primeiro consumidor, desdobramento do orçamento12–24 h partilhado com importação. Não é estimativa nova do saldo depois da implementação local.
-**Evidência:** [matriz-requisitos.csv](../../../../docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv).
+**Evidência actual:** recibo business_proximity_increment_20261102 em [local-validation-20261029.json](../../unification/local-validation-20261029.json), [manual](../../unification/traceability-and-manual.md) e linha existente da matriz; provas históricas mantidas na matriz.
#### 14. Importação de empresas/empreendimentos
**IDs:** AUD-ESTABLISHMENT-01.
-**Preservado:** Ficheiros inventariados e importadores privados existentes não autorizam divulgação automática.
+**Preservado:** lote privado específico já entregue em28/10, com fonte/hash/linha, repetições conservadas, idempotência e recuperação demonstradas.361464 observações não são empresas únicas. O recibo histórico proactive-supply-git-delivery-20261028.json prevalece sobre a indicação anterior de ausência do importador.
-**Saldo:** Importador específico com normalização, prévia, rejeições, proveniência, idempotência e correspondências inequívocas.
+**Acrescentado localmente:** consulta privada de fontes/linhas e pendências territoriais/de identidade, referências recuperáveis e indicadores de cobertura. Corrigidas respostas antigas ao mudar de contexto. Nove Feature/138, seis frontend e verificações estáticas/build; onze tabelas QA preservadas.
-**Próximo resultado:** Um lote QA nominal do inventário com recibo, conflitos explícitos e replay sem novas linhas.
+**Saldo:** reconciliação/consolidação de entidades, outros formatos/lotes delimitados e observação visual/disponibilização do delta. Consulta não aplica correspondências nem publica empresas; dados incompletos não provam ausência de mercado.
-**Previsão:** 8–16 h por primeiro formato/lote delimitado; não somar mecanismo de duplicados quando partilhado. Restantes formatos dependem do inventário. Base: Planeamento novo do primeiro lote; dados e publicação fora da faixa.
+**Próximo resultado:** reutilizar o importador e as fontes aceites no recorte concreto seguinte, conservando ambiguidades, história e autorização; não criar importador paralelo.
-**Evidência:** [matriz-requisitos.csv](../../../../docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv).
+**Previsão histórica:**8–16 h para primeiro formato/lote; não é orçamento novo do lote já concluído ou deste delta. Reestimar apenas o saldo delimitado, sem duplicar o mecanismo partilhado de reconciliação.
+
+**Evidência actual:** recibo proactive_supply_review_increment_20261102 em local-validation-20261029.json, manual e matriz existentes, com as provas históricas preservadas.
#### 15. Fundos
**IDs:** AUD-FUND-01.
-**Preservado:** Biblioteca e preparação financeira existentes; ofertas experimentais não equivalem a catálogo de fundos.
+**Implementado localmente:** catálogo e editor versionado, fonte/data e prazos conhecidos ou indeterminados, filtros territoriais/sectoriais, critérios explicados, guardados e alertas internos. A conferência de critérios não aprova elegibilidade ou financiamento. Reutiliza as permissões, auditoria e mecanismos existentes.
-**Saldo:** Catálogo com janelas, territórios, elegibilidade explicada, origem e atualização.
+**Provas preservadas:** 36 Feature/612 asserções, oito frontend e nove cenários reais de concorrência em QA sintética, nos recibos funding_alerts_increment_20261102 e funding_assessment_concurrency_increment_20261102. Fontes de código conferidas por hash em 02/11; não são testes novos ou prova de instalação no activo.
-**Próximo resultado:** Um fundo documentado com prazo conhecido/desconhecido e limites de elegibilidade sem aprovação automática.
+**Saldo:** cobertura/fontes concretas dos programas, vínculos sectoriais/cartográficos da referência, observação visual e disponibilização/agendador no destino. Canais externos permanecem fora da integração demonstrada. A referência documental disponível não equivale a todos os dados operacionais de um programa.
-**Previsão:** 8–16 h para primeiro lote delimitado com dados, faixa histórica preliminar; atualização de todo o universo não estimada. Base: Orçamento histórico específico, confiança baixa.
+**Próximo resultado:** continuar a partir do motor existente e do recorte documental concreto, preservando desconhecidos, versões e autoridade; não desenvolver outro catálogo.
-**Evidência:** [visao-consolidada-modulos.md](../../../../docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md).
+**Previsão histórica:**8–16 h para primeiro lote delimitado; a faixa não é novo orçamento das funcionalidades já desenvolvidas. Saldo de fontes/destino depende do recorte concreto.
+
+**Evidência actual:** manual, matriz e [recibos locais existentes](../../unification/local-validation-20261029.json).
#### 16. Comparador societário e modelos
**IDs:** AUD-COMPANY-01, AUD-COMPANY-02.
-**Preservado:** Biblioteca e formulários comuns reutilizáveis; não foram localizados exemplares específicos suficientes para declarar modelos entregues.
+**Implementado localmente:** comparador informativo com perguntas aplicáveis, alternativas/fundamentos da edição legal citada e preferência sem decisão automática. Consulta pública, escolha/criação explícita de dossier, snapshots cifrados e histórico recuperável; sem reescrever identidade ou etapas. Fonte oficial republicada conservada por hash.
-**Saldo:** Comparador orientado por perguntas e modelos versionados por forma jurídica, com fundamentos e limites.
+**Provas:** 14 Feature/385 asserções, seis frontend e verificações estáticas/compilação aprovados; recibo company_comparison_increment_20261102 no manual/matriz existentes. Sem instalação remota ou aceitação visual declarada.
-**Próximo resultado:** Um ramo comparativo e um modelo identificado/recuperável; alternativas e dados ausentes explícitos.
+**Saldo:** modelos específicos de AUD-COMPANY-02, casos especiais/redacções adicionais, observação visual/login real e disponibilização. Preparação factual privada em sete secções entregue localmente com histórico e capital exacto (recibo company_preparation_increment_20261102). Biblioteca genérica, comparador e ficha factual não são os sete exemplares de contratos; estes continuam pendentes, sem URL actualmente disponível pelo proprietário.
-**Previsão:** 8–16 h para primeiro conjunto delimitado com modelos/fontes disponíveis, faixa histórica partilhada pelos dois IDs. Sem exemplares: prazo indeterminado. Base: Orçamento histórico específico; não duplicar por requisito.
+**Próximo resultado:** delimitar o modelo/guia concreto e reutilizar o motor documental/versionamento e o contexto já criado; preservar originais, fontes e interpretações anteriores.
-**Evidência:** [visao-consolidada-modulos.md](../../../../docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md).
+**Previsão histórica:**8–16 h para o primeiro conjunto; não é orçamento novo do comparador já desenvolvido. Sem exemplares específicos, a faixa dos modelos permanece dependente do recorte real.
+
+**Evidência actual:** [recibos locais](../../unification/local-validation-20261029.json), manual e matriz existentes.
#### 17. Capitalização/private equity e Bolsa
**IDs:** AUD-CAPITAL-01, AUD-CAPITAL-02.
-**Preservado:** Conteúdos/fontes existentes, sem alegar admissão ou financiamento garantidos.
+**Implementado localmente:** guia de capitalização e guião BVM, ambos públicos e ligados ao dossier pelo mesmo mecanismo de referências cifradas. BVM: cinco percursos de acções/obrigações por segmento, seis etapas e intervenientes, requisitos/dispensas/documentos por âmbito com fonte/artigo/redacção/página. Documentos comuns aparecem uma vez; referências de guias diferentes conservam edição/histórico próprios.
-**Saldo:** Guiões com intervenientes, preparação, riscos, documentos e requisitos por segmento/âmbito.
+**Provas BVM:** 14 Feature/474 asserções e 18 frontend, PHPStan/Pint/tipos/lint/build; recibo bvm_admission_increment_20261103. O recibo capital_guidance_increment_20261102 permanece como prova anterior do guia de capitalização. Fontes oficiais recuperadas e pontos críticos dos PDF conferidos visualmente; não é prova visual da aplicação.
-**Próximo resultado:** Um guião documentado por âmbito com percurso, lacunas e ações no dossier.
+**Saldo concreto:** montantes anuais/encargos actuais, procedimentos operacionais CVM recentes completos, regimes especiais/alterações posteriores não abrangidos, observação visual/login real e disponibilização. Os mínimos de 2024, válidos até 31/03/2025, ficam históricos, sem montante actual calculado ou zero por defeito. Guiões não concedem financiamento, registo ou admissão.
-**Previsão:** 8–16 h para primeiro conjunto delimitado, faixa histórica partilhada pelos dois IDs. Cobertura integral depende de fontes/âmbito. Base: Orçamento histórico específico, confiança baixa.
+**Próximo resultado:** continuar os restantes saldos autorizados; recuperar as fontes específicas pendentes para actualizar os guias sem reescrever as referências guardadas.
-**Evidência:** [visao-consolidada-modulos.md](../../../../docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md).
+**Previsão histórica:** 8–16 h partilhadas pelos dois IDs; não é novo orçamento dos guiões base já demonstrados. Saldos dependem do âmbito/fontes em falta.
+
+**Evidência actual:** [recibos locais](../../unification/local-validation-20261029.json), manual e matriz existentes.
#### 18. Checklists versionadas
**IDs:** AUD-CHECKLIST-01.
-**Preservado:** Checklists de configuração existentes.
+**Preservado/implementado localmente:** editor/histórico/vigência, selecção múltipla/declarações, recuperação automática privada e anexos com limites por edição, condições/obrigatórios, original/scan/hash/cifra e snapshot/recibo. Formulário geral e perguntas de anexos pesquisam por nome/referência/dossier e seleccionam a origem exacta dentro da autoridade já existente: próprio uploader, dossier actual ou dossiers pessoais. Referência/datas/proveniência são reutilizadas sem nova cópia física e sem expor dados de fontes organizacionais alheias. Suporte da etapa usa vínculo por nome e conserva a origem utilizada; clientes antigos continuam disponíveis.
-**Saldo:** Editor administrativo sem código, publicação/versionamento e preservação de submissões anteriores.
+**Saldo:** outros consumidores/contextos e configuração transversal de limites/formatos/mensagens, obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização no destino. Quatro MIME/tectos técnicos actuais não são parametrização integral. Preparação/conferência interna não são homologação ou acto oficial.
-**Próximo resultado:** Publicar v2 sem alterar respostas/submissões de v1; recuperar ambas em QA.
+**Próximo resultado:** conferir os restantes consumidores documentais e critérios p481/p161 sobre os motores/cadastros existentes. Não repetir o saldo geral de UUID agora resolvido como capacidade ausente.
-**Previsão:** 8–16 h para um primeiro tipo de checklist, faixa histórica preliminar. Base: Orçamento histórico específico.
+**Provas:** 56 Feature/766 e 40 frontend; estática/tipos/lint/build aprovados. 16 tabelas QA vazias/owner/RLS/índices; prova anterior de concorrência preservada, sem novo ensaio alegado. Recibo desk_document_reuse_increment_20261103. Sem nova migração ou escrita activa; visual/destino pendentes.
-**Evidência:** [matriz-requisitos.csv](../../../../docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv).
+**Previsão histórica:** 8–16h para primeiro tipo; não reorçamentar o que já foi demonstrado.
#### 19. Indicadores de utilização
-**IDs:** AUD-HUMAN-03, AUD-STATS-01.
+**IDs:** MASTER-e1169a77-0018; AUD-HUMAN-03/AUD-STATS-01 com âmbitos próprios.
-**Preservado:** Contagens internas existentes; não são score de sucesso ou pessoas únicas.
+**Implementado localmente:** painel factual e registo manual de experiências já demonstrados, agora com respostas de pesquisa/zero resultados em nove canais públicos. Contagens diárias sem termos/valores/identificadores, edições/definições históricas separadas, base/cobertura/exclusões visíveis, taxa só entre respostas registadas e exportação recuperável. Recolha não invalida pesquisa quando falha, respeita sinais de privacidade e limites técnicos do chamador. Relatórios anexados a experiências continuam contexto, sem causalidade ou grupos inferidos.
-**Saldo:** Definir eventos, denominadores, baseline, deduplicação e apresentação; pesos de sucesso não aprovados.
+**Provas da pesquisa:** 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build; duas conexões para limite de bloqueio e dois processos realmente sobrepostos com200 incrementos/150 zeros conservados. Recibo public_search_metrics_increment_20261103. Provas anteriores do painel/registo, estatísticas por origem e pesquisa rápida preservadas.
-**Próximo resultado:** Um indicador observável com evento/denominador auditáveis e ausência de dados distinta de zero.
+**Saldo concreto:** fontes de pesquisa não instrumentadas/medição integral, aquisição/activação, comparação pública, percurso CRM, investimento confirmado, conclusão versionada do roteiro, tempos de projecto/etapas, abandono, satisfação/suporte e pós-investimento. Ligação transversal de editores/alterações e execução/eventos de variantes pendentes. Pesos/pilotos de AUD-HUMAN-03 mantêm definição específica, sem bloquear métricas factuais. Visual/login real e disponibilização/migração no destino pendentes.
-**Previsão:** 4–8 h após definição do primeiro conjunto, faixa histórica preliminar; espera por decisão não convertida em horas. Base: Orçamento histórico específico; métricas constituem decisão de produto da Tempo.
+**Limites:** contagens são respostas registadas, não pessoas/pesquisas únicas; refresh, bots/cache e recolha best effort impedem afirmar cobertura total. Dias UTC, hoje parcial, base temporal própria em vez de corte por subsegundo. Filtro de serviço não é estendido às pesquisas por inferência; sem dados não é zero.
-**Evidência:** [matriz-requisitos.csv](../../../../docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv).
+**Próximo resultado:** continuar os indicadores/fontes e ligações efectivamente autorizados, preservando transparência, consentimento, segurança e igualdade.
+
+**Previsão histórica:**4–8 h para primeiro conjunto; não reorçamentar painel/registo/recolha demonstrados como ausentes. Saldo integral sem previsão sustentada.
+
+**Evidência:** matriz, manual e [recibos locais](../../unification/local-validation-20261029.json).
#### 20. Jornadas educativas
-**IDs:** AUD-EDU-01.
+**IDs:** AUD-EDU-01, AUD-EDU-02, AUD-EDU-03.
-**Preservado:** Catálogo e serviços educativos parciais.
+**Implementado localmente:** rascunhos incompletos privados de procura de trabalhadores/capacidade formativa, dono/tipo/versão, guarda e recuperação pelos formulários existentes, conflito sem perder edições e snapshots da submissão. A declaração completa segue a revisão independente anterior; rascunhos não entram nos agregados. Sem zeros ou datas fictícios.
-**Saldo:** Procura/capacidade com rascunho incompleto e painéis por ator, recuperação e ações pertinentes.
+**Provas preservadas:**14 Feature/333 asserções, cinco frontend e dez cenários concorrentes em QA sintética. A linha AUD-EDU-02 foi reconciliada com estes incrementos de AUD-EDU-01; os hashes das seis fontes e dos logs foram conferidos, sem repetir o desenvolvimento.
-**Próximo resultado:** Um percurso educativo com rascunho, nova sessão e acesso por ator em QA.
+**Saldo:** painéis e restantes perfis de AUD-EDU-03/01, observação visual e disponibilização. O rascunho já implementado não é outra jornada por desenvolver.
-**Previsão:** 12–24 h para primeiro percurso delimitado, faixa histórica preliminar; variantes adicionais não incluídas. Base: Orçamento histórico específico.
+**Próximo resultado:** confrontar os painéis/perfis restantes com o acesso existente, conservando as competências e os dados anteriores.
-**Evidência:** [visao-consolidada-modulos.md](../../../../docs/investmoz/v2/auditoria-portal/visao-consolidada-modulos.md).
+**Previsão histórica:**12–24 h para primeiro percurso; não é novo orçamento do motor já concluído. Reestimar apenas o saldo delimitado.
+
+**Evidência actual:** manual, matriz e recibos education_drafts_ui_increment_20261102, education_drafts_concurrency_increment_20261102 e education_draft_requirement_reconciliation_20261102 em [recibos locais existentes](../../unification/local-validation-20261029.json).
#### 21. Partilha documental individual e variantes de sala
@@ -624,7 +641,7 @@ Estimativas de trabalho técnico restante, incluindo implementação localizada,
| Países/origem/estatísticas — AUD-COUNTRY-01…07, AUD-STATS | Catálogo ISO, fluxos anteriores, C133; filtros/filas de oportunidades. COUNTRY02 ativo, duas colunas e histórico preservados. | Consumidores fundiário/Balcão/declarações e combinações restantes; C134visual; país mestre real da Tempo aindaNULL, não inferir peloNUIT/contacto. Publicação do anúncio C133 não demonstrada pelo workflow. | Campo correto e separado→gravação→nova sessão→submissão/replay→filtro/estatística sem duplicação, por formulário pertinente. | **6–10h**; preenchimento real é ação legítima posterior, não pré-condição para instalar extensão. |
| Territórios/seletores/mapas — AUD-GEO/REL/FIELD | Hierarquia/API; mapas/coedição de recursos anteriores; QA56 quatro níveis e rejeições422. Limite INE em província/distrito/posto; localidade sem geometria própria. | Restam consumidores de zonas, carteira, parcerias, catálogo, Balcão/fundiário/educação e visuais.173 correspondências:0províncias/26distritos/147postos; Mandie/Guro ambíguo. Fonte não oferece localidades/parcelas. Ativo sem camadas importadas por este lote. | Seleção/limpeza de filhos/persistência/legenda/ausência de geometria corretas; publicar camadas só por ação separada. | **10–18h** consumidores e correspondências inequívocas iniciais; fecho dos173indeterminados não incluído. |
| Dossier/percurso — cinco fases/19etapas, AUD-DESK-02/AUD-SIM | A/B integrado encerrado no âmbito definido; ferramenta devolve resultado ao dossier, isolamento e preparação paralela. | Restantes variantes/etapas não encerradas pelos dois cenários.190000 está separado da ativação atual e entra na disponibilização do percurso; não bloqueia workflow isolado. | Rastrear cada etapa/estado/contexto ainda não provado sem renumerar roteiros; conservar acesso direto a ferramentas e dados únicos. | **4–8h** variantes existentes/compatibilidade; instalação ativa separada. |
-| Balcão/orientação/CRM — AUD-DESK/CRM/GUIDE | Apoio e acompanhamento em A/B; casos/fontes/recuperações anteriores. Não depende de CRM externo. | Origem/atribuições/próxima ação/documentos por consumidor; recibo atualTXT não é PDF. Orientação exige regra/período/parâmetro aplicável, sem questionar novamente a credibilidade da fonte oficial. | Pedido→receção/acompanhamento→resultado/documento recuperável por titular/analista autorizado, com formato real explicado. | **4–8h**, integrado na faixa documental14–28h. |
+| Balcão/orientação/CRM — AUD-DESK/CRM/GUIDE | Apoio e acompanhamento em A/B; casos/fontes/recuperações anteriores. Não depende de CRM externo. | Origem/atribuições/próxima ação/documentos por consumidor; recibo atualTXT não é PDF. Orientação exige regra/período/parâmetro aplicável, sem questionar novamente a credibilidade da fonte oficial. [CRM-TASK-CREATION-20261103] Recuperação da criação de tarefas CRM sem duplicar a tarefa/eventos de negócio e sem apagar edições feitas durante o envio. 77 Feature/877 asserções (10 novos), confirmação final sobreposta10/79;1545 frontend (12 novos),41 focados. PHPStan/Pint/tipos/formato/lint/build aprovados. QA45 vazias com owner/RLS/lock conferidos; índice único novo somente em QA. 77 recibos/266 provas anteriores preservados. Recibo crm_task_creation_increment_20261103; parcial, sem instalação/escritas no activo. [CRM-TASK-PREPARATION-20261103] Preparação de nova tarefa CRM cifrada, por conta/lead, com gravação automática, comparação antes de adoptar e retoma do envio original sem duplicar. 48 Feature/369 asserções antes da última normalização;14/123 específicos finais sobrepostos em13 casos (14 novos no total).57 frontend actuais (16 novos,41 sobrepostos com a ronda integral anterior1545, que não foi repetida). PHPStan/Pint/tipos/formato/lint/build aprovados. QA46 vazias/owner/RLS/lock;1 tabela nova somente em QA.78 recibos/278 provas anteriores preservados. Recibo crm_task_preparation_increment_20261103; parcial, sem instalação/escritas no activo.| Pedido→receção/acompanhamento→resultado/documento recuperável por titular/analista autorizado, com formato real explicado. | **4–8h**, integrado na faixa documental14–28h. |
| Documentos/biblioteca — AUD-LIB/SCAN/OP-02 | Importação anterior preview/hash/scan/replay; originais privados; imagem/WebP; PDF fundiário visual anterior; PDF da licença e da sala com MIME/hash/scan próprio agora verificados. | Outros templates/geradores/formatos/limites e PDFs etiquetados; acervo completo ainda sem consulta de todos os exemplares. ACL individual de oportunidade desligada. Primeiro processo legítimo ativo não substituído por QA. | Original preservado→scan→derivada quando aplicável→recuperação autorizada→retirada/revogação; declarar separadamente PDF enviado, PDF do navegador e gerador servidor. | **6–12h**, integrado na faixa documental14–28h. |
| Negócios/bolsa/parcerias — AUD-BIZ/PART | C133 interesse/country/origem/SQL; sala1 anterior. Nova sala2 criada pelo fluxo existente, PDF concedido e retirado após cancelamento, sessão antiga/nova404 e original do autor200. | Publicação operacional/mandatos do anúncio de negócios; marcos/candidaturas/variantes. C137UI escondia retirada em sala fechada: corrigido/compilado QA, ainda visual. Sala não substitui contrato canónico de oportunidade. | Publicação legítima do consumidor, candidaturas/decisões fundamentadas e revogação efetiva por estado/perfil. | **4–8h**, integrado na faixa documental14–28h. |
| Simuladores — AUD-SIM | Resultado financeiro e retorno ao dossier em A/B; rascunhos recuperáveis. | Fiscal/contributivo ainda parcial; faltam correspondência de regras/artigos, parâmetros/períodos e cenários. Não usar zero/taxa recente para ausência. | Cada cálculo suportado explica aplicabilidade, fontes e cenários; caso indeterminado é identificado, sem aprovação/score inventado. | **16–32h preliminares** para regras suportadas/dados disponíveis; fora60–110h e sem compromisso de cobertura de parâmetros ausentes. |
@@ -734,14 +751,14 @@ Ativo: `https://portal-investidor.test`, entrega `2e2f16c83483`, código `a02ef2
| Módulo e requisitos de referência | Disponível no ativo | Demonstrado em QA / fechos conservados | Implementado sem cobertura completa; parcial ou ausente |
|---|---|---|---|
-| Autenticação, perfis e dashboard — AUD-PROFILE-01/05/06/09/15/24/26/31, AUD-DASH-01 | HTTPS, MFA, dupla de Superutilizadores, administração e atribuições operacionais. `/dashboard`, `/perfis/gestao`, `/minhas-oportunidades`, `/minhas-oportunidades/create`. Aurora Promotor interno da operação Tempo; Palmira Validador e Mario Publicador transversais às seis categorias. Os titulares 2/13 não recebem papéis operacionais automaticamente. | C37 QA18 encerrado por confirmação manual com logout/recuperação; bootstrap e onboarding concluídos. Coedição, negações, independência e atribuições têm provas específicas. | C132 ativo contido; entrega individual das novas entradas MFA e investigação ainda pendentes. Substituição/recuperação de titulares, todos os conflitos/revogações e privacidade/consentimentos não são encerrados pelo bootstrap. Recência MFA de 900 s é escolha técnica identificada, não nova regra organizacional aprovada. |
+| Autenticação, perfis e dashboard — AUD-PROFILE-01/05/06/09/15/24/26/31, AUD-DASH-01 | HTTPS, MFA, dupla de Superutilizadores, administração e atribuições operacionais. `/dashboard`, `/perfis/gestao`, `/minhas-oportunidades`, `/minhas-oportunidades/create`. Aurora Promotor interno da operação Tempo; Palmira Validador e Mario Publicador transversais às seis categorias. Os titulares 2/13 não recebem papéis operacionais automaticamente. | C37 QA18 encerrado por confirmação manual com logout/recuperação; bootstrap e onboarding concluídos. Coedição, negações, independência e atribuições têm provas específicas. [DASHBOARD-WORK-QUEUE-20261103] Fila pessoal com prazos/páginas/destinos reais e restrição de auditor no resumo;41 Feature finais,82 frontend/estática/build,26 tabelas QA vazias. Recibo dashboard_work_queue_increment_20261103. [CRM-NEXT-ACTION-20261103] Tarefa suspensa não substitui próxima acção e ambos os percursos respeitam a guarda;1 conclusão/1 recusa/1 tarefa futura conservada em concorrência real,75 Feature e2 finais sobrepostos,87 frontend/estática/build,29 tabelas QA vazias. Recibo crm_next_action_increment_20261103.| C132 ativo contido; entrega individual das novas entradas MFA e investigação ainda pendentes. Substituição/recuperação de titulares, todos os conflitos/revogações e privacidade/consentimentos não são encerrados pelo bootstrap. Recência MFA de 900 s é escolha técnica identificada, não nova regra organizacional aprovada. |
| Oportunidades e workflow — AUD-OP-01/02/03/04/05, AUD-PROFILE-08/11/12/28 | Seis categorias base habilitadas; gestão, rascunhos, recursos, revisão e publicação para os âmbitos atribuídos. `/management/opportunities`, `/minhas-oportunidades/{id}/edit`, `.../resources`, `.../view`. 030000 e 040000 instalados; COUNTRY02/050000 preservado. | Casos 30–35 e arrendamento 54 com correção, recuperação, revisão independente e publicação no âmbito ensaiado. Materialidade reabre gates específicos e conserva os restantes. Detalhe por categoria abaixo. | Response/§27 integral ainda incompleto (`normative_response_complete=false`). 519 propriedades no schema, 248 campos recuperados em GET; Create/Patch e variantes semânticas/documentais não encerrados. Restauração e partilha individual desligadas. C131 normalização de contactos corrigida apenas em QA. |
| Países, origem e estatísticas — AUD-COUNTRY-01…07, AUD-STATS-01 | COUNTRY02 ligado, duas colunas instaladas sem novos cadastros. País mestre de organização, residência e origem são conceitos distintos. Tempo já existe; país de constituição permanece NULL. `/investidor/profile`, `/management/opportunity-origin`, `/management/interests`, `/management/crm/leads`. | Catálogo ISO e percursos antes ensaiados conservam a prova. Filas: filtros por categoria/estado e contagens com persistência demonstrados. | O NULL não permite alegar gravação real do país mestre; preencher posteriormente pelo fluxo autorizado, sem adivinhar. Restam consumidores de negócios/fundiário/Balcão, origem após submissão/replay e estatísticas próprias. QA tem três negócios existentes e nenhum publicado: falta anúncio sintético pelo fluxo existente para o ensaio de interesse público. |
| Territórios, seletores e mapas — AUD-GEO-01…04, AUD-REL-01/02, AUD-FIELD | Rotas e seletores existem. `/oportunidades`, `/zonas`, `/carteira`, `/management/territory-geometry-import`, `.../territory-options`, `.../territory-geometries`. Ativo: zero geometrias importadas; cadastro territorial não é camada apresentada. | QA: 1.990 territórios e 408 geometrias INE internas: 11 províncias, 133 distritos, 264 postos. Editor de recursos ensaiado com limpeza de descendentes, rejeição de hierarquia estrangeira, coedição e recuperação do mapa. | Esperadas 581 correspondências (11/159/411): pendentes 173 (0/26/147), listadas por nome/código na reconciliação cartográfica existente. Mandie/Guro ambíguo. Restam zonas, carteira, educação, parcerias e catálogo público por consumidor. Importação e publicação são ações separadas, não autorizadas no ativo neste lote. |
| Dossier e percurso integrado — AUD-DESK-02, AUD-SIM-01/02, referências das cinco fases/19 etapas | A extensão 190000 do percurso integrado continua fora da ativação atual; não bloqueia o workflow isolado. Ferramentas mantêm acesso direto. | A/B encerrados nos critérios aceites: criação/gravação, recuperação noutra sessão, aplicabilidade, resultado financeiro no dossier correto, Balcão e tarefa independente enquanto terra aguarda informação. Cinco fases/19 etapas conservadas. | Disponibilização integrada não ativa; restantes etapas/variantes não cobertas pelos cenários A/B. Não confundir o fecho desses cenários com todo o motor, todas as regras ou a auditoria global. |
-| Balcão, orientação e CRM interno — AUD-DESK-01/02, AUD-CRM-01, AUD-GUIDE-01 | Rotas `/balcao-virtual`, `/balcao-virtual/dossiers/{id}`, `/balcao-virtual/pedidos/{id}` e acompanhamento `/management/crm/leads` existentes. Não depende de CRM externo para os percursos internos. | Preparação de apoio e acompanhamento incluídos nos cenários A/B e provas anteriores; GET atual complementa disponibilidade, sem provar botões/gravação. | Restam origens por formulário, atribuições/next action e documentos por consumidor. Fontes/âmbito/período da orientação precisam de correspondência concreta; importação oficial não ativa regra/cálculo. |
+| Balcão, orientação e CRM interno — AUD-DESK-01/02, AUD-CRM-01, AUD-GUIDE-01 | Rotas `/balcao-virtual`, `/balcao-virtual/dossiers/{id}`, `/balcao-virtual/pedidos/{id}` e acompanhamento `/management/crm/leads` existentes. Não depende de CRM externo para os percursos internos. | Preparação/apoio A/B preservados. [DESK-PAYMENT-EVIDENCE-20261103] Complemento/correcção de comprovativo no mesmo pagamento, valores/origem/histórico preservados e revisão independente; consulta em encerrados. 53 testes Feature/721 asserções, 47 frontend/estática/build e concorrência por referência: 1 registo/1 evento/conflito 409. Recibo desk_payment_evidence_increment_20261103, sem escrita activa. [DESK-CLOSED-LIFECYCLE-20261103] Coerência de encerrados em decisões/atribuições/mensagens/etapas/tarefas e CRM, cancelamento de rascunhos já autorizado agora por interface. 77 Feature e15 específicos finais sobrepostos,64 frontend/estática/build;20 tabelas QA vazias. Recibo desk_closed_lifecycle_increment_20261103. [CRM-RECORD-VERSIONS-20261103] Quatro editores CRM com revisão/comparação, conservação de alterações e controlo de concorrência;45 Feature/594,75 frontend/estática/build;1 gravação/1 conflito/1 evento em processos reais,23 tabelas QA vazias. Recibo crm_record_versions_increment_20261103. [DASHBOARD-WORK-QUEUE-20261103] Fila pessoal com prazos/páginas/destinos reais e restrição de auditor no resumo;41 Feature finais,82 frontend/estática/build,26 tabelas QA vazias. Recibo dashboard_work_queue_increment_20261103. [CRM-NEXT-ACTION-20261103] Tarefa suspensa não substitui próxima acção e ambos os percursos respeitam a guarda;1 conclusão/1 recusa/1 tarefa futura conservada em concorrência real,75 Feature e2 finais sobrepostos,87 frontend/estática/build,29 tabelas QA vazias. Recibo crm_next_action_increment_20261103.| Restam origens por formulário, atribuições/next action e documentos por consumidor. Fontes/âmbito/período da orientação precisam de correspondência concreta; importação oficial não ativa regra/cálculo. Fecho/reabertura integral pelo dono implementados conforme decisão expressa; visual/destino pendentes, sem bloquear restantes incrementos.|
| Documentos, biblioteca, scans e derivadas — AUD-LIB-01/02, AUD-SCAN-01, AUD-OP-02, AUD-PROFILE-17/26 | Scanner real responde PONG, ClamAV 1.5.4/28151 com assinaturas de 12/10. Serviços e limites PHP já disponibilizados; originais preservados. `/documentos`, anexos pelo consumidor autorizado. | Clone/QA demonstrou envio, scan, derivadas, recuperação, falha/repetição e ACLs de LocalService. Alias de gestão não contorna política; revogação nega sessão antiga/nova nos anexos ensaiados. | Primeiro processamento documental legítimo completo no destino continua pendente. Enumeração fresca do worker não conclusiva por ACL/Acesso Negado, sem consumir trabalhos ativos. ACL individual de ficheiro/partilha não habilitada; acesso segue oportunidade/grant, não Superutilizador universal. Restam PDFs/exportações/derivadas por tipo e consumidor e documentos etiquetados. |
-| Negócios existentes e Bolsa/parcerias — AUD-BIZ-01, AUD-PART-01 | Catálogos e ferramentas existentes: `/negocios`, `/management/negocios`, `/parcerias`. | Provas específicas de sala/permissões e materiais mantidas. HTTP atual demonstra transporte das rotas autorizadas, sem novas submissões/publicações. | Direitos/mandatos, manifestações/país/origem e estatísticas dos negócios existentes ainda incompletamente cobertos. Não confundir este catálogo com a categoria de oportunidade “venda de negócio”. Revogação da sala não demonstra partilha individual de todos os documentos do portal. |
+| Negócios existentes e Bolsa/parcerias — AUD-BIZ-01, AUD-PART-01 | Catálogos e ferramentas existentes: `/negocios`, `/management/negocios`, `/parcerias`. | Provas específicas de sala/permissões e materiais mantidas. HTTP atual demonstra transporte das rotas autorizadas, sem novas submissões/publicações. [PARTNERSHIP-EDITING-20261103] Edição conserva omissões e alterações, compara conflitos e recupera criação pela chave original/autoridade actual;19 Feature/148,103 frontend,concorrência1 efeito,QA45 e estática/build aprovados. Recibo partnership_editing_increment_20261103; cobertura parcial, sem entrega activa. [PARTNERSHIP-PARTICIPANTS-20261103] Responsáveis por nomes/partes e representação actual; histórico/revogação e substituição expressa,25 Feature/211,1413 frontend,QA45 e estática/build. Recibo partnership_participants_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-ROOM-RECOVERY-20261103] Sala conserva preparações e compara versões; repetições por actor/chave sem duplicar efeito ou partilha,34 Feature/310 e2/37 sobrepostos,1429 frontend,QA45 e concorrência real do marco com replay documental; estática/build aprovados. Recibo partnership_room_recovery_increment_20261103; parcial e sem entrega activa. [PARTNERSHIP-CANDIDACIES-20261103] Candidaturas por ID exacto e acesso efectivo, omissões/preparações conservadas, contexto revisto e repetição por chave;47 Feature/401,1451 frontend,QA45,concorrência1 submissão/1 recusa409 e estática/build aprovados. Recibo partnership_candidacies_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-HISTORY-20261103] Consulta privada de versões/decisões pelo âmbito histórico e acesso actual, contexto congelado e cursor cifrado;57 Feature/488,1460 frontend,QA45 e estática/build aprovados. Recibo partnership_history_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-DASHBOARD-20261103] Painel sem título privado e avisos por âmbito actual/histórico, encaminhados aos participantes operacionais vigentes;73 Feature/576,1466 frontend,QA45 e estática/build aprovados. Recibo partnership_dashboard_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-PUBLICATION-20261103] Publicação/moderação com motivo e contexto revisto, replay por actor/chave e snapshot privado;85 Feature/642,1482 frontend,QA45 e estática/build aprovados. Recibo partnership_publication_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-VERSIONS-20261103] Leitor privado de versões da publicação e captura de novas edições/criações, por âmbito histórico e cursor cifrado;97 Feature/739,1490 frontend,QA45 e estática/build aprovados. Recibo partnership_versions_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-DRAFT-RECOVERY-20261103] Edições sem resposta recuperáveis por tentativa/actor, contexto posterior comparado e preparação conservada;109 Feature/802,1502 frontend/28 focados,QA45 e estática/build aprovados. Recibo partnership_draft_recovery_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-AGREEMENTS-20261103] Acordos recuperáveis por tentativa, contexto proponente/candidato revisto, confirmações das duas partes e histórico preservado;121 Feature/905,1514 frontend/28 focados,QA45 e estática/build aprovados. Recibo partnership_agreements_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-AGREEMENT-HISTORY-20261103] Histórico privado do acordo e leitura legada robusta, com paginação/âmbitos e valores congelados;132 Feature/1009,1525 frontend/39 focados,QA45 e estática/build aprovados. Recibo partnership_agreement_history_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-AGREEMENT-PROJECTION-20261103] DTO corrente sem histórico privado, agregado e auditoria preservados;141 Feature/1146,39 frontend focados,QA45/estática aprovados;cliente/build anterior reutilizado. Recibo partnership_agreement_projection_increment_20261103; parcial, sem entrega activa. [PARTNERSHIP-PUBLICATION-SUMMARY-20261103] Síntese histórica de cinco entradas no detalhe, sem IDs/eventos brutos e com reservas do leitor;149 Feature/1247,1533 frontend/55 focados,QA45 e estática/build aprovados. Recibo partnership_publication_summary_increment_20261103; parcial, sem entrega activa.| Direitos/mandatos, manifestações/país/origem e estatísticas dos negócios existentes ainda incompletamente cobertos. Não confundir este catálogo com a categoria de oportunidade “venda de negócio”. Revogação da sala não demonstra partilha individual de todos os documentos do portal. |
| Simuladores — AUD-SIM-01/02 | `/Simulador`, `/simulador-fiscal` e rascunhos existentes. | Resultado financeiro associado ao dossier correto nos cenários A/B; rascunhos e recuperação previamente ensaiados. | Fiscal/contributivo por regras/artigos aplicáveis parcial. Não inventar taxas, períodos ou zero para parâmetros ausentes. Catálogo de fundos, comparador societário e guia da Bolsa não são substituídos pelo simulador financeiro. |
| Educação — AUD-EDU-01/02/03 | `/educacao`, `/management/education`, análise de procura/capacidade existentes. | Consultas/provas históricas têm alcance delimitado. | Rascunho incompleto privado de procura/capacidade e jornadas/painéis por ator não implementados. Seletor/mapa/recuperação em cada consumidor ainda por completar. Não iniciar novas jornadas antes das prioridades autorizadas. |
| Legado, acervo e identidade visual — AUD-LEG-01…07, AUD-LIB-01 | Gate legado continua OFF no ativo. Nenhuma divulgação nova. | Piloto público de agronegócio com autenticação só ao guardar, referência no dossier e nova sessão confirmado manualmente. Setores reutilizam biblioteca e componentes; Energia/Mineração distintos. Inventário histórico: 92 URLs e 50 versões de artigos. | Mercado Financeiro privado por corpo vazio; cobertura integral, imagens/anexos e contextos dos outros setores parcial. Artigos territoriais de Turismo sem associação geográfica automática. Móvel/acessibilidade por setor não encerrados pelo piloto. |
@@ -806,3 +823,62 @@ Continuidade local 02/11/2026 — Balcão: editor acompanhado de histórico pagi
Continuidade local 02/11/2026 — ACT-11: alertas no portal para novas disponibilizações do catálogo público, com preferências próprias, confirmação, frequência, cancelamento e correspondência pela pesquisa existente. Notificações de manifestações preservadas. Migração e comando de geração instaláveis, com agenda existente e sem canais externos. Concursos/incentivos de outros catálogos, disponibilização e verificação visual continuam pendentes. Provas/limites em `traceability-and-manual.md`, secção ACT-11 de 02/11/2026; nenhum fecho transversal.
Continuidade local 02/11/2026 — ACT-11: além de oportunidades, concursos podem ser escolhidos explicitamente para alertas de versões actualmente publicadas. Consulta, regime, estados, versões e direitos reutilizam o catálogo existente; preferências antigas mantêm somente oportunidades. Dados anteriores e notificações de manifestações conservados; 30 testes distintos/607 asserções e seis frontend aprovados. A pendência de concursos do recorte anterior foi implementada em QA; incentivos, canais externos, instalação/agendador e conferência visual continuam pendentes. Detalhes no manual existente, sem fecho transversal.
+
+Actualização 02/11/2026 — Fundos e apoios (AUD-FUND-01): catálogo e editor locais, versões/fontes/janelas, critérios informativos, interesses privados e integração voluntária nos alertas existentes. Estado parcial: provas detalhadas no manual/recibo funding_alerts_increment_20261102 (36 testes/612 asserções, seis frontend e verificações estáticas/compilação aprovadas). Sem canais/recolha externos ou instalação no activo; concorrência do gerador, visual e vínculos de referência por completar. Esta actualização reconcilia o saldo histórico de biblioteca apenas, sem declarar ACT-11/ACT-12 agregados concluídos.
+
+Actualização 02/11/2026 — Fundos/alertas: concorrência do gerador e preferências conferida em nove cenários com dois processos; perguntas aplicáveis do formulário corrigidas. Oito frontend, tipos/lint/compilação aprovados; PHP sem delta e provas anteriores reutilizadas após conferir hashes. Detalhes no recibo funding_assessment_concurrency_increment_20261102/manual. Concorrência antes pendente actualizada no recorte demonstrado; visual, vínculos e disponibilização continuam pendentes.
+
+Actualização 02/11/2026 — AUD-EDU-01: rascunhos por pessoa para procura/capacidade iniciados no núcleo/API, com corpo cifrado, recuperação, versão e submissão única; regras de submissão/revisão reutilizadas. 14 testes/291 asserções, PHPStan e Pint aprovados. Interface, restantes painéis/perfis, concorrência e visual pendentes; migração validada apenas em QA. Detalhes no manual e recibo education_drafts_increment_20261102; estado parcial preservado.
+
+Actualização 02/11/2026 — AUD-EDU-01: ligação aos formulários e recuperação privada implementadas localmente. Guarda incompletos, continua pelo mesmo ID, conserva campos/local em conflito e apresenta snapshot submetido sem novo envio. Lista própria paginada, no-store/histórico cifrado e recarga parcial dos indicadores. 14 testes/333 asserções, cinco frontend e verificações estáticas/compilação aprovados; provas no manual e recibo education_drafts_ui_increment_20261102. Restam concorrência, visual, restantes perfis/painéis e disponibilização; nenhuma migração no activo.
+
+Actualização 02/11/2026 — AUD-EDU-01: concorrência de rascunhos/submissões demonstrada em dez cenários com dois processos e bloqueios observados, para procura e capacidade. Repetições sem duplicação, versão obsoleta recusada, quatro declarações/snapshots e auditoria conservados; revisão independente mantida. Provas anteriores reutilizadas após conferir hashes, recibo education_drafts_concurrency_increment_20261102. Visual, outros perfis/painéis e disponibilização continuam pendentes; base activa intacta.
+
+
+Continuidade 02/11/2026 — AUD-MARKET-01: raio geodésico implementado na API e interface, combinado com sector/modalidade/classificação e área, com fonte/data de registo/cobertura explícitas. Apenas pontos primários públicos exactos; precisão territorial protegida e filtros recuperáveis. Onze Feature/384 asserções e dez frontend, análise estática/tipos/lint/Pint/compilação aprovados, incluindo revalidação de plantio de algodao. Recibo business_proximity_increment_20261102; detalhes e limites no manual. Restam cobertura/alimentação de pontos públicos, origem documental, visual e disponibilização. Sem alterações no activo.
+
+
+Continuidade 02/11/2026 — AUD-MARKET-01: alimentação do ponto pelo formulário privado e publicação normal ligadas, com opt-in/território/fonte, histórico cifrado e preservação de UUID/locais secundários. 28 Feature/677 asserções e 17 frontend, análise estática em cache isolada/tipos/lint/Pint/build aprovados. Recibo business_point_publication_increment_20261102; provas e limites no manual. Cobertura real, visual e destino pendentes; migração só em QA sintético, sem novos papéis/rotas/reabertura de anúncios publicados.
+
+
+Continuidade 02/11/2026 — AUD-CHECKLIST-01: entrada em vigor por data implementada no editor e reutilizada pelo catálogo/dossier/percurso/criação. Versões futuras listadas na gestão; dados e edições anteriores preservados. Corrigida repetição da publicação inicial com JSONB; 21 Feature/314 asserções e nove frontend, PHPStan/tipos/lint/Pint/build aprovados. Recibo desk_effective_dates_increment_20261102; detalhes e escolhas técnicas no manual. Outros contextos, visual e destino pendentes; nenhuma migração ou pessoa real no activo.
+
+
+Continuidade02/11/2026 — AUD-ESTABLISHMENT-01: reconciliada entrega privada de28/10 (361464 observações, não empresas únicas); importador não foi recriado. Novo visor privado de fontes/linhas/pendências, sem fusão ou publicação, e correcção de respostas antigas no contexto territorial. Nove Feature/138 asserções, seis frontend e verificações estáticas/build aprovados; onze tabelas QA preservadas. Recibo proactive_supply_review_increment_20261102. Restam reconciliação de entidades, outros formatos e visual/destino do delta; provas históricas preservadas no manual/matriz.
+
+
+Continuidade 02/11/2026 — AUD-OP-05: corrigida publicação de etapa opcional explicitamente limpa, preservando desconhecido, versão do catálogo e histórico; omissão e seis valores legados conservados. 15 Feature/371 asserções e Pint/PHPStan aprovados em QA exclusiva. Recibo maturity_publication_increment_20261102; sem interface/migração/activo alterados. Restam adopção explícita de legados, variantes/categorias restantes e visual/destino; provas anteriores de pesquisa mantidas.
+
+
+Continuidade 02/11/2026 — AUD-COMPANY-01: comparador base público e ligado ao dossier implementado, perguntas aplicáveis, fontes/artigos e snapshots históricos cifrados; sem mudar a identidade ou concluir etapas. 14 Feature/385, seis frontend e verificações estáticas/build aprovados. Recibo company_comparison_increment_20261102. Modelos AUD-COMPANY-02, casos especiais, visual/login real e disponibilização permanecem separados.
+
+
+Continuidade 02/11/2026 — AUD-COMPANY-02: preparação factual privada em sete secções implementada no dossier, com reutilização de origens, capital exacto, histórico cifrado e recuperação de conflitos. 18 Feature/343 e 12 frontend, estática/build aprovados; recibo company_preparation_increment_20261102. Os sete exemplares não foram fornecidos (proprietário sem URL neste momento); minutas/derivadas/revisão formal e instalação mantêm-se pendentes. Não confundir ficha com contrato.
+
+
+Continuidade 02/11/2026 — AUD-CAPITAL-01: guia público de capitalização ligado ao dossier, quatro instrumentos/riscos/preparação, cinco fontes por edição/hash e referências cifradas com histórico/retirada/recuperação. 21 Feature/524 e 13 frontend, estática/build aprovados; recibo capital_guidance_increment_20261102. Visual/login real e destino pendentes. AUD-CAPITAL-02 conserva o guião bolsista por segmento; não confundir guia informativo com financiamento/admissão.
+
+
+Continuidade 03/11/2026 — AUD-CAPITAL-02: guião BVM público/dossier com cinco percursos, seis etapas/intervenientes, fontes/artigos/páginas, documentação partilhada/específica e histórico cifrado existente. 14 Feature/474,18 frontend e estática/build aprovados; recibo bvm_admission_increment_20261103. Mínimos anuais/encargos actuais, procedimentos CVM recentes completos, casos especiais, visual/login real e destino mantêm-se pendentes. Valores expirados de2024 não activam critérios de2026.
+
+Actualização03/11/2026 — [EDUCATION-WORK-QUEUE-20261103] Painel interno dos gestores com acompanhamento próprio, revisão independente e detalhe contextual. Revisão fixa a versão analisada, exige comparação se mudou, conserva edições posteriores e repete a mesma tentativa sem nova decisão. Fundamentos anteriores/novos preservados em snapshot cifrado e consulta privada paginada. 30 Feature/629 asserções (16 novos,14 anteriores);22 frontend (17 novos,cinco anteriores). PHPStan/Pint/tipos/formato/lint/build aprovados;54 tabelas QA vazias, owner/RLS/lock conferidos.79 recibos/289 provas anteriores preservados. Recibo education_work_queue_increment_20261103. Parcial local, sem migração/escritas no activo. A indicação histórica de rascunho incompleto não implementado foi superada pelos incrementos aceites de02/11, já reconciliados em AUD-EDU-02. O painel interno de gestores está agora implementado neste recorte; continuam pendentes os restantes actores e os seus vínculos/consentimentos, que o proprietário confirmou não estarem documentados.
+
+Actualização03/11/2026 — [OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Registo automático de falhas técnicas de submissão/publicação, referência correlacionada, consulta própria e perfil próprio de Suporte técnico com fila por organização/tipo. Reutiliza auditoria append-only e atribuições existentes, sem aprovação ou acesso documental adicional.15 Feature/264 asserções (oito novos,sete anteriores);12 frontend (seis novos,seis anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Base final QA com59 tabelas vazias, owner/RLS/lock conferidos; primeira execução mista acompanhada separadamente.80 recibos/298 provas anteriores preservados. Recibo opportunity_technical_incidents_increment_20261103. Parcial local; migração do papel somente em QA, sem alterações no activo. Perfil próprio decidido pelo proprietário; tratamento e restantes alertas/instalador/entrega/visual mantêm saldo específico, sem voltar a declarar inexistente o registo/fila agora implementados.
+
+Actualização03/11/2026 — [TECHNICAL-INCIDENT-HANDLING-20261103] Tratamento de incidentes pelo perfil existente: assunção/substituição explícita, notas cifradas, devolução à fila, resolução e reabertura, histórico privado paginado e filtros pelo estado actual. Versão e tentativa identificada preservam notas e impedem repetição de efeitos.18 Feature/339 asserções (dez novos,oito anteriores);28 frontend (16 novos,12 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Um cenário com dois processos e espera real no incidente:200/409, replay só de leitura, investimento e raiz intactos. QA final59 tabelas vazias; prova concorrente retém só amostras sintéticas declaradas.81 recibos/306 provas anteriores preservados. Recibo technical_incident_handling_increment_20261103. Parcial local, zero novas migrações/escritas activas. Tratamento completo no recorte técnico descrito; retoma durável, alertas/outros pontos, instalador/entrega e visual conservam o saldo. Execução mista anterior encerrada e base conferida, sem converter diagnóstico falhado em aprovação global.
+
+Actualização03/11/2026 — [SUPPORT-PROFILE-INSTALLATION-20261103] Actualização do perfil de Suporte técnico integrada no instalador autenticado existente: prévia, MFA, provas do destino/código, confirmação e recibo idempotente. Schema e ledger partilham a mesma verificação no servidor e na disponibilidade do perfil.18 Feature finais/230 asserções (dez novos,oito do instalador anterior); regressão inicial36/569;30 frontend (15 novos,15 do tratamento anterior),PHPStan/Pint/tipos/formato/lint/build aprovados. Backup PostgreSQL e arquivo de candidato/original privado sintético efectivamente restaurados em QA: 190 tabelas,30 sequências,1567 ficheiros e três envelopes MFA legíveis. Actualização e repetição conservaram todas as tabelas salvo uma entrada de migração e um recibo; zero atribuições de suporte inferidas. QA de testes62 tabelas vazias.82 recibos/318 provas anteriores preservados. Recibo support_profile_installation_increment_20261103. Parcial local, sem instalação/escrita activa. Integração do instalador demonstrada; instalação no destino/visual, alertas/outros limites e retoma durável conservam saldo.
+
+Actualização03/11/2026 — [SUPPORT-INCIDENT-NOTICES-20261103] Avisos internos de incidentes por consultar para o Suporte técnico efectivo, com contador próprio na navegação, filtro antes da paginação e marca explícita de consulta por actor/raiz. A consulta não é tratamento, resolução, aprovação ou acesso documental.25 Feature finais/376 asserções (sete novos,18 de instalação anteriores);31 frontend (nove novos,22 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. QA62 tabelas vazias e identidade/owner/RLS/FORCE conferidos.83 recibos/330 provas anteriores preservados. Recibo support_incident_notices_increment_20261103. Parcial local, sem migração ou escrita activa. Avisos de novos incidentes por consultar implementados; outras alteracoes, limites tecnicos, instalacao/visual e retoma duravel conservam saldo.
+
+[RESOURCE-TECHNICAL-INCIDENTS-20261103] Incidentes de upload de documentos/imagens e preparação WebP integrados no mesmo suporte, avisos e tratamento por âmbito. Limpeza conservadora conserva originais referenciados e bytes de resultado incerto; falhas na limpeza não escondem o erro original.23 Feature/285 asserções (oito novos,cinco de recursos e dez do instalador); um caso adicional sem GD/duas asserções;37 frontend (seis novos,31 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. GD/WebP carregado apenas no processo CLI de QA; configuração normal sem alteração. QA64 tabelas vazias, com identidade/owner/RLS/FORCE conferidos.84 recibos/339 provas anteriores preservados. Recibo resource_technical_incidents_increment_20261103. Parcial local, sem migração ou escrita activa.
+
+[SCAN-TECHNICAL-INCIDENTS-20261103] Falhas no despacho e execução da análise de documentos ligadas ao Suporte técnico por contexto capturado e acesso actual. Tentativas e callbacks identificados no histórico existente; resultados antigos não substituem resultados posteriores, e falha de confirmação da fila não reverte um documento já limpo.30 Feature/365 asserções finais (15 novos,cinco de recursos,dez do instalador), com42/574 anteriores sobrepostos;43 frontend (seis novos). PHPStan/Pint/tipos/formato/lint/build aprovados.67 tabelas QA vazias. Uma mensagem de fila real consumida por outro processo, com ClamD deliberadamente indisponível: inconclusivo, quarentena, original cifrado intacto,zero temporários e incidente próprio.85 recibos/351 provas preservados;14 provas novas. Recibo scan_technical_incidents_increment_20261103. Parcial local,zero escrita/migração activa.
+
+[SCAN-RETRY-20261103] Repetição da análise distingue aceite, reserva existente, contexto alterado, envio não confirmado e envio diferido. Reserva existente não altera o documento nem duplica o pedido; falha tardia não sobrepõe clean/infected/scanning. Mesma autoridade documental, revalidada após commit, com auditoria da preparação e original preservado. Botão dos anexos de zonas usa resposta Inertia; avisos aparecem também na gestão documental.36 Feature/378 asserções (11 novos,15 de scans,dez do instalador),24/228 iniciais sobrepostos e47 frontend (quatro novos),PHPStan/Pint/tipos/formato/lint/build aprovados.69 tabelas QA vazias. Ensaio com reserva em cache PostgreSQL e fila reais: segundo pedido preservou190 tabelas; outro processo consumiu uma mensagem e libertou a reserva do seu dono. ClamD deliberadamente indisponível manteve quarentena, cifra e histórico,zero temporários.86 recibos/365 provas preservados;14 novas provas. Recibo scan_retry_increment_20261103. Parcial local,zero escrita/migração activa.
+
+[INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa.
+
+[ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa.
+
+[ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa.
diff --git a/resources/js/components/business-point-summary.tsx b/resources/js/components/business-point-summary.tsx
new file mode 100644
index 00000000..0225f173
--- /dev/null
+++ b/resources/js/components/business-point-summary.tsx
@@ -0,0 +1,131 @@
+import { businessPointApplicable } from '@/lib/business-locations';
+
+export type RegisteredBusinessLocation = {
+ id: string;
+ precision_level: string;
+ is_public: boolean;
+ has_geometry: boolean;
+ latitude: number | string | null;
+ longitude: number | string | null;
+};
+
+export default function BusinessPointSummary({
+ payload,
+ registered,
+ available = true,
+ published = false,
+ territoryLabel,
+}: {
+ payload: Record;
+ registered?: RegisteredBusinessLocation | null;
+ available?: boolean;
+ published?: boolean;
+ territoryLabel?: string;
+}) {
+ const active = businessPointApplicable(payload);
+ if (!active && !registered) return null;
+ const source =
+ payload.location_point_source_mode === 'listing'
+ ? payload.source_reference
+ : payload.location_point_source_reference;
+ const date =
+ payload.location_point_source_mode === 'listing'
+ ? payload.source_date
+ : payload.location_point_source_date;
+ return (
+
+ {registered && (
+
+ Localização primária actualmente cadastrada:{' '}
+ {registered.is_public
+ ? 'divulgação marcada como pública'
+ : 'reservada'}
+ , precisão{' '}
+ {(
+ {
+ province: 'província',
+ district: 'distrito',
+ admin_post: 'posto administrativo',
+ locality: 'localidade',
+ exact: 'exacta',
+ } as Record
+ )[registered.precision_level] ?? registered.precision_level}
+ .
+ {registered.latitude !== null &&
+ registered.longitude !== null && (
+ <>
+ {' '}
+ Latitude {registered.latitude}; longitude{' '}
+ {registered.longitude}.
+ >
+ )}
+
+ )}
+ {active ? (
+ <>
+
+ {published
+ ? 'Ponto declarado na publicação: latitude'
+ : 'Ponto em preparação: latitude'}{' '}
+ {payload.location_latitude || 'por indicar'}; longitude{' '}
+ {payload.location_longitude || 'por indicar'}. Usa o
+ território declarado; com várias localizações, é
+ necessário escolher a correspondente.
+
+ {territoryLabel && (
+
+ Localização declarada para o ponto: {territoryLabel}
+ .
+
+ )}
+
+ Fonte do ponto: {source || 'por indicar'}. Data da
+ fonte: {date || 'desconhecida'}. Referência{' '}
+ {payload.location_point_share_source === 'yes'
+ ? 'também proposta para divulgação pública'
+ : 'mantida no processo reservado'}
+ ; a data acompanha o ponto publicado.
+
+ {published ? (
+
+ Dados utilizados na publicação e preservados no
+ histórico reservado. A localização actualmente
+ cadastrada é apresentada acima; uma edição posterior
+ não reescreve o histórico.
+
+ ) : (
+
+ A gravação não publica o ponto. Na publicação
+ autorizada do anúncio, este ponto passa a primário
+ público e substitui o primário cadastrado. A versão
+ anterior fica no histórico reservado; as
+ localizações secundárias são conservadas. Confirme
+ território e coordenadas após alterações: a
+ declaração não comprova a correspondência espacial
+ ou a localização real.
+
+ )}
+ {!available && (
+
+ O suplemento de localização ainda não está instalado
+ neste destino. Instale a actualização antes de
+ submeter este ponto ou conserve o cadastro
+ existente.
+
+ )}
+ >
+ ) : (
+ registered && (
+
+ Este formulário não propõe um novo ponto. O cadastro
+ existente é conservado, incluindo as divulgações já
+ registadas.
+
+ )
+ )}
+
+ );
+}
diff --git a/resources/js/components/crm-edit-comparison.tsx b/resources/js/components/crm-edit-comparison.tsx
new file mode 100644
index 00000000..a27a47aa
--- /dev/null
+++ b/resources/js/components/crm-edit-comparison.tsx
@@ -0,0 +1,120 @@
+import type { CrmRecordEditor } from '@/lib/crm-record-edit';
+
+export default function CrmEditComparison({
+ editor,
+ labels,
+ display = (_key, value) => value || 'Não indicado',
+}: {
+ editor: CrmRecordEditor;
+ labels: Record;
+ display?: (key: string, value: string) => string;
+}) {
+ return (
+
+
+ Comparar com os dados actuais
+
+ {editor.form.errors.version && (
+
{editor.form.errors.version}
+ )}
+ {editor.invalid && (
+
+ Recupere este registo antes de gravar. A versão disponível
+ não foi confirmada.
+
+ )}
+ {editor.refreshing && (
+
+ A recuperar os dados actuais. As suas edições são
+ conservadas.
+
+ )}
+ {editor.stale && (
+ <>
+
+ O registo mudou desde a versão {editor.baseVersion}.
+ Compare com a versão {editor.version} antes de
+ continuar.
+
+
+
+
+
+ Campo
+ Actualmente guardado
+ Sua edição
+ Escolha
+
+
+
+ {editor.changed.map((key) => (
+
+ {labels[key] ?? key}
+
+ {display(key, editor.current[key])}
+
+
+ {display(key, editor.values[key])}
+
+
+ {editor.conflicts.includes(key) ? (
+ <>
+
+ editor.choose(
+ key,
+ 'current',
+ )
+ }
+ >
+ Usar valor actual
+ {' '}
+
+ editor.choose(
+ key,
+ 'mine',
+ )
+ }
+ >
+ Manter minha alteração
+
+ {editor.unresolved.includes(
+ key,
+ ) && (
+
+ Escolha o valor a
+ conservar neste
+ campo.
+
+ )}
+ >
+ ) : (
+ 'Actualização compatível com a sua edição'
+ )}
+
+
+ ))}
+
+
+
+
0
+ }
+ onClick={editor.adopt}
+ >
+ Usar esta versão e conservar as alterações escolhidas
+
+ >
+ )}
+
+ );
+}
diff --git a/resources/js/components/crm-task-creation.tsx b/resources/js/components/crm-task-creation.tsx
new file mode 100644
index 00000000..8fdebe36
--- /dev/null
+++ b/resources/js/components/crm-task-creation.tsx
@@ -0,0 +1,293 @@
+import { useCrmTaskCreation } from '@/lib/crm-task-creation';
+import type { TaskCreationContext } from '@/lib/crm-task-creation';
+import type { Lead, Owner } from '@/pages/crm/types';
+import { Field, button, control } from '@/pages/management/shared';
+import { useState } from 'react';
+
+export default function CrmTaskCreation({
+ lead,
+ owners,
+ context,
+}: {
+ lead: Lead;
+ owners: Owner[];
+ context: TaskCreationContext;
+}) {
+ const edit = useCrmTaskCreation(lead, context);
+ const { form } = edit;
+ const [showPreparation, setShowPreparation] = useState(false);
+ const preparation = edit.preparation;
+ const labels = {
+ title: 'Tarefa',
+ due_at: 'Prazo',
+ assignee_user_id: 'Responsável pela tarefa',
+ };
+ function display(field: keyof typeof labels, value: string) {
+ if (!value) return 'Por preencher';
+ if (field === 'assignee_user_id')
+ return (
+ owners.find((owner) => String(owner.id) === value)?.name ??
+ 'Responsável anterior indisponível'
+ );
+ if (field === 'due_at') {
+ const date = new Date(value);
+ return Number.isNaN(date.getTime())
+ ? 'Prazo por confirmar'
+ : new Intl.DateTimeFormat('pt-MZ', {
+ dateStyle: 'medium',
+ timeStyle: 'short',
+ timeZone: 'Africa/Maputo',
+ }).format(date) + ' (Maputo)';
+ }
+ return value;
+ }
+ const missing =
+ form.data.assignee_user_id &&
+ !owners.some(
+ (owner) => String(owner.id) === form.data.assignee_user_id,
+ );
+ const sentDate = edit.sent ? new Date(edit.sent.due_at) : null;
+ const sentDeadline =
+ sentDate && !Number.isNaN(sentDate.getTime())
+ ? new Intl.DateTimeFormat('pt-MZ', {
+ dateStyle: 'medium',
+ timeStyle: 'short',
+ timeZone: 'Africa/Maputo',
+ }).format(sentDate) + ' (Maputo)'
+ : 'Prazo por confirmar';
+ return (
+
+ );
+}
diff --git a/resources/js/components/dashboard-work-queue.tsx b/resources/js/components/dashboard-work-queue.tsx
new file mode 100644
index 00000000..187feb21
--- /dev/null
+++ b/resources/js/components/dashboard-work-queue.tsx
@@ -0,0 +1,167 @@
+import { Link } from '@inertiajs/react';
+import { states as interestStates } from '@/pages/management/shared';
+import { taskStates } from '@/pages/crm/types';
+
+type WorkItem = {
+ id: string;
+ title: string;
+ reference: string | null;
+ status: string;
+ due_at: string | null;
+ overdue: boolean;
+ href: string;
+};
+type WorkGroup = {
+ total: number;
+ overdue: number;
+ items: WorkItem[];
+ page: number;
+ last_page: number;
+ previous: string | null;
+ next: string | null;
+};
+export type DashboardQueue = {
+ as_of: string;
+ desk_states: Record;
+ groups: Partial>;
+};
+const groups = {
+ interests: 'Manifestações atribuídas a mim',
+ desk: 'Pedidos do Balcão atribuídos a mim',
+ crm_tasks: 'Tarefas do CRM atribuídas a mim',
+} as const;
+const date = (value: string) =>
+ new Intl.DateTimeFormat('pt-MZ', {
+ dateStyle: 'medium',
+ timeStyle: 'short',
+ timeZone: 'Africa/Maputo',
+ }).format(new Date(value));
+
+export default function DashboardWorkQueue({
+ queue,
+}: {
+ queue: DashboardQueue | null | undefined;
+}) {
+ if (!queue) return null;
+ return (
+
+
+ O meu acompanhamento
+
+
+ Pedidos e tarefas atribuídos a si, por prazo. Actualizado em{' '}
+ {date(queue.as_of)} (Maputo)
+ .
+
+
+ {Object.entries(groups).map(([kind, title]) => {
+ const group = queue.groups[kind as keyof typeof groups];
+ if (!group) return null;
+ const states =
+ kind === 'interests'
+ ? interestStates
+ : kind === 'desk'
+ ? queue.desk_states
+ : taskStates;
+ return (
+
+
+ {title}
+
+
+ {group.total} por acompanhar · {group.overdue}{' '}
+ com prazo ultrapassado
+
+ {group.items.length ? (
+
+ {group.items.map((item) => (
+
+
+ {item.title}
+
+ {item.reference && (
+
+ {item.reference}
+
+ )}
+
+ {states[item.status] ??
+ item.status}
+
+
+ {item.due_at ? (
+ <>
+
+ {date(item.due_at)}{' '}
+ (Maputo)
+
+ {item.overdue && (
+
+ {' '}
+ · Prazo
+ ultrapassado
+
+ )}
+ >
+ ) : (
+ 'Sem prazo definido'
+ )}
+
+
+ ))}
+
+ ) : (
+
+ Não tem registos activos atribuídos neste
+ acompanhamento.
+
+ )}
+ {group.last_page > 1 && (
+
+ {group.previous && (
+
+ Anterior
+
+ )}
+
+ Página {group.page} de {group.last_page}
+
+ {group.next && (
+
+ Seguinte
+
+ )}
+
+ )}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/resources/js/components/desk-attachment-field.tsx b/resources/js/components/desk-attachment-field.tsx
new file mode 100644
index 00000000..2f69c2b3
--- /dev/null
+++ b/resources/js/components/desk-attachment-field.tsx
@@ -0,0 +1,453 @@
+import { useRef, useState } from 'react';
+import { profileJson, ProfileValidationError } from '@/lib/profile-json';
+import { deskChoices } from '@/lib/desk-field-values';
+import type { DeskDocument } from './desk-internal-operations';
+import DeskDocumentPicker, {
+ type ReusableDeskDocument,
+} from './desk-document-picker';
+
+export type AttachmentField = {
+ label: string;
+ required: boolean;
+ mime_types?: string[];
+ max_size_kb?: number;
+ max_files?: number;
+};
+export type AttachmentInventory = {
+ documents: DeskDocument[];
+ case_version: number;
+ link_id?: string | null;
+ reused_link?: boolean;
+ reusable_documents?: DeskDocument[];
+};
+type Props = {
+ caseId: string;
+ requestId: string;
+ caseVersion: number;
+ fieldKey: string;
+ field: AttachmentField;
+ value: unknown;
+ documents: DeskDocument[];
+ reusableDocuments?: DeskDocument[];
+ disabled: boolean;
+ uploading: boolean;
+ onChange: (ids: string[]) => void;
+ onBusy: (busy: boolean) => void;
+ onInventory: (result: AttachmentInventory, select: boolean) => void;
+};
+const formatLabels: Record = {
+ 'application/pdf': 'PDF',
+ 'image/png': 'PNG',
+ 'image/jpeg': 'JPEG',
+ 'text/plain': 'Texto simples',
+};
+
+export default function DeskAttachmentField(props: Props) {
+ const latest = useRef(props);
+ const fileInput = useRef(null);
+ latest.current = props;
+ const [file, setFile] = useState(null),
+ [source, setSource] = useState(''),
+ [consent, setConsent] = useState(false);
+ const [busy, setBusy] = useState(false),
+ [message, setMessage] = useState(''),
+ [errors, setErrors] = useState>({});
+ const [reuseId, setReuseId] = useState('');
+ const [remoteOrigin, setRemoteOrigin] =
+ useState(null);
+ const reusable = [
+ ...new Map(
+ (props.reusableDocuments ?? [])
+ .filter(
+ (doc) =>
+ !props.documents.some(
+ (current) =>
+ current.document_id === doc.document_id,
+ ),
+ )
+ .map((doc) => [
+ JSON.stringify([
+ doc.document_id,
+ doc.source_reference,
+ doc.stage ?? null,
+ doc.valid_until ?? null,
+ ]),
+ doc,
+ ]),
+ ).values(),
+ ];
+ const origin = remoteOrigin ?? reusable.find((doc) => doc.id === reuseId);
+ const selected = deskChoices(props.value);
+ const unique = [
+ ...new Map(
+ props.documents.map((doc) => [
+ doc.document_id,
+ props.documents.find(
+ (d) =>
+ d.document_id === doc.document_id &&
+ selected.includes(d.id),
+ ) ?? doc,
+ ]),
+ ).values(),
+ ];
+ async function refresh() {
+ if (busy) return;
+ setBusy(true);
+ try {
+ const data = await profileJson(
+ `/balcao-virtual/pedidos/${props.requestId}`,
+ {},
+ 'GET',
+ );
+ if (
+ !Array.isArray(data.documents) ||
+ !Number.isInteger(data.caseVersion)
+ )
+ throw new Error(
+ 'Não foi possível confirmar a lista dos documentos. As respostas desta página foram conservadas.',
+ );
+ latest.current.onInventory(
+ {
+ documents: data.documents,
+ case_version: data.caseVersion,
+ reusable_documents: data.reusableDocuments,
+ },
+ false,
+ );
+ setMessage(
+ 'Estado e lista dos documentos actualizados. As respostas desta página foram conservadas.',
+ );
+ } catch (error) {
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'Não foi possível actualizar os documentos.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ async function upload() {
+ if (
+ props.disabled ||
+ props.uploading ||
+ busy ||
+ (!file && !origin) ||
+ !consent ||
+ (!origin?.source_reference?.trim() && !source.trim())
+ )
+ return;
+ if (
+ !origin &&
+ file &&
+ file.size > (props.field.max_size_kb ?? 10240) * 1024
+ ) {
+ setErrors({
+ file: 'O ficheiro excede o tamanho máximo desta pergunta.',
+ });
+ return;
+ }
+ setBusy(true);
+ props.onBusy(true);
+ setErrors({});
+ setMessage('A enviar o documento privado…');
+ const data = new FormData();
+ data.set('version', String(props.caseVersion));
+ data.set('request_id', props.requestId);
+ data.set('field_key', props.fieldKey);
+ if (origin) {
+ data.set('document_id', origin.document_id);
+ if (origin.id) data.set('reuse_link_id', origin.id);
+ if (!origin.source_reference?.trim())
+ data.set('source_reference', source);
+ } else if (file) {
+ data.set('file', file);
+ data.set('source_reference', source);
+ }
+ data.set('consent', '1');
+ try {
+ const result: AttachmentInventory = await profileJson(
+ `/balcao-virtual/dossiers/${props.caseId}/documentos`,
+ data,
+ );
+ if (
+ !Array.isArray(result.documents) ||
+ !Number.isInteger(result.case_version) ||
+ typeof result.link_id !== 'string' ||
+ !result.documents.some(
+ (document) => document.id === result.link_id,
+ )
+ )
+ throw new Error(
+ 'O envio não confirmou o documento associado. Actualize a lista antes de repetir; o ficheiro seleccionado continua nesta página.',
+ );
+ latest.current.onInventory(result, true);
+ setFile(null);
+ if (fileInput.current) fileInput.current.value = '';
+ setConsent(false);
+ setReuseId('');
+ setRemoteOrigin(null);
+ setMessage(
+ result.reused_link
+ ? 'Este documento já estava associado. Conservou-se a referência registada; pode seleccioná-lo nesta pergunta.'
+ : 'Documento associado ao pedido. A análise de segurança e a selecção nesta pergunta são apresentadas abaixo.',
+ );
+ } catch (error) {
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'O envio não foi confirmado. Actualize a lista antes de repetir.',
+ );
+ if (error instanceof ProfileValidationError)
+ setErrors(error.fields);
+ } finally {
+ setBusy(false);
+ latest.current.onBusy(false);
+ }
+ }
+ return (
+
+
+ {props.field.label}
+ {props.field.required ? ' *' : ''}
+
+
+ Seleccione documentos já associados a este dossier ou envie um
+ ficheiro. O mesmo original pode apoiar várias perguntas, sem
+ novo envio.
+
+
+ Formatos:{' '}
+ {(props.field.mime_types ?? [])
+ .map((mime) => formatLabels[mime] ?? mime)
+ .join(', ')}
+ . Até {props.field.max_size_kb} KB por ficheiro e{' '}
+ {props.field.max_files} ficheiro(s) seleccionados.
+
+ {unique.map((doc) => {
+ const checked = selected.includes(doc.id);
+ const mime = doc.media_type?.split(';')[0].trim().toLowerCase();
+ const known =
+ !!mime &&
+ doc.size_bytes !== null &&
+ doc.size_bytes !== undefined;
+ const fits =
+ (!mime || props.field.mime_types?.includes(mime)) &&
+ (doc.size_bytes === null ||
+ doc.size_bytes === undefined ||
+ doc.size_bytes <=
+ (props.field.max_size_kb ?? 0) * 1024);
+ return (
+
+ =
+ (props.field.max_files ?? 1))
+ }
+ onChange={(event) =>
+ props.onChange(
+ event.target.checked
+ ? [...selected, doc.id]
+ : selected.filter(
+ (id) =>
+ !props.documents.some(
+ (document) =>
+ document.id === id &&
+ document.document_id ===
+ doc.document_id,
+ ),
+ ),
+ )
+ }
+ />{' '}
+ {doc.file_name} · versão{' '}
+ {doc.version_no ?? 'por confirmar'} ·{' '}
+ {doc.malware_scan_status === 'clean' &&
+ doc.status === 'active'
+ ? 'Análise de segurança concluída'
+ : 'Análise ou disponibilidade pendente'}
+ {!fits && ' · Não satisfaz os limites desta pergunta'}
+ {!known &&
+ ' · Formato ou tamanho por conferir ao submeter'}
+
+ {doc.source_reference}
+
+ {doc.status === 'active' &&
+ doc.malware_scan_status === 'clean' && (
+
+ Consultar documento autorizado
+
+ )}
+
+ );
+ })}
+ {selected
+ .filter((id) => !props.documents.some((doc) => doc.id === id))
+ .map((id) => (
+
+ Existe uma selecção cuja disponibilidade precisa de ser
+ actualizada.{' '}
+
+ props.onChange(
+ selected.filter((value) => value !== id),
+ )
+ }
+ >
+ Retirar esta selecção
+
+
+ ))}
+ {!unique.length && (
+
+ Ainda não existem documentos associados a este pedido ou ao
+ dossier para seleccionar.
+
+ )}
+ void refresh()}
+ >
+ Actualizar documentos disponíveis
+
+
+ Pode guardar o rascunho enquanto a análise está pendente. Para
+ submeter uma pergunta aplicável, os suportes seleccionados têm
+ de estar disponíveis, autorizados e com análise de segurança
+ válida; isso não os torna documentos oficialmente aprovados.
+
+
+ {message && (
+
+ {message}
+
+ )}
+ {Object.entries(errors).map(([key, error]) => (
+
+ {error}
+
+ ))}
+
+ );
+}
diff --git a/resources/js/components/desk-case-state-form.tsx b/resources/js/components/desk-case-state-form.tsx
new file mode 100644
index 00000000..51b926e1
--- /dev/null
+++ b/resources/js/components/desk-case-state-form.tsx
@@ -0,0 +1,124 @@
+import { useForm } from '@inertiajs/react';
+import { createOperationKey } from '@/lib/operation-key';
+import { button, card, input } from '@/pages/investment/shared';
+
+type CaseState = { id: string; version: number; closed_at?: string | null };
+export default function DeskCaseStateForm({
+ dossier,
+ activity,
+ disabled = false,
+ onChanged,
+}: {
+ dossier: CaseState;
+ activity: {
+ open_requests: number | null;
+ open_tasks: number | null;
+ pending_payments: number | null;
+ } | null;
+ disabled?: boolean;
+ onChanged?: () => void;
+}) {
+ const target = dossier.closed_at ? 'open' : 'closed';
+ const form = useForm({
+ version: dossier.version,
+ state: target,
+ reason: '',
+ client_key: createOperationKey(),
+ });
+ const stale =
+ form.data.version !== dossier.version || form.data.state !== target;
+ return (
+
+ );
+}
diff --git a/resources/js/components/desk-document-picker.tsx b/resources/js/components/desk-document-picker.tsx
new file mode 100644
index 00000000..0183ed59
--- /dev/null
+++ b/resources/js/components/desk-document-picker.tsx
@@ -0,0 +1,175 @@
+import { useId, useRef, useState } from 'react';
+import { profileJson } from '@/lib/profile-json';
+
+export type ReusableDeskDocument = {
+ id: string | null;
+ document_id: string;
+ file_name: string;
+ version_no: number | null;
+ source_reference: string | null;
+ category: string | null;
+ stage: string | null;
+ valid_until: string | null;
+ origin_label: string | null;
+ status: string;
+ malware_scan_status: string;
+ media_type: string | null;
+ size_bytes: number | null;
+};
+type Props = {
+ caseId: string;
+ disabled: boolean;
+ selected: ReusableDeskDocument | null;
+ onSelect: (document: ReusableDeskDocument | null) => void;
+};
+const key = (doc: ReusableDeskDocument) =>
+ doc.id ?? `upload:${doc.document_id}`;
+
+export default function DeskDocumentPicker(props: Props) {
+ const group = useId();
+ const [query, setQuery] = useState('');
+ const [documents, setDocuments] = useState([]);
+ const [next, setNext] = useState(null);
+ const [busy, setBusy] = useState(false);
+ const [message, setMessage] = useState('');
+ const latest = useRef(props);
+ latest.current = props;
+ const sequence = useRef(0);
+
+ async function search(offset = 0) {
+ if (busy || props.disabled) return;
+ const ticket = ++sequence.current;
+ const caseId = props.caseId;
+ setBusy(true);
+ setMessage('A pesquisar documentos autorizados…');
+ try {
+ const params = new URLSearchParams({
+ q: query,
+ offset: String(offset),
+ });
+ const result = await profileJson(
+ `/balcao-virtual/dossiers/${caseId}/documentos-disponiveis?${params}`,
+ {},
+ 'GET',
+ );
+ if (ticket !== sequence.current || latest.current.caseId !== caseId)
+ return;
+ if (
+ !Array.isArray(result.documents) ||
+ (result.next_offset !== null &&
+ !Number.isInteger(result.next_offset))
+ )
+ throw new Error(
+ 'Não foi possível confirmar os resultados. A selecção anterior foi conservada.',
+ );
+ setDocuments(result.documents);
+ setNext(result.next_offset);
+ setMessage(
+ result.documents.length
+ ? 'Seleccione a origem que pretende reutilizar.'
+ : 'Sem documentos nesta página. Pode ajustar a pesquisa ou continuar, se houver mais resultados.',
+ );
+ } catch (error) {
+ if (ticket === sequence.current && latest.current.caseId === caseId)
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'Não foi possível pesquisar documentos.',
+ );
+ } finally {
+ if (ticket === sequence.current) setBusy(false);
+ }
+ }
+
+ return (
+
+
Reutilizar um documento autorizado
+
+ Pesquise pelo nome do ficheiro, dossier ou referência. A
+ selecção conserva a origem e a validade declarada; a associação
+ exige confirmação.
+
+
+ Nome ou referência do documento
+ {
+ setQuery(event.target.value);
+ setDocuments([]);
+ setNext(null);
+ setMessage(
+ 'Pesquisa alterada. Pesquise para actualizar os resultados.',
+ );
+ }}
+ onKeyDown={(event) => {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ void search();
+ }
+ }}
+ />
+
+
void search()}
+ >
+ Pesquisar documentos
+
+
{message}
+ {documents.map((doc) => (
+
+ props.onSelect(doc)}
+ />{' '}
+ {doc.file_name} · versão {doc.version_no ?? 'por confirmar'}{' '}
+ · {doc.origin_label ?? 'Ficheiro enviado por si'} ·{' '}
+ {doc.source_reference || 'Referência por completar'}
+ {doc.stage ? ` · origem ${doc.stage}` : ''}
+ {doc.valid_until
+ ? ` · validade declarada ${doc.valid_until}`
+ : ''}{' '}
+ · {doc.malware_scan_status}
+
+ ))}
+ {next !== null && (
+
void search(next)}
+ >
+ Próxima página de documentos
+
+ )}
+ {props.selected && (
+
+
+ Origem seleccionada: {props.selected.file_name} ·{' '}
+ {props.selected.source_reference ||
+ 'Referência por completar'}
+ {props.selected.valid_until
+ ? ` · validade declarada ${props.selected.valid_until}`
+ : ''}
+
+
props.onSelect(null)}
+ >
+ Retirar origem seleccionada
+
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/desk-draft-recovery.tsx b/resources/js/components/desk-draft-recovery.tsx
new file mode 100644
index 00000000..eaecc85e
--- /dev/null
+++ b/resources/js/components/desk-draft-recovery.tsx
@@ -0,0 +1,691 @@
+import { router } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { profileJson, ProfileValidationError } from '@/lib/profile-json';
+import { createOperationKey } from '@/lib/operation-key';
+import {
+ checkpointRecovery,
+ checkpointSignature,
+ checkpointSame,
+ type CheckpointView,
+ type DeskAnswers,
+ type RecoveryChoice,
+ type CheckpointRequest,
+ type CheckpointInput,
+} from '@/lib/desk-checkpoints';
+import type { DeskAnswer } from '@/lib/desk-field-values';
+
+type Props = {
+ id: string;
+ version: number;
+ payload: DeskAnswers;
+ initial: DeskAnswers;
+ reason: string;
+ fields: Record<
+ string,
+ { label: string; type?: string; options?: Record }
+ >;
+ paused: boolean;
+ pendingWork?: boolean;
+ onBusy: (busy: boolean) => void;
+ onBlocked: (blocked: boolean) => void;
+ onRecover: (
+ payload: DeskAnswers,
+ reason: string,
+ request: CheckpointRequest,
+ ) => void;
+};
+
+const commonLabels: Record = {
+ country: 'País do requerente',
+ declared_origin_country_code: 'País de origem',
+ context_opportunity: 'Contexto da oportunidade',
+};
+
+export default function DeskDraftRecovery(props: Props) {
+ const latest = useRef(props);
+ latest.current = props;
+ const alive = useRef(true),
+ busy = useRef(false),
+ edited = useRef([]);
+ const previous = useRef(props.payload),
+ base = useRef(props.initial);
+ const previousReason = useRef(props.reason),
+ reasonEdited = useRef(false),
+ failedSignature = useRef('');
+ const recoveryPending = useRef<{
+ body: CheckpointInput;
+ request: CheckpointRequest;
+ payload: DeskAnswers;
+ reason: string;
+ } | null>(null);
+ const view = useRef(null),
+ pending = useRef(null);
+ const saved = useRef(
+ checkpointSignature({ ...props.payload, __reason: props.reason }),
+ );
+ const force = useRef(false);
+ const [state, setState] = useState<
+ 'loading' | 'ready' | 'saving' | 'error' | 'compare' | 'unavailable'
+ >('loading');
+ const [message, setMessage] = useState('A recuperar o estado do rascunho…');
+ const [comparison, setComparison] = useState(null);
+ const [choices, setChoices] = useState>({});
+ const [reasonChoice, setReasonChoice] = useState<'page' | 'saved'>('page');
+ const [tick, setTick] = useState(0);
+ const signature = checkpointSignature({
+ ...props.payload,
+ __reason: props.reason,
+ });
+ const unsaved =
+ props.pendingWork ||
+ force.current ||
+ signature !== saved.current ||
+ pending.current !== null ||
+ recoveryPending.current !== null;
+ const markBusy = (value: boolean) => {
+ busy.current = value;
+ latest.current.onBusy(value);
+ };
+ const compare = (data: CheckpointView) => {
+ view.current = data;
+ setComparison(data);
+ setChoices({});
+ setReasonChoice(
+ latest.current.reason || reasonEdited.current ? 'page' : 'saved',
+ );
+ setState('compare');
+ latest.current.onBlocked(true);
+ setMessage(
+ 'Compare o que está nesta página, o rascunho recuperado e o pedido actual.',
+ );
+ };
+
+ useEffect(() => {
+ alive.current = true;
+ void profileJson(
+ `/balcao-virtual/pedidos/${props.id}/rascunho`,
+ {},
+ 'GET',
+ )
+ .then((data: CheckpointView) => {
+ if (!alive.current) return;
+ view.current = data;
+ if (!data.installed) {
+ setState('unavailable');
+ setMessage(
+ 'Gravação automática ainda não instalada. Pode continuar a guardar manualmente.',
+ );
+ return;
+ }
+ const different =
+ data.checkpoint &&
+ (checkpointSignature(data.checkpoint.payload) !==
+ checkpointSignature(latest.current.payload) ||
+ data.checkpoint.reason !== latest.current.reason);
+ if (
+ data.request.version !== props.version ||
+ !data.request.can_edit ||
+ different
+ )
+ compare(data);
+ else {
+ setState('ready');
+ setMessage(
+ data.checkpoint
+ ? 'Rascunho recuperável no servidor.'
+ : 'A gravação automática acompanha as alterações.',
+ );
+ }
+ })
+ .catch(() => {
+ if (alive.current) {
+ setState('unavailable');
+ setMessage(
+ 'Não foi possível consultar a recuperação. As edições desta página e a gravação manual continuam disponíveis.',
+ );
+ }
+ });
+ return () => {
+ alive.current = false;
+ };
+ }, [props.id, props.version]);
+
+ useEffect(() => {
+ const keys = new Set([
+ ...Object.keys(previous.current),
+ ...Object.keys(props.payload),
+ ]);
+ for (const key of keys)
+ if (
+ !checkpointSame(previous.current[key], props.payload[key]) &&
+ !edited.current.includes(key)
+ )
+ edited.current.push(key);
+ previous.current = props.payload;
+ if (previousReason.current !== props.reason)
+ reasonEdited.current = true;
+ previousReason.current = props.reason;
+ }, [props.payload, props.reason]);
+
+ async function persist() {
+ const p = latest.current,
+ current = view.current;
+ if (
+ busy.current ||
+ p.paused ||
+ !current?.installed ||
+ !current.request.can_edit ||
+ state === 'compare'
+ )
+ return;
+ if (
+ !pending.current &&
+ !force.current &&
+ checkpointSignature({ ...p.payload, __reason: p.reason }) ===
+ saved.current
+ )
+ return;
+ const body = pending.current ?? {
+ version: current.checkpoint?.version ?? 0,
+ request_version: current.request.version,
+ operation_key: createOperationKey(),
+ payload: structuredClone(p.payload),
+ edited_keys: [...edited.current],
+ reason: p.reason,
+ };
+ pending.current = body;
+ markBusy(true);
+ setState('saving');
+ setMessage('A guardar automaticamente…');
+ try {
+ const data: CheckpointView = await profileJson(
+ `/balcao-virtual/pedidos/${p.id}/rascunho`,
+ body,
+ );
+ if (!alive.current) return;
+ if (
+ !data.checkpoint ||
+ data.request.id !== p.id ||
+ data.checkpoint.version !== body.version + 1 ||
+ data.checkpoint.request_version !== body.request_version
+ )
+ throw new Error(
+ 'A resposta da gravação não confirmou a versão esperada. Compare com o servidor antes de continuar.',
+ );
+ view.current = data;
+ pending.current = null;
+ force.current = false;
+ saved.current = checkpointSignature({
+ ...body.payload,
+ __reason: body.reason,
+ });
+ setState('ready');
+ setMessage(
+ 'Guardado automaticamente no servidor. Ainda não foi submetido.',
+ );
+ setTick((v) => v + 1);
+ } catch (error) {
+ if (!alive.current) return;
+ failedSignature.current = checkpointSignature({
+ ...body.payload,
+ __reason: body.reason,
+ });
+ if (
+ error instanceof ProfileValidationError &&
+ Object.keys(error.fields).length
+ )
+ pending.current = null;
+ setState('error');
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'A gravação falhou. As alterações continuam nesta página.',
+ );
+ } finally {
+ if (alive.current) markBusy(false);
+ }
+ }
+
+ useEffect(() => {
+ if (
+ state === 'error' &&
+ pending.current === null &&
+ signature !== failedSignature.current
+ ) {
+ setState('ready');
+ return;
+ }
+ if (state !== 'ready' || props.paused || !unsaved) return;
+ const timer = setTimeout(() => void persist(), 2000);
+ return () => clearTimeout(timer);
+ }, [signature, state, props.paused, tick]);
+
+ useEffect(() => {
+ const leave = (event: BeforeUnloadEvent) => {
+ if (unsaved) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ const stop = router.on('before', (event) => {
+ if (
+ event.detail.visit.method === 'get' &&
+ unsaved &&
+ !window.confirm(
+ 'Existem alterações ainda não guardadas automaticamente. Pretende sair desta página?',
+ )
+ )
+ event.preventDefault();
+ });
+ window.addEventListener('beforeunload', leave);
+ return () => {
+ stop();
+ window.removeEventListener('beforeunload', leave);
+ };
+ }, [unsaved]);
+
+ async function refresh() {
+ if (busy.current) return;
+ markBusy(true);
+ try {
+ const data: CheckpointView = await profileJson(
+ `/balcao-virtual/pedidos/${props.id}/rascunho`,
+ {},
+ 'GET',
+ );
+ if (alive.current) {
+ pending.current = null;
+ recoveryPending.current = null;
+ if (data.installed) compare(data);
+ else {
+ setState('unavailable');
+ setMessage(
+ 'Gravação automática ainda não instalada. Pode continuar a guardar manualmente.',
+ );
+ }
+ }
+ } catch (error) {
+ if (alive.current)
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'Não foi possível comparar.',
+ );
+ } finally {
+ if (alive.current) markBusy(false);
+ }
+ }
+
+ const allowed = comparison
+ ? comparison.request.status === 'returned'
+ ? comparison.request.editable_fields
+ : [
+ ...new Set([
+ ...Object.keys(props.fields),
+ 'country',
+ 'declared_origin_country_code',
+ 'context_reuse',
+ 'context_opportunity',
+ 'context_opportunity_snapshot',
+ ]),
+ ]
+ : [];
+ const recovery = comparison
+ ? checkpointRecovery(
+ base.current,
+ props.payload,
+ edited.current,
+ comparison.request.payload,
+ comparison.checkpoint,
+ allowed,
+ choices,
+ )
+ : null;
+ async function adopt(useSaved: boolean) {
+ if (
+ busy.current ||
+ !comparison ||
+ !comparison.request.can_edit ||
+ (useSaved && recovery!.conflicts.length)
+ )
+ return;
+ const payload = useSaved
+ ? recovery!.payload
+ : { ...comparison.request.payload };
+ if (!useSaved)
+ for (const key of allowed)
+ if (Object.hasOwn(props.payload, key))
+ payload[key] = props.payload[key];
+ const intent = useSaved
+ ? recovery!.intent
+ : allowed.filter(
+ (key) =>
+ !checkpointSame(
+ payload[key],
+ comparison.request.payload[key],
+ ),
+ );
+ const reason =
+ useSaved && reasonChoice === 'saved'
+ ? (comparison.checkpoint?.reason ?? '')
+ : props.reason;
+ const attempt = recoveryPending.current ?? {
+ body: {
+ version: comparison.checkpoint?.version ?? 0,
+ request_version: comparison.request.version,
+ operation_key: createOperationKey(),
+ payload,
+ edited_keys: intent,
+ reason,
+ },
+ request: comparison.request,
+ payload,
+ reason,
+ };
+ recoveryPending.current = attempt;
+ markBusy(true);
+ try {
+ const data: CheckpointView = await profileJson(
+ `/balcao-virtual/pedidos/${props.id}/rascunho`,
+ attempt.body,
+ );
+ if (!alive.current) return;
+ if (
+ !data.checkpoint ||
+ data.request.id !== props.id ||
+ data.checkpoint.version !== attempt.body.version + 1 ||
+ data.checkpoint.request_version !== attempt.body.request_version
+ )
+ throw new Error(
+ 'A recuperação não confirmou a versão esperada. Compare com o servidor antes de continuar.',
+ );
+ previous.current = attempt.payload;
+ base.current = attempt.request.payload;
+ view.current = data;
+ edited.current = attempt.body.edited_keys;
+ pending.current = null;
+ recoveryPending.current = null;
+ force.current = false;
+ saved.current = checkpointSignature({
+ ...attempt.payload,
+ __reason: attempt.reason,
+ });
+ setComparison(null);
+ setState('ready');
+ latest.current.onBlocked(false);
+ latest.current.onRecover(
+ attempt.payload,
+ attempt.reason,
+ attempt.request,
+ );
+ setMessage(
+ 'Rascunho recuperado e guardado no servidor, sem submeter.',
+ );
+ setTick((v) => v + 1);
+ } catch (error) {
+ if (alive.current)
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'A recuperação não foi guardada. Repita a mesma tentativa ou compare novamente.',
+ );
+ } finally {
+ if (alive.current) markBusy(false);
+ }
+ }
+ const display = (value: DeskAnswer | undefined, key: string) =>
+ value === null || value === undefined || value === ''
+ ? 'Por preencher'
+ : Array.isArray(value)
+ ? value
+ .map(
+ (code) =>
+ props.fields[key]?.options?.[code] ??
+ (props.fields[key]?.type === 'attachment'
+ ? 'Documento por recuperar na lista actual'
+ : code),
+ )
+ .join(' · ')
+ : props.fields[key]?.type === 'consent'
+ ? value === 'accepted'
+ ? 'Aceite'
+ : value === 'declined'
+ ? 'Recusado'
+ : String(value)
+ : (props.fields[key]?.options?.[String(value)] ??
+ String(value));
+ return (
+
+ Gravação automática do rascunho
+
+ {message}
+
+
+ As respostas ficam cifradas no servidor para a sua conta,
+ incluindo valores ainda incompletos. Esta gravação não submete,
+ não revê o contexto e não autoriza a submissão.
+
+ {unsaved && state !== 'compare' && (
+
+ Existem alterações nesta página ainda por guardar
+ automaticamente.
+
+ )}
+ {state === 'error' && (
+ <>
+ void persist()}>
+ Tentar novamente a mesma gravação
+
+ void refresh()}>
+ Comparar com o servidor
+
+
+ Se a sessão expirou, mantenha esta página e
+ autentique-se noutro separador antes de tentar
+ novamente.
+
+ >
+ )}
+ {state === 'unavailable' && (
+ void refresh()}>
+ Voltar a consultar a recuperação
+
+ )}
+ {comparison && recovery && (
+ <>
+
+ Pedido actual: versão {comparison.request.version}.{' '}
+ {comparison.checkpoint && (
+ <>
+ Rascunho automático: versão{' '}
+ {comparison.checkpoint.version}, guardado em{' '}
+ {comparison.checkpoint.updated_at}.
+ >
+ )}
+
+ {!comparison.request.can_edit ? (
+
+ O pedido já não permite edição. As respostas desta
+ página são conservadas aqui; pode consultar o pedido
+ actual antes de sair.
+
+ ) : (
+ <>
+
+
+
+ Comparação das respostas a recuperar
+
+
+
+ Campo
+ Nesta página
+ Guardado automaticamente
+ Pedido actual
+ Escolha
+
+
+
+ {recovery.rows.map((row) => (
+
+
+ {props.fields[row.key]
+ ?.label ??
+ commonLabels[row.key] ??
+ row.key}
+
+
+ {display(row.page, row.key)}
+
+
+ {display(
+ row.saved,
+ row.key,
+ )}
+
+
+ {display(
+ row.current,
+ row.key,
+ )}
+
+
+
+ Resposta a conservar{' '}
+ {row.conflict &&
+ !choices[row.key] &&
+ '(escolha necessária)'}
+
+ setChoices(
+ (c) => ({
+ ...c,
+ [row.key]:
+ e
+ .target
+ .value as RecoveryChoice,
+ }),
+ )
+ }
+ >
+
+ Escolha uma
+ resposta
+
+
+ Nesta página
+
+ {comparison.checkpoint && (
+
+ Guardado
+ automaticamente
+
+ )}
+
+ Pedido actual
+
+
+
+
+
+ ))}
+
+
+
+ {comparison.checkpoint && (
+
+ Justificação de correcção a recuperar
+
+ setReasonChoice(
+ e.target.value === 'saved'
+ ? 'saved'
+ : 'page',
+ )
+ }
+ >
+
+ Nesta página:{' '}
+ {props.reason || 'Por preencher'}
+
+
+ Guardada:{' '}
+ {comparison.checkpoint.reason ||
+ 'Por preencher'}
+
+
+
+ )}
+
+ Em pedidos devolvidos, apenas os campos
+ autorizados são recuperados. A autorização de
+ submissão e a revisão do contexto têm de ser
+ confirmadas de novo.
+
+ 0 ||
+ busy.current
+ }
+ onClick={() => void adopt(true)}
+ >
+ Recuperar as respostas escolhidas
+
+ void adopt(false)}
+ >
+ Manter esta página e substituir o rascunho
+ automático
+
+ void refresh()}
+ >
+ Actualizar a comparação
+
+ >
+ )}
+ >
+ )}
+ {state === 'error' && message && (
+
+ A gravação automática está interrompida. {message}
+ {message &&
+ pending.current &&
+ ' A tentativa anterior é conservada para repetição sem duplicação.'}
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/desk-internal-operations.tsx b/resources/js/components/desk-internal-operations.tsx
index dbab2aed..1d293607 100644
--- a/resources/js/components/desk-internal-operations.tsx
+++ b/resources/js/components/desk-internal-operations.tsx
@@ -1,6 +1,7 @@
import { createOperationKey } from '@/lib/operation-key';
import { useForm } from '@inertiajs/react';
import { card, input, button } from '@/pages/investment/shared';
+import DeskPaymentDocumentForm from './desk-payment-document-form';
export type DeskDocument = {
id: string;
@@ -10,6 +11,12 @@ export type DeskDocument = {
malware_scan_status: string;
category: string;
source_reference: string;
+ request_id?: string | null;
+ media_type?: string | null;
+ size_bytes?: number | null;
+ version_no?: number | null;
+ stage?: string | null;
+ valid_until?: string | null;
};
export function DocumentReview({
caseId,
@@ -163,6 +170,14 @@ export type DeskPayment = {
verified_by: number | null;
reason: string | null;
version: number;
+ document_evidence?: {
+ link_id: string;
+ file_name: string;
+ document_version: number;
+ source_reference: string;
+ sha256: string;
+ valid_until: string | null;
+ } | null;
};
export function RequestOperations({
requestId,
@@ -182,7 +197,7 @@ export function RequestOperations({
amount: '',
currency: 'MZN',
source_reference: '',
- document_id: '',
+ document_link_id: '',
consent: false,
});
const review = useForm({
@@ -221,10 +236,35 @@ export function RequestOperations({
: 'Declarado — por conferir'}
Fonte do valor: {p.source_reference}
+ {p.document_evidence ? (
+
+ Comprovativo: {p.document_evidence.file_name} ·
+ versão {p.document_evidence.document_version} ·
+ referência documental:{' '}
+ {p.document_evidence.source_reference}
+ {p.document_evidence.valid_until
+ ? ` · validade declarada ${p.document_evidence.valid_until}`
+ : ''}
+
+ ) : (
+
+ {p.document_id
+ ? 'Comprovativo associado em registo anterior; metadados da associação não capturados à época.'
+ : 'Comprovativo ainda não associado.'}
+
+ )}
Responsável pela conferência:{' '}
{p.verified_by ?? 'Ainda sem conferência'} · {p.reason}
+ {owner &&
+ ['pending', 'internal_issue'].includes(p.status) && (
+
+ )}
))}
{owner && (
@@ -240,6 +280,10 @@ export function RequestOperations({
Registar referência e comprovativo
+
+ Se esta referência já está registada acima, junte ou
+ corrija o comprovativo nesse registo.
+
Referência fornecida
- payment.setData('document_id', e.target.value)
+ payment.setData(
+ 'document_link_id',
+ e.target.value,
+ )
}
>
Pendente — registar referência agora
{documents.map((d) => (
-
- {d.file_name}
+
+ {d.file_name} · versão{' '}
+ {d.version_no ?? 'por confirmar'} ·{' '}
+ {d.source_reference}
))}
diff --git a/resources/js/components/desk-payment-document-form.tsx b/resources/js/components/desk-payment-document-form.tsx
new file mode 100644
index 00000000..e2ec2444
--- /dev/null
+++ b/resources/js/components/desk-payment-document-form.tsx
@@ -0,0 +1,138 @@
+import { useForm } from '@inertiajs/react';
+import { createOperationKey } from '@/lib/operation-key';
+import { button, card, input } from '@/pages/investment/shared';
+import type { DeskDocument, DeskPayment } from './desk-internal-operations';
+
+export default function DeskPaymentDocumentForm({
+ requestId,
+ payment,
+ documents,
+}: {
+ requestId: string;
+ payment: DeskPayment;
+ documents: DeskDocument[];
+}) {
+ const form = useForm({
+ version: payment.version,
+ document_link_id: '',
+ reason: '',
+ consent: false,
+ client_key: createOperationKey(),
+ });
+ return (
+ {
+ event.preventDefault();
+ if (form.processing || form.data.version !== payment.version)
+ return;
+ form.put(
+ `/balcao-virtual/pedidos/${requestId}/pagamentos/${payment.id}/comprovativo`,
+ {
+ onSuccess: () => {
+ form.reset('document_link_id', 'reason', 'consent');
+ form.setData('version', form.data.version + 1);
+ form.setData('client_key', createOperationKey());
+ },
+ },
+ );
+ }}
+ >
+
+ {payment.document_id
+ ? 'Corrigir comprovativo deste registo'
+ : 'Juntar comprovativo a este registo'}
+
+
+ A referência, o valor e a moeda já registados são conservados. O
+ comprovativo ficará por conferir; o histórico da conferência
+ anterior é preservado.
+
+ {form.data.version !== payment.version && (
+
+ Este registo foi actualizado. Confira a versão actual antes
+ de continuar.{' '}
+ {
+ form.setData('version', payment.version);
+ form.setData('client_key', createOperationKey());
+ form.setData('consent', false);
+ }}
+ >
+ Usar versão actual, conservando a selecção
+
+
+ )}
+
+ Comprovativo já associado ao pedido ou dossier
+ {
+ form.setData('document_link_id', event.target.value);
+ form.setData('client_key', createOperationKey());
+ form.setData('consent', false);
+ }}
+ >
+ Seleccione o documento de suporte
+ {documents.map((doc) => (
+
+ {doc.file_name} · versão{' '}
+ {doc.version_no ?? 'por confirmar'} ·{' '}
+ {doc.source_reference}
+
+ ))}
+
+
+
+ Se o original ainda não está associado, utilize os anexos do
+ pedido ou os documentos do dossier e regresse a este registo.
+
+
+ Motivo da associação ou correcção
+ {
+ form.setData('reason', event.target.value);
+ form.setData('client_key', createOperationKey());
+ form.setData('consent', false);
+ }}
+ />
+
+
+
+ form.setData('consent', event.target.checked)
+ }
+ />
+ Autorizo associar este comprovativo ao registo existente.
+
+
+ Guardar comprovativo no mesmo registo
+
+ {Object.entries(form.errors).map(([key, error]) => (
+
+ {error}
+
+ ))}
+
+ );
+}
diff --git a/resources/js/components/desk-service-history.tsx b/resources/js/components/desk-service-history.tsx
index 37f5bfc7..f6ade8fd 100644
--- a/resources/js/components/desk-service-history.tsx
+++ b/resources/js/components/desk-service-history.tsx
@@ -9,6 +9,7 @@ type Version = {
author_id: number | null;
published_by: number | null;
published_at: string | null;
+ effective_from?: string | null;
definition: Definition;
source: { identifier?: string; edition?: string; sha256?: string };
reason: string | null;
@@ -147,6 +148,17 @@ export default function DeskServiceHistory({
{publishedDate(version.published_at)}
+
+
+ Entrada em vigor
+
+
+ {version.effective_from ||
+ 'Sem data explícita (versão histórica)'}
+ . Pedidos existentes mantêm esta versão,
+ mesmo após uma edição posterior.
+
+
Motivo registado
diff --git a/resources/js/components/desk-typed-choice.tsx b/resources/js/components/desk-typed-choice.tsx
new file mode 100644
index 00000000..3c363007
--- /dev/null
+++ b/resources/js/components/desk-typed-choice.tsx
@@ -0,0 +1,88 @@
+import { deskChoices, deskScalar } from '@/lib/desk-field-values';
+
+export default function DeskTypedChoice({
+ fieldKey,
+ field,
+ value,
+ disabled,
+ onChange,
+}: {
+ fieldKey: string;
+ field: {
+ type: string;
+ label: string;
+ required: boolean;
+ options?: Record;
+ statement?: string;
+ };
+ value: unknown;
+ disabled: boolean;
+ onChange: (value: string | string[]) => void;
+}) {
+ return (
+
+
+ {field.label}
+ {field.required ? ' *' : ''}
+
+ {field.type === 'multiselect' ? (
+ <>
+
+ Seleccione as opções aplicáveis.{' '}
+ {field.required &&
+ 'Ao submeter, escolha pelo menos uma.'}
+
+ {Object.entries(field.options ?? {}).map(
+ ([code, label]) => (
+
+
+ onChange(
+ event.target.checked
+ ? [...deskChoices(value), code]
+ : deskChoices(value).filter(
+ (v) => v !== code,
+ ),
+ )
+ }
+ />{' '}
+ {label}
+
+ ),
+ )}
+ >
+ ) : (
+ <>
+ {field.statement}
+
+ Registe a sua escolha. Uma resposta obrigatória exige
+ escolher aceitar ou recusar; não exige aceitar.
+
+ {Object.entries({
+ accepted: 'Aceito esta declaração',
+ declined: 'Não aceito esta declaração',
+ }).map(([code, label]) => (
+
+ onChange(code)}
+ />{' '}
+ {label}
+
+ ))}
+ onChange('')}
+ >
+ Deixar por responder
+
+ >
+ )}
+
+ );
+}
diff --git a/resources/js/components/education-review.tsx b/resources/js/components/education-review.tsx
new file mode 100644
index 00000000..e63c9449
--- /dev/null
+++ b/resources/js/components/education-review.tsx
@@ -0,0 +1,229 @@
+import { useEducationReview } from '@/lib/education-review';
+import type { EducationReviewProps } from '@/lib/education-review';
+import { Field, button, control } from '@/pages/management/shared';
+const states: Record = {
+ submitted: 'Submetida',
+ reviewed: 'Revista internamente',
+ rejected: 'Rejeitada',
+};
+export default function EducationReview(props: EducationReviewProps) {
+ const edit = useEducationReview(props),
+ { form } = edit,
+ row = props.declaration;
+ return (
+
+ {edit.notice && {edit.notice}
}
+ {(edit.stale || edit.conflict) && (
+
+ A declaração mudou
+
+ Compare a versão analisada com os dados actuais antes de
+ confirmar a decisão.
+
+
+ Qualificação
+
+ Analisada: {edit.base.qualification} · Actual:{' '}
+ {edit.current.qualification}
+
+
+ Quantidade de{' '}
+ {props.kind === 'demands'
+ ? 'trabalhadores'
+ : 'vagas formativas'}
+
+
+ Analisada: {edit.base.quantity} · Actual:{' '}
+ {edit.current.quantity}
+
+ Período
+
+ Analisado: {edit.base.period_start} a{' '}
+ {edit.base.period_end} · Actual:{' '}
+ {edit.current.period_start} a{' '}
+ {edit.current.period_end}
+
+ Validade da fonte
+
+ Analisada: {edit.base.valid_until} · Actual:{' '}
+ {edit.current.valid_until}
+
+ Fonte
+
+ Analisada: {edit.base.source} · Actual:{' '}
+ {edit.current.source}
+
+ Data de referência
+
+ Analisada:{' '}
+ {edit.base.reference_date || 'Não identificada'} ·
+ Actual:{' '}
+ {edit.current.reference_date || 'Não identificada'}
+
+ {props.kind === 'demands' && (
+ <>
+ Empregador declarado
+
+ Analisado:{' '}
+ {edit.base.employer || 'Não identificado'} ·
+ Actual:{' '}
+ {edit.current.employer ||
+ 'Não identificado'}
+
+ >
+ )}
+ {Array.from(
+ new Set([
+ ...Object.keys(edit.base.references),
+ ...Object.keys(edit.current.references),
+ ]),
+ ).map((field) => (
+
+
+ {(
+ {
+ occupation: 'Ocupação',
+ skill: 'Competência',
+ project: 'Projecto',
+ course: 'Curso',
+ location: 'Localização',
+ } as Record
+ )[field] ?? 'Referência'}
+
+
+ Analisada:{' '}
+ {edit.base.references[field] ||
+ 'Não identificada'}{' '}
+ · Actual:{' '}
+ {edit.current.references[field] ||
+ 'Não identificada'}
+
+
+ ))}
+ Estado
+
+ Analisado:{' '}
+ {states[edit.base.status] ?? edit.base.status} ·
+ Actual:{' '}
+ {states[edit.current.status] ?? edit.current.status}
+
+
+
+ Actualizar declaração
+
+ {edit.canAdopt && (
+
+ Confirmar a leitura desta versão
+
+ )}
+
+ )}
+ {row.can_review !== true && !edit.uncertain ? (
+
+ {row.review_unavailable === 'self'
+ ? 'Esta declaração foi submetida por si. A revisão cabe a outro gestor.'
+ : row.review_unavailable === 'expired'
+ ? 'A fonte expirou. A declaração permanece disponível para consulta.'
+ : 'Actualize a declaração para confirmar as opções de revisão.'}
+
+ ) : (
+ {
+ event.preventDefault();
+ edit.submit();
+ }}
+ >
+
+ Decisão de revisão interna
+
+ {edit.uncertain && (
+
+ A recuperação repete a decisão enviada:{' '}
+ {states[edit.sent?.status ?? ''] ?? 'Por confirmar'}
+ . Fundamento: {edit.sent?.review_reason}. As edições
+ posteriores ficam conservadas.
+
+ )}
+
+
+ edit.change('status', event.target.value)
+ }
+ >
+ Registar revisão
+
+ Rejeitar declaração
+
+
+
+
+
+ edit.change('review_reason', event.target.value)
+ }
+ />
+
+ {form.errors.version_no && (
+
+ Actualize e compare a declaração antes de continuar.
+ A decisão preparada foi conservada.
+
+ )}
+
+
+ {edit.uncertain
+ ? 'Recuperar a mesma revisão'
+ : 'Guardar decisão'}
+
+
+ Actualizar dados da declaração
+
+
+
+ )}
+ {row.can_review !== true &&
+ !edit.uncertain &&
+ form.data.review_reason && (
+
+ Fundamento preparado nesta página:{' '}
+ {form.data.review_reason}
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/education-submitted-snapshot.tsx b/resources/js/components/education-submitted-snapshot.tsx
new file mode 100644
index 00000000..f6296deb
--- /dev/null
+++ b/resources/js/components/education-submitted-snapshot.tsx
@@ -0,0 +1,110 @@
+import { Link } from '@inertiajs/react';
+
+export type EducationDraft = {
+ id: string;
+ kind: 'demands' | 'capacities';
+ version_no: number;
+ state: 'draft' | 'submitted';
+ updated_at: string;
+ payload: Record;
+ record_id: string | null;
+ references: {
+ project_id?: { name?: string };
+ course_id?: { title?: string };
+ occupation_id?: { name?: string };
+ skill_id?: { name?: string };
+ territory_path?: { name: string }[];
+ } | null;
+};
+export type EducationDraftSummary = Pick<
+ EducationDraft,
+ 'id' | 'kind' | 'version_no' | 'state' | 'updated_at'
+> & { label?: string | null };
+
+export default function EducationSubmittedSnapshot({
+ draft,
+}: {
+ draft: EducationDraft;
+}) {
+ const labels: Record = {
+ employer: 'Empregador declarante',
+ qualification: 'Qualificação',
+ quantity:
+ draft.kind === 'demands'
+ ? 'Trabalhadores necessários'
+ : 'Vagas formativas',
+ period_start: 'Início do período',
+ period_end: 'Fim do período',
+ reference_date: 'Data de referência da fonte',
+ valid_until: 'Fonte válida até',
+ source: 'Fonte e evidência',
+ };
+ return (
+
+ Declaração submetida
+
+ Os dados abaixo conservam a submissão efectuada. A revisão
+ independente mantém o seu percurso; esta consulta não certifica
+ a instituição ou formação.
+
+
+ {Object.entries(labels)
+ .filter(
+ ([key]) =>
+ draft.payload[key] !== undefined &&
+ draft.payload[key] !== null &&
+ draft.payload[key] !== '',
+ )
+ .map(([key, label]) => (
+
+
{label}
+
+ {draft.payload[key]}
+
+
+ ))}
+ {draft.references && (
+ <>
+
+
+ {draft.kind === 'demands'
+ ? 'Projecto utilizado'
+ : 'Curso utilizado'}
+
+
+ {draft.references.project_id?.name ??
+ draft.references.course_id?.title ??
+ 'Referência conservada'}
+
+
+
+
+ Ocupação / competência utilizadas
+
+
+ {draft.references.occupation_id?.name} /{' '}
+ {draft.references.skill_id?.name}
+
+
+
+
Local utilizado
+
+ {draft.references.territory_path
+ ?.map((node) => node.name)
+ .join(' / ') || 'Referência conservada'}
+
+
+ >
+ )}
+
+ {draft.kind === 'demands' && draft.record_id && (
+
+ Consultar análise e estado actual
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/funding-criteria-assessment.tsx b/resources/js/components/funding-criteria-assessment.tsx
new file mode 100644
index 00000000..a48cede0
--- /dev/null
+++ b/resources/js/components/funding-criteria-assessment.tsx
@@ -0,0 +1,197 @@
+import { useState } from 'react';
+import { portalRequest } from '@/lib/portal-api';
+import { card, button } from '@/pages/investment/shared';
+import type { Programme } from '@/pages/funding/shared';
+
+type Assessment = {
+ notice: string;
+ criteria: { code: string; status: string }[];
+};
+const statusLabels: Record = {
+ matches: 'Corresponde à resposta esperada',
+ does_not_match: 'Não corresponde à resposta esperada',
+ unknown: 'Informação por confirmar',
+ not_applicable: 'Não aplicável ao tipo de candidato indicado',
+};
+
+export default function FundingCriteriaAssessment({
+ record,
+}: {
+ record: Programme;
+}) {
+ const [kind, setKind] = useState('unknown');
+ const [windowCode, setWindowCode] = useState('');
+ const [answers, setAnswers] = useState>({});
+ const [assessment, setAssessment] = useState(null);
+ const [error, setError] = useState('');
+ const [busy, setBusy] = useState(false);
+ const selectedWindow = record.payload.windows.find(
+ (item) => item.code === windowCode,
+ );
+ const criteria = [
+ ...record.payload.criteria,
+ ...(selectedWindow?.criteria ?? []),
+ ];
+ const applicable = criteria.filter(
+ (item) => item.applies_to === 'all' || item.applies_to === kind,
+ );
+ const awaitingType = criteria.filter(
+ (item) => item.applies_to !== 'all' && kind === 'unknown',
+ ).length;
+ const notApplicable = criteria.length - applicable.length - awaitingType;
+ function resetResult() {
+ setAssessment(null);
+ setError('');
+ }
+ async function assess() {
+ setBusy(true);
+ resetResult();
+ try {
+ setAssessment(
+ await portalRequest(
+ `/fundos/${record.id}/criterios`,
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ version_id: record.version_id,
+ applicant_kind: kind,
+ window_code: windowCode || null,
+ answers: Object.fromEntries(
+ applicable.map((item) => [
+ item.code,
+ answers[item.code] ?? 'unknown',
+ ]),
+ ),
+ }),
+ },
+ ),
+ );
+ } catch (failure) {
+ setError(
+ failure instanceof Error
+ ? failure.message
+ : 'Não foi possível conferir os critérios.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ return (
+
+
+ Conferir critérios documentados
+
+
+ Esta consulta não envia candidatura nem concede financiamento.
+ As respostas não ficam guardadas.
+
+
+ Tipo de candidato
+ {
+ setKind(event.target.value);
+ resetResult();
+ }}
+ >
+ Por definir
+ Pessoa singular
+ Entidade
+
+
+ {record.payload.windows.length > 0 && (
+
+ Janela
+ {
+ setWindowCode(event.target.value);
+ resetResult();
+ }}
+ >
+ Apenas critérios gerais
+ {record.payload.windows.map((item) => (
+
+ {item.title}
+
+ ))}
+
+
+ )}
+ {criteria.length === 0 && (
+
+ Esta ficha não contém critérios suficientes para conferir a
+ correspondência.
+
+ )}
+ {awaitingType > 0 && (
+
+ Escolha o tipo de candidato para apresentar os{' '}
+ {awaitingType} critérios específicos. Sem essa escolha,
+ ficam por confirmar.
+
+ )}
+ {notApplicable > 0 && (
+
+ {notApplicable} critérios de outro tipo de candidato não se
+ aplicam à escolha indicada.
+
+ )}
+ {applicable.map((item) => (
+
+
+ {item.question}
+ {
+ setAnswers({
+ ...answers,
+ [item.code]: event.target.value,
+ });
+ resetResult();
+ }}
+ >
+
+ Não sei / por confirmar
+
+ Sim
+ Não
+
+
+
{item.explanation}
+
Fonte: {item.source_reference}
+ {assessment && (
+
+ {
+ statusLabels[
+ assessment.criteria.find(
+ (result) => result.code === item.code,
+ )?.status ?? 'unknown'
+ ]
+ }
+
+ )}
+
+ ))}
+ void assess()}
+ >
+ {busy ? 'A conferir…' : 'Conferir respostas'}
+
+ {error && {error}
}
+ {assessment && {assessment.notice}
}
+
+ );
+}
diff --git a/resources/js/components/investment-profile-editor.tsx b/resources/js/components/investment-profile-editor.tsx
new file mode 100644
index 00000000..c7d2ed02
--- /dev/null
+++ b/resources/js/components/investment-profile-editor.tsx
@@ -0,0 +1,313 @@
+import { useEffect, useId } from 'react';
+import CountrySelect, { type Country } from './country-select';
+import OrganizationCountryReuse from './organization-country-reuse';
+import { Field, input, button } from '@/pages/investment/shared';
+import {
+ useInvestmentProfileEditor,
+ type ProfileRecord,
+ type OrganizationRecord,
+} from '@/lib/investment-profile-editor';
+
+export default function InvestmentProfileEditor({
+ record,
+ fields,
+ countries,
+ company = false,
+ actorId,
+ editorId,
+ reportDirty,
+ labels,
+ organizations = [],
+}: {
+ record: ProfileRecord;
+ fields: string[];
+ countries: Country[];
+ company?: boolean;
+ actorId: number;
+ editorId: string;
+ reportDirty: (id: string, dirty: boolean) => void;
+ labels: Record;
+ organizations?: OrganizationRecord[];
+}) {
+ const isCompany = company || !!record.id;
+ const editor = useInvestmentProfileEditor(
+ record,
+ fields,
+ isCompany,
+ actorId,
+ editorId,
+ reportDirty,
+ );
+ const id = useId(),
+ disabled =
+ editor.busy ||
+ editor.uncertain ||
+ editor.blocked ||
+ editor.externalBusy;
+ useEffect(() => {
+ if (Object.keys(editor.errors).length)
+ document
+ .getElementById(id)
+ ?.querySelector('[aria-invalid="true"]')
+ ?.focus();
+ }, [editor.errors, id]);
+ const fieldErrorKeys = [
+ ...fields.map((key) => 'payload.' + key),
+ ...(isCompany ? ['payload.country'] : []),
+ ];
+ return (
+ <>
+ {
+ event.preventDefault();
+ void editor.save();
+ }}
+ >
+
+ {record.payload.country && (
+
+ País anteriormente registado:{' '}
+ {record.payload.country}. Conservado sem atribuir
+ automaticamente residência, constituição ou origem
+ da solicitação.
+
+ )}
+ {fields.map((key) => {
+ const fieldId = id + '-' + key,
+ error =
+ editor.errors['payload.' + key] ??
+ (key === 'incorporation_country_code'
+ ? editor.errors['payload.country']
+ : undefined),
+ long = [
+ 'description',
+ 'experience',
+ 'investment_capacity',
+ ].includes(key);
+ return (
+
+ {key.endsWith('_country_code') ? (
+
+ editor.change(key, value)
+ }
+ />
+ ) : long ? (
+
+ editor.change(
+ key,
+ event.target.value,
+ )
+ }
+ />
+ ) : (
+
+ editor.change(
+ key,
+ event.target.value,
+ )
+ }
+ />
+ )}
+ {!key.endsWith('_country_code') && error && (
+
+ {error}
+
+ )}
+
+ );
+ })}
+
+ {editor.error && {editor.error}
}
+ {Object.entries(editor.errors)
+ .filter(([key]) => !fieldErrorKeys.includes(key))
+ .map(([key, value]) => (
+
+ {value}
+
+ ))}
+ {editor.notice && {editor.notice}
}
+ {editor.stale && (
+
+ Existe uma versão mais recente deste registo. A sua
+ preparação foi conservada; consulte e compare antes de
+ guardar.
+
+ )}
+
+
+ {editor.uncertain
+ ? 'Repetir o mesmo pedido'
+ : isCompany
+ ? 'Guardar declaração da empresa'
+ : 'Guardar perfil de investimento'}
+
+ void editor.refresh()}
+ >
+ Consultar registo guardado
+
+
+ {editor.remote && (
+
+
+ Versão guardada: {editor.remote.version}; versão da
+ preparação: {editor.base.version}.
+
+
+
+
+ Campo
+ Preparação nesta página
+ Registo guardado
+
+
+
+ {fields
+ .filter(
+ (key) =>
+ editor.draft[key] !==
+ editor.remote?.payload[key],
+ )
+ .map((key) => (
+
+ {labels[key]}
+
+ {editor.draft[key] ||
+ 'Não informado'}
+
+
+ {editor.remote?.payload[key] ||
+ 'Não informado'}
+
+
+ ))}
+
+
+ {!editor.uncertain && (
+
+ editor.adopt(true)}
+ >
+ Usar versão actual e manter a preparação
+
+ {
+ if (
+ window.confirm(
+ 'Substituir a preparação desta página pelos valores guardados?',
+ )
+ )
+ editor.adopt(false);
+ }}
+ >
+ Carregar os valores guardados
+
+
+ )}
+
+ )}
+
+ {isCompany && record.id && (
+
+ )}
+ >
+ );
+}
diff --git a/resources/js/components/investor-guidance.tsx b/resources/js/components/investor-guidance.tsx
index 72ef7a0d..ca856b31 100644
--- a/resources/js/components/investor-guidance.tsx
+++ b/resources/js/components/investor-guidance.tsx
@@ -33,6 +33,7 @@ export type Guidance = {
rules_version: string;
computed_at: string;
can_write: boolean;
+ can_update_tasks?: boolean;
facts: Record;
financial_draft: Record | null;
consulted: {
@@ -725,21 +726,25 @@ export function InvestorGuidance({
Consultar o pedido e a resposta do responsável
)}
- {(manager || actorId === task.assignee_user_id) && (
- <>
-
- Resultado ou motivo
-
- setReason(e.target.value)
- }
- />
-
-
- {['in_progress', 'done', 'cancelled'].map(
- (status) => (
+ {guidance.can_update_tasks !== false &&
+ (manager || actorId === task.assignee_user_id) && (
+ <>
+
+ Resultado ou motivo
+
+ setReason(e.target.value)
+ }
+ />
+
+
+ {[
+ 'in_progress',
+ 'done',
+ 'cancelled',
+ ].map((status) => (
- ),
- )}
-
- >
- )}
+ ))}
+
+ >
+ )}
))}
{!guidance.tasks.length && (
diff --git a/resources/js/components/opportunity-technical-incidents.tsx b/resources/js/components/opportunity-technical-incidents.tsx
new file mode 100644
index 00000000..fd2d9d84
--- /dev/null
+++ b/resources/js/components/opportunity-technical-incidents.tsx
@@ -0,0 +1,81 @@
+import {
+ incidentOperationLabel,
+ incidentErrorLabel,
+} from '@/lib/technical-incident-labels';
+
+export type OpportunityTechnicalIncident = {
+ reference: string;
+ operation: string;
+ version: number;
+ occurred_at: string;
+ error_code: string;
+ handling?: {
+ version: number;
+ status: string;
+ updated_at: string | null;
+ } | null;
+};
+
+export default function OpportunityTechnicalIncidents({
+ incidents,
+}: {
+ incidents: OpportunityTechnicalIncident[];
+}) {
+ if (!incidents.length) return null;
+ return (
+
+
+ As minhas tentativas com falha técnica
+
+
+ Últimos dez registos desta conta. Consulte o estado actual antes
+ de repetir uma operação. Um incidente não confirma nem desfaz
+ uma gravação, submissão ou publicação.
+
+
+ Guarde a referência para acompanhamento. O Suporte técnico
+ consulta os incidentes no âmbito da sua atribuição e não altera
+ a decisão de investimento.
+
+ {incidents.map((incident) => (
+
+
+ {incidentOperationLabel(incident.operation)} · versão
+ observada {incident.version}
+
+ {incident.occurred_at}
+ {incident.handling ? (
+
+ Estado técnico:{' '}
+ {(
+ {
+ open: 'Na fila',
+ in_progress: 'Em tratamento',
+ resolved: 'Resolvido',
+ } as Record
+ )[incident.handling.status] || 'Não identificado'}
+
+ ) : (
+ Estado técnico indisponível para consulta.
+ )}
+ {incidentErrorLabel(incident.error_code)}
+ {incident.operation === 'scan_document' && (
+
+ O recurso já foi registado. Acompanhe o estado da
+ análise de segurança antes de pedir nova análise.
+
+ )}
+
+ Referência para acompanhamento: {incident.reference}
+
+
+ ))}
+
+ );
+}
diff --git a/resources/js/components/organization-country-editor.tsx b/resources/js/components/organization-country-editor.tsx
new file mode 100644
index 00000000..45c6941d
--- /dev/null
+++ b/resources/js/components/organization-country-editor.tsx
@@ -0,0 +1,233 @@
+import { useEffect, useId } from 'react';
+import CountrySelect, { type Country } from './country-select';
+import { Field, input, button, card } from '@/pages/investment/shared';
+import {
+ useInvestmentProfileEditor,
+ type OrganizationRecord,
+} from '@/lib/investment-profile-editor';
+
+export default function OrganizationCountryEditor({
+ organization,
+ countries,
+ actorId,
+ reportDirty,
+}: {
+ organization: OrganizationRecord;
+ countries: Country[];
+ actorId: number;
+ reportDirty: (id: string, dirty: boolean) => void;
+}) {
+ const fields = ['country', 'source_reference'];
+ const editor = useInvestmentProfileEditor(
+ {
+ id: organization.id,
+ version: organization.version,
+ payload: {
+ country: organization.country ?? '',
+ source_reference: organization.provenance?.reference ?? '',
+ },
+ },
+ fields,
+ false,
+ actorId,
+ 'organization-' + organization.id,
+ reportDirty,
+ organization,
+ );
+ const id = useId(),
+ disabled =
+ !editor.mayEdit ||
+ editor.busy ||
+ editor.uncertain ||
+ editor.blocked;
+ useEffect(() => {
+ if (Object.keys(editor.errors).length)
+ document
+ .getElementById(id)
+ ?.querySelector('[aria-invalid="true"]')
+ ?.focus();
+ }, [editor.errors, id]);
+ return (
+
+ {organization.name}
+
+ Versão guardada: {organization.version}.{' '}
+ {organization.provenance?.kind === 'representative_declaration'
+ ? 'País declarado pelo representante.'
+ : 'Fonte do país ainda não informada.'}
+
+ {!editor.mayEdit && (
+
+ Consulta do país de constituição. A sua representação actual
+ não permite alterar esta informação.
+
+ )}
+ {
+ event.preventDefault();
+ void editor.save();
+ }}
+ >
+
+
+ editor.change('country', country)
+ }
+ />
+
+
+ Fonte ou referência deste país
+
+
+ editor.change('source_reference', event.target.value)
+ }
+ />
+ {editor.errors.source_reference && (
+
+ {editor.errors.source_reference}
+
+ )}
+ {Object.entries(editor.errors)
+ .filter(([key]) => !fields.includes(key))
+ .map(([key, value]) => (
+
+ {value}
+
+ ))}
+ {editor.error && {editor.error}
}
+ {editor.notice && {editor.notice}
}
+ {editor.stale && (
+
+ O país ou outra informação da organização foi alterado.
+ A sua preparação foi conservada; consulte e compare
+ antes de guardar.
+
+ )}
+
+ {editor.mayEdit && (
+
+ {editor.uncertain
+ ? 'Repetir o mesmo pedido'
+ : 'Guardar país da organização'}
+
+ )}
+ void editor.refresh()}
+ >
+ Consultar país guardado
+
+
+ {editor.remote && (
+
+
+ Versão guardada: {editor.remote.version}; versão da
+ preparação: {editor.base.version}.
+
+
+
+
+ Campo
+ Preparação nesta página
+ Registo guardado
+
+
+
+ {fields
+ .filter(
+ (key) =>
+ editor.draft[key] !==
+ editor.remote?.payload[key],
+ )
+ .map((key) => (
+
+
+ {key === 'country'
+ ? 'País de constituição'
+ : 'Fonte ou referência'}
+
+
+ {editor.draft[key] ||
+ 'Não informado'}
+
+
+ {editor.remote?.payload[key] ||
+ 'Não informado'}
+
+
+ ))}
+
+
+ {editor.mayEdit && !editor.uncertain && (
+
+ editor.adopt(true)}
+ >
+ Usar versão actual e manter a preparação
+
+ {
+ if (
+ window.confirm(
+ 'Substituir a preparação desta organização pelos valores guardados?',
+ )
+ )
+ editor.adopt(false);
+ }}
+ >
+ Carregar os valores guardados
+
+
+ )}
+
+ )}
+
+
+ );
+}
diff --git a/resources/js/components/organization-country-reuse.tsx b/resources/js/components/organization-country-reuse.tsx
new file mode 100644
index 00000000..49d8e78e
--- /dev/null
+++ b/resources/js/components/organization-country-reuse.tsx
@@ -0,0 +1,155 @@
+import { button } from '@/pages/investment/shared';
+import { useOrganizationCountryReuse } from '@/lib/organization-country-reuse';
+import type {
+ useInvestmentProfileEditor,
+ OrganizationRecord,
+} from '@/lib/investment-profile-editor';
+
+export default function OrganizationCountryReuse({
+ companyId,
+ actorId,
+ organizations,
+ editor,
+ reportDirty,
+}: {
+ companyId: string;
+ actorId: number;
+ organizations: OrganizationRecord[];
+ editor: ReturnType;
+ reportDirty: (id: string, dirty: boolean) => void;
+}) {
+ const reuse = useOrganizationCountryReuse(
+ companyId,
+ actorId,
+ editor,
+ reportDirty,
+ organizations,
+ );
+ const preview = reuse.preview;
+ const sources = organizations.filter((source) => source.country);
+ if (
+ !organizations.length &&
+ !preview &&
+ !reuse.uncertain &&
+ !reuse.error &&
+ !reuse.notice
+ )
+ return null;
+ return (
+
+ Reutilizar o país de constituição
+
+ Escolha uma organização representada para consultar o país
+ guardado. A confirmação altera esta declaração; manifestações
+ anteriores conservam os seus valores.
+
+ {editor.dirty && !editor.externalBusy && (
+
+ Guarde ou confirme a preparação da declaração antes de
+ reutilizar o país.
+
+ )}
+ {!reuse.uncertain && (
+
+ {sources.map((source) => (
+ void reuse.inspect(source.id)}
+ >
+ Consultar país de {source.name}
+
+ ))}
+
+ )}
+ {!sources.length && !reuse.uncertain && (
+
+ Sem país guardado nas organizações representadas nesta
+ página.
+
+ )}
+ {reuse.error && {reuse.error}
}
+ {reuse.notice && {reuse.notice}
}
+ {reuse.sourceChanged && (
+
+ A organização foi alterada. Consulte novamente o país antes
+ de confirmar.
+
+ )}
+ {preview && (
+
+
+ Declaração: versão {preview.companyVersion}; país
+ actual: {preview.companyCountry || 'Não informado'}.
+
+
+ País a reutilizar: {preview.country}, de{' '}
+ {preview.organizationName}, versão{' '}
+ {preview.organizationVersion}.
+
+
+ Fonte ou referência:{' '}
+ {preview.reference ||
+ 'Não informada no registo guardado'}
+ .
+
+
+ void reuse.confirm()}
+ >
+ {reuse.uncertain
+ ? 'Repetir a mesma reutilização'
+ : 'Confirmar reutilização do país'}
+
+ {reuse.uncertain ? (
+
+ void reuse.inspect(
+ reuse.pendingOrganizationId ??
+ preview.organizationId,
+ )
+ }
+ >
+ Consultar estado da reutilização
+
+ ) : (
+
+ Cancelar preparação da reutilização
+
+ )}
+
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/partnership-agreement-instrument.tsx b/resources/js/components/partnership-agreement-instrument.tsx
new file mode 100644
index 00000000..b04ba9c4
--- /dev/null
+++ b/resources/js/components/partnership-agreement-instrument.tsx
@@ -0,0 +1,86 @@
+import { agreementParties, readAgreement } from '@/lib/partnership-agreement';
+
+export default function AgreementInstrument({ value }: { value: unknown }) {
+ const instrument = readAgreement(value);
+ if (instrument.kind === 'absent')
+ return Não ficou registado um instrumento nesta versão.
;
+ if (instrument.kind === 'malformed')
+ return (
+
+ O instrumento guardado não tem uma estrutura reconhecida. O
+ registo foi conservado.
+
+ );
+ return (
+
+
+ {instrument.title === null
+ ? 'Título não registado'
+ : instrument.title || 'Título não indicado'}
+
+
+ {instrument.terms === null
+ ? 'Condições não registadas'
+ : instrument.terms || 'Condições não indicadas'}
+
+ {instrument.confirmationsState === 'absent' ? (
+
As confirmações não ficaram registadas neste instrumento.
+ ) : instrument.confirmationsState === 'malformed' ? (
+
+ As confirmações guardadas não têm uma estrutura reconhecida.
+ O registo foi conservado.
+
+ ) : (
+ <>
+ {!Object.keys(instrument.confirmations).length && (
+
Confirmações: Pendentes
+ )}
+ {agreementParties.map((party) => {
+ const stamp = instrument.confirmations[party];
+ if (!stamp)
+ return (
+
+ {party === 'proponent'
+ ? 'Proponente'
+ : 'Candidata'}
+ : sem confirmação registada.
+
+ );
+ return (
+
+
+ {party === 'proponent'
+ ? 'Proponente'
+ : 'Candidata'}
+ :{' '}
+ {stamp.actorId === null
+ ? 'Registo de confirmação incompleto'
+ : `autor ${stamp.actorName ?? stamp.actorId}`}{' '}
+ · {stamp.date ?? 'Data não registada'}
+
+ {stamp.reason !== null && (
+
+ Motivo: {stamp.reason || 'Não indicado'}
+
+ )}
+
+ );
+ })}
+ {instrument.extraConfirmations && (
+
+ Existem referências adicionais no registo; não
+ substituem a confirmação de cada parte.
+
+ )}
+ >
+ )}
+
+ Estado de assinatura guardado:{' '}
+ {instrument.legalStatus === 'not_verified'
+ ? 'não verificada'
+ : (instrument.legalStatus ?? 'não registado')}
+ . Esta consulta não certifica assinatura jurídica.
+
+
+ );
+}
diff --git a/resources/js/components/partnership-candidacies.tsx b/resources/js/components/partnership-candidacies.tsx
new file mode 100644
index 00000000..d54c9265
--- /dev/null
+++ b/resources/js/components/partnership-candidacies.tsx
@@ -0,0 +1,730 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { Link, usePage } from '@inertiajs/react';
+import {
+ criterionValue,
+ useCandidacyEdit,
+ useCandidacyLeaveGuard,
+ type CandidacyEditor,
+} from '@/lib/partnership-candidacy-edit';
+import {
+ Field,
+ Errors,
+ control,
+ button,
+ labels,
+ type Interest,
+ type Catalogues,
+ type Partnership,
+} from '@/pages/partnerships/shared';
+export type CandidacyProps = {
+ record: Partnership;
+ owner: boolean;
+ canEdit: boolean;
+ acceptingInterests: boolean;
+ canStartInterest: boolean;
+ interests: Interest[];
+ organizations: Catalogues['organizations'];
+};
+type DraftReporter = (id: string, dirty: boolean) => void;
+function useReport(editor: CandidacyEditor, id: string, report: DraftReporter) {
+ useEffect(() => {
+ report(id, editor.dirty);
+ }, [report, id, editor.dirty]);
+ useEffect(() => () => report(id, false), [report, id]);
+}
+const submissionLabels: Record = {
+ organization_id: 'Participação',
+ proposal: 'Proposta curta',
+ capacity: 'Capacidade disponível',
+ availability: 'Disponibilidade',
+ contribution: 'Contribuição proposta',
+ conflicts: 'Conflitos de interesse declarados',
+ consent: 'Autorização de partilha',
+};
+function Comparison({
+ editor,
+ organizations,
+}: {
+ editor: CandidacyEditor;
+ organizations: Catalogues['organizations'];
+}) {
+ const label = (key: string) =>
+ key.startsWith('criterion:')
+ ? (editor.criterionLabels[key.slice('criterion:'.length)] ??
+ 'Critério já indisponível')
+ : (submissionLabels[key] ?? 'Motivo da acção');
+ const display = (key: string, value: string | undefined) =>
+ key.startsWith('criterion:')
+ ? `${labels[criterionValue(value).state]} — ${criterionValue(value).evidence || 'Sem referência de evidência'}`
+ : key === 'organization_id'
+ ? value
+ ? (organizations.find(
+ (organization) => organization.id === value,
+ )?.name ?? 'Organização já indisponível')
+ : 'Sem organização indicada'
+ : key === 'consent'
+ ? value === 'yes'
+ ? 'Autorizada'
+ : 'Não autorizada'
+ : value || 'Não indicado';
+ return (
+
+
+ Comparar com os dados actuais da candidatura
+
+ {editor.problem &&
{editor.problem}
}
+ {editor.invalid && (
+
+ A candidatura não está disponível para este formulário com o
+ acesso actual. A preparação foi conservada e a gravação está
+ suspensa.
+
+ )}
+ {!editor.editable && editor.dirty && (
+
+ O estado ou acesso actual não permite novas alterações. A
+ preparação abaixo foi conservada em memória, sem nova
+ autorização.
+
+ )}
+ {editor.refreshing && (
+
A recuperar sem apagar a preparação.
+ )}
+ {editor.stale && (
+ <>
+
+ A candidatura, a parceria ou os critérios foram
+ alterados. Reveja as declarações e os requisitos actuais
+ antes de continuar.
+
+ {editor.changed.length > 0 && (
+
+
+
+
+ Campo
+ Actualmente guardado
+ Sua preparação
+ Escolha
+
+
+
+ {editor.changed.map((key) => (
+
+ {label(key)}
+
+ {display(
+ key,
+ editor.current[key],
+ )}
+
+
+ {display(
+ key,
+ editor.values[key],
+ )}
+
+
+ {editor.conflicts.includes(
+ key,
+ ) ? (
+ <>
+
+ editor.choose(
+ key,
+ 'current',
+ )
+ }
+ >
+ Usar valor actual
+ {' '}
+
+ editor.choose(
+ key,
+ 'mine',
+ )
+ }
+ >
+ Manter minha
+ alteração
+
+ {editor.unresolved.includes(
+ key,
+ ) && (
+
+ Escolha o valor
+ a conservar.
+
+ )}
+ >
+ ) : (
+ 'Actualização compatível'
+ )}
+
+
+ ))}
+
+
+
+ )}
+
0
+ }
+ onClick={editor.adopt}
+ >
+ Usar este contexto e conservar as alterações escolhidas
+
+ >
+ )}
+ {editor.retired.length > 0 && (
+
+
+ Critérios anteriores conservados apenas nesta preparação
+
+ {editor.retired.map((key) => (
+
+ {label(key)}: {display(key, editor.values[key])}
+
+ ))}
+
+ Estes critérios já não pertencem à avaliação actual e
+ não serão enviados.
+
+
+ Descartar preparação dos critérios anteriores
+
+
+ Esta acção só descarta a preparação local; não altera o
+ histórico guardado.
+
+
+ )}
+ {editor.recovering && (
+
+ Recuperar repete o pedido original. As alterações escritas
+ depois do envio ficam para uma próxima operação.
+
+ )}
+
+ );
+}
+function Submission({
+ p,
+ recordId,
+ interestId = null,
+ actorId,
+ report,
+ onCreated,
+ suppressed = false,
+}: {
+ p: CandidacyProps;
+ recordId: number;
+ interestId?: number | null;
+ actorId: number | null;
+ report: DraftReporter;
+ onCreated?: (id: number | null) => void;
+ suppressed?: boolean;
+}) {
+ const editor = useCandidacyEdit({
+ props: p,
+ recordId,
+ interestId,
+ mode: 'submission',
+ actorId,
+ });
+ const draftId = 'submission:' + (interestId ?? 'new');
+ useReport(editor, draftId, report);
+ useEffect(() => {
+ onCreated?.(editor.activeId);
+ }, [onCreated, editor.activeId]);
+ const fresh = interestId === null;
+ const available = fresh
+ ? p.interests.length === 0 || editor.activeId !== null
+ : true;
+ if (
+ (!available || suppressed || !editor.editable) &&
+ !editor.dirty &&
+ !editor.problem
+ )
+ return null;
+ const interest = p.interests.find(
+ (candidate) => candidate.id === (interestId ?? editor.activeId),
+ );
+ return (
+ {
+ event.preventDefault();
+ editor.submit();
+ }}
+ >
+
+ {editor.activeId === null
+ ? 'Manifestar interesse'
+ : 'Actualizar manifestação de interesse'}
+
+
+ Declarações são informações comunicadas por si; não atribuem
+ verificação. Dados desconhecidos podem ser esclarecidos no
+ processo.
+
+ {editor.activeId !== null && (
+
+ Voltar a submeter cria uma nova versão e reinicia a
+ avaliação actual. Esta operação conserva a versão anterior
+ no histórico de auditoria.
+
+ )}
+
+
+
+
+ editor.change('organization_id', event.target.value)
+ }
+ >
+ Sem organização indicada
+ {editor.values.organization_id &&
+ !p.organizations.some(
+ (organization) =>
+ organization.id ===
+ editor.values.organization_id,
+ ) && (
+
+ Organização já indisponível
+
+ )}
+ {p.organizations.map((organization) => (
+
+ {organization.name}
+
+ ))}
+
+
+ {interest?.organization_id &&
+ !editor.values.organization_id && (
+
+ Retirar a organização conserva o autor registado da
+ candidatura; a edição passa a depender desse autor,
+ conforme a regra de participação pessoal.
+
+ )}
+
+
+ editor.change('proposal', event.target.value)
+ }
+ />
+
+ {(
+ [
+ 'capacity',
+ 'availability',
+ 'contribution',
+ 'conflicts',
+ ] as const
+ ).map((key) => (
+
+
+ editor.change(key, event.target.value)
+ }
+ />
+
+ ))}
+
+
+ editor.change(
+ 'consent',
+ event.target.checked ? 'yes' : 'no',
+ )
+ }
+ />{' '}
+ Autorizo a partilha desta candidatura com o responsável pela
+ parceria.
+
+
+
+
+ {editor.recovering
+ ? 'Recuperar submissão enviada'
+ : 'Guardar interesse'}
+
+
+ );
+}
+function Decision({
+ p,
+ recordId,
+ interestId,
+ actorId,
+ report,
+}: {
+ p: CandidacyProps;
+ recordId: number;
+ interestId: number;
+ actorId: number | null;
+ report: DraftReporter;
+}) {
+ const editor = useCandidacyEdit({
+ props: p,
+ recordId,
+ interestId,
+ mode: 'decision',
+ actorId,
+ });
+ useReport(editor, 'decision:' + interestId, report);
+ if (!editor.editable && !editor.dirty && !editor.problem) return null;
+ const unrecorded = editor.criteria.some(
+ (criterion) =>
+ editor.values['criterion:' + criterion.code] !==
+ editor.current['criterion:' + criterion.code],
+ );
+ return (
+
+
+
+ {editor.ownerMode && (
+
+ Registar avaliação fundamentada
+ {editor.criteria.map((criterion) => {
+ const value = criterionValue(
+ editor.values['criterion:' + criterion.code],
+ );
+ return (
+
+
+
+ editor.changeCriterion(
+ criterion.code,
+ 'state',
+ event.target.value,
+ )
+ }
+ >
+ {['unknown', 'met', 'unmet'].map(
+ (state) => (
+
+ {labels[state]}
+
+ ),
+ )}
+
+
+
+
+ editor.changeCriterion(
+ criterion.code,
+ 'evidence',
+ event.target.value,
+ )
+ }
+ />
+
+
+ );
+ })}
+
+ )}
+
+
+ editor.change('reason', event.target.value)
+ }
+ />
+
+ {editor.ownerMode && unrecorded && (
+
+ Existem alterações de avaliação ainda por guardar. As
+ outras decisões usam a avaliação actualmente guardada,
+ apresentada acima.
+
+ )}
+
+
+ {editor.recovering ? (
+ editor.submit()}
+ >
+ Recuperar acção enviada
+
+ ) : (
+
+ {(editor.ownerMode
+ ? [
+ 'assess',
+ 'clarify',
+ 'shortlist',
+ 'reject',
+ ...(editor.status === 'shortlisted'
+ ? ['connect']
+ : []),
+ ]
+ : ['withdraw']
+ ).map((action) => (
+ editor.submit(action)}
+ >
+ {
+ {
+ assess: 'Guardar avaliação',
+ clarify: 'Pedir esclarecimento',
+ shortlist: 'Adicionar à lista curta',
+ reject: 'Não seleccionar',
+ connect: 'Abrir negociação',
+ withdraw: 'Retirar candidatura',
+ }[action]
+ }
+
+ ))}
+
+ )}
+
+ );
+}
+function Card({
+ p,
+ id,
+ recordId,
+ actorId,
+ report,
+ suppressed,
+}: {
+ p: CandidacyProps;
+ id: number;
+ recordId: number;
+ actorId: number | null;
+ report: DraftReporter;
+ suppressed: boolean;
+}) {
+ const interest = p.interests.find((interest) => interest.id === id);
+ const score =
+ interest &&
+ interest.match.score_min !== null &&
+ interest.match.score_max !== null
+ ? `${interest.match.score_min}–${interest.match.score_max}%`
+ : 'Por determinar';
+ return (
+
+ {interest ? (
+ <>
+
+ Candidatura {interest.id} · {labels[interest.status]}
+
+ {interest.proposal}
+
+ Consultar versões e decisões
+
+ {interest.payload.capacity}
+
+ Disponibilidade:{' '}
+ {interest.payload.availability || 'Por esclarecer'}
+
+
+ Contribuição:{' '}
+ {interest.payload.contribution || 'Por esclarecer'}
+
+
+ Conflitos declarados:{' '}
+ {interest.payload.conflicts || 'Sem informação'}
+
+ {interest.decision_reason && (
+ Última decisão: {interest.decision_reason}
+ )}
+
+ Correspondência: {score} · Elegibilidade:{' '}
+ {labels[interest.match.eligibility]}. O intervalo
+ distingue dados desconhecidos de incumprimentos; não é
+ uma aprovação.
+
+
+ {interest.room_id && (
+
+ Abrir conexão privada
+
+ )}
+ >
+ ) : (
+
+ Esta candidatura deixou de estar disponível para consulta
+ nesta conta. A preparação local foi conservada; não é uma
+ autorização de acesso.
+
+ )}
+
+
+
+ );
+}
+export default function PartnershipCandidacies({
+ p,
+ otherDirty = false,
+}: {
+ p: CandidacyProps;
+ otherDirty?: boolean;
+}) {
+ const { auth } = usePage<{ auth: { user: { id: number } | null } }>().props;
+ const openedRecord = useRef(p.record.id);
+ const [drafts, setDrafts] = useState>({});
+ const [created, setCreated] = useState(null);
+ const report = useCallback((id: string, dirty: boolean) => {
+ setDrafts((previous) =>
+ (previous[id] ?? false) === dirty
+ ? previous
+ : { ...previous, [id]: dirty },
+ );
+ }, []);
+ const onCreated = useCallback((id: number | null) => setCreated(id), []);
+ const retained = Object.entries(drafts)
+ .filter(([key, dirty]) => dirty && !key.endsWith(':new'))
+ .map(([key]) => Number(key.split(':')[1]))
+ .filter(Number.isSafeInteger);
+ const ids = [
+ ...new Set([
+ ...p.interests.map((interest) => interest.id),
+ ...retained,
+ ]),
+ ];
+ useCandidacyLeaveGuard(otherDirty || Object.values(drafts).some(Boolean));
+ return (
+
+ {p.record.id !== openedRecord.current && (
+
+ A resposta não corresponde à parceria aberta. A preparação
+ foi conservada e os comandos estão suspensos.
+
+ )}
+ {ids.map((id) => (
+
+ ))}
+
+
+ );
+}
diff --git a/resources/js/components/partnership-edit-comparison.tsx b/resources/js/components/partnership-edit-comparison.tsx
new file mode 100644
index 00000000..b7f86203
--- /dev/null
+++ b/resources/js/components/partnership-edit-comparison.tsx
@@ -0,0 +1,275 @@
+import type {
+ PartnershipEditor,
+ PartnershipSection,
+} from '@/lib/partnership-edit';
+import { labels, type Catalogues } from '@/pages/partnerships/shared';
+
+const fields: Record = {
+ title: 'Título',
+ offer: 'Recursos que oferece',
+ seeking: 'Colaboração que procura',
+ organization_id: 'Organização representada',
+ sector_id: 'Sector',
+ kind: 'Oferta ou procura',
+ partnership_type: 'Tipo de parceria',
+ deadline: 'Prazo para manifestações de interesse',
+ summary: 'Resumo',
+ requirements: 'Requisitos desejáveis',
+ mandatory: 'Critérios obrigatórios',
+ confidentiality: 'Visibilidade',
+ consent: 'Autorização de divulgação',
+ availability: 'Disponibilidade dos recursos ou colaboração',
+ locations: 'Localizações e respectivas fontes',
+ origins: 'Origens documentais',
+};
+export default function PartnershipEditComparison({
+ editor,
+ catalogues,
+}: {
+ editor: PartnershipEditor;
+ catalogues: Catalogues;
+}) {
+ function display(
+ key: PartnershipSection,
+ value: PartnershipEditor['values'][PartnershipSection],
+ ): string {
+ if (typeof value === 'boolean')
+ return value ? 'Autorização indicada' : 'Sem autorização indicada';
+ if (Array.isArray(value))
+ return value.length
+ ? value
+ .map((item) => {
+ if (typeof item === 'string')
+ return (
+ catalogues.criteria[item] ??
+ 'Critério anterior fora da configuração actual'
+ );
+ if ('geo_location_id' in item)
+ return `${catalogues.territories.find((place) => place.id === item.geo_location_id)?.name ?? 'Localização anteriormente indicada'} · ${{ primary: 'Principal', operating: 'Operação', coverage: 'Cobertura' }[item.role] ?? item.role} · ${item.source_reference}`;
+ return (
+ catalogues.sources?.find(
+ (source) =>
+ source.type === item.type &&
+ source.target_id === item.target_id,
+ )?.title ??
+ 'Origem documental anteriormente associada'
+ );
+ })
+ .join('\n')
+ : 'Nenhuma selecção';
+ if (!value) return 'Não indicado';
+ if (key === 'organization_id')
+ return (
+ catalogues.organizations.find(
+ (item) => String(item.id) === value,
+ )?.name ?? 'Organização anteriormente indicada'
+ );
+ if (key === 'sector_id')
+ return (
+ catalogues.sectors.find((item) => String(item.id) === value)
+ ?.name ?? 'Sector anteriormente indicado'
+ );
+ if (key === 'partnership_type')
+ return (
+ catalogues.types[value] ??
+ 'Tipo anterior fora da configuração actual'
+ );
+ if (key === 'kind')
+ return value === 'offering'
+ ? 'Oferta'
+ : value === 'seeking'
+ ? 'Procura'
+ : value;
+ if (key === 'confidentiality')
+ return value === 'private'
+ ? 'Privada'
+ : value === 'public'
+ ? 'Pública'
+ : value;
+ return value;
+ }
+ return (
+
+ {editor.problem && {editor.problem}
}
+ {editor.invalid && (
+
+ Os dados desta edição não foram reconhecidos. Reabra a
+ parceria correcta antes de guardar; a edição actual foi
+ conservada.
+
+ )}
+ {editor.retryingCreation && (
+
+ Repita a criação anterior para recuperar o registo. O pedido
+ anterior será reutilizado, sem substituir as suas edições
+ posteriores nem criar outra parceria.
+
+ )}
+ {editor.retryingSave && (
+
+
+ A edição anterior não foi confirmada. Recuperar repete
+ exactamente a mesma tentativa e conserva o que preparou
+ depois de enviar.
+
+
+ Recuperar a mesma gravação
+
+
+ )}
+ {editor.mustRefresh && (
+
+ Consulte os dados actuais antes de adoptar uma versão para
+ uma nova tentativa.
+
+ )}
+ {editor.refreshing && (
+
+ A recuperar os dados actuais. As suas edições são
+ conservadas.
+
+ )}
+
+ Comparar com os dados actuais
+
+ {editor.current && !editor.editable && (
+
+ Estado actual:{' '}
+ {labels[editor.current.status] ?? 'Estado por confirmar'}. A
+ parceria está disponível para consulta; a edição por guardar
+ foi conservada e não pode ser gravada neste estado.
+
+ )}
+ {editor.current?.status === 'published' && (
+
+ Ao guardar esta revisão, a proposta volta a rascunho e
+ requer nova submissão e revisão pelo percurso existente.
+
+ )}
+ {(editor.stale || editor.retryingSave) && (
+ <>
+
+ A proposta mudou desde{' '}
+ {editor.baseVersion === null
+ ? 'a preparação inicial'
+ : `a versão ${editor.baseVersion}`}
+ . Compare com a versão {editor.current?.version} e
+ escolha como conservar os seus dados.
+
+
+
+
+
+ Campo
+ Actualmente guardado
+ Sua edição
+ Escolha
+
+
+
+ {editor.changed.map((key) => (
+
+
+ {fields[key]}
+
+
+ {editor.current &&
+ display(
+ key,
+ editor.current.values[key],
+ )}
+
+
+ {display(key, editor.values[key])}
+
+
+ {editor.conflicts.includes(key) ? (
+ <>
+
+ editor.choose(
+ key,
+ 'current',
+ )
+ }
+ >
+ Usar valor actual
+
+
+ editor.choose(
+ key,
+ 'mine',
+ )
+ }
+ >
+ Manter minha alteração
+
+ {editor.unresolved.includes(
+ key,
+ ) && (
+
+ Escolha o valor a
+ conservar neste
+ campo.
+
+ )}
+ >
+ ) : (
+ 'Actualização compatível com a sua edição'
+ )}
+
+
+ ))}
+
+
+
+ 0
+ }
+ onClick={editor.adopt}
+ >
+ Usar esta versão e conservar as alterações escolhidas
+
+ >
+ )}
+
+ );
+}
diff --git a/resources/js/components/partnership-publication-summary.tsx b/resources/js/components/partnership-publication-summary.tsx
new file mode 100644
index 00000000..d85b5861
--- /dev/null
+++ b/resources/js/components/partnership-publication-summary.tsx
@@ -0,0 +1,85 @@
+import { Link } from '@inertiajs/react';
+import {
+ publicationHistoryActions,
+ type PublicationHistorySummary,
+} from '@/lib/partnership-history';
+import { labels } from '@/pages/partnerships/shared';
+
+const status = (value: string | null) =>
+ value === null
+ ? 'Estado não registado ou reservado'
+ : (labels[value] ?? 'Estado não identificado no registo');
+export default function PublicationSummary({
+ value,
+}: {
+ value: PublicationHistorySummary;
+}) {
+ return (
+
+ Histórico e decisões
+
+ Até {value.limit}{' '}
+ {value.limit === 1
+ ? 'alteração mais recente'
+ : 'alterações mais recentes'}
+ . Os nomes são os disponíveis no cadastro actual; as decisões e
+ motivos são os que ficaram guardados.
+
+ {!value.entries.length ? (
+ Ainda não existem alterações guardadas para apresentar.
+ ) : (
+
+ {value.entries.map((entry, index) => (
+
+
+ Versão {entry.version ?? 'não registada'} ·{' '}
+ {entry.restricted
+ ? 'Conteúdo reservado'
+ : (publicationHistoryActions[
+ entry.action ?? ''
+ ] ?? 'Alteração registada')}
+
+ {entry.restricted ? (
+
+ Os dados desta alteração não estão
+ disponíveis para esta conta. Consulte o
+ histórico para conhecer os limites do
+ registo.
+
+ ) : (
+ <>
+
+ {entry.actor_name ??
+ 'Autor não registado'}{' '}
+ ·{' '}
+ {entry.occurred_at ??
+ 'Data não registada'}
+
+
+ {status(entry.status_before)} →{' '}
+ {status(entry.status_after)}
+
+ {entry.reason !== null && (
+
+ Motivo:{' '}
+ {entry.reason || 'Não indicado'}
+
+ )}
+ >
+ )}
+
+ ))}
+
+ )}
+ {value.has_more && (
+ Existem alterações anteriores no histórico completo.
+ )}
+
+ Consultar versões e decisões da publicação
+
+
+ );
+}
diff --git a/resources/js/components/partnership-publication.tsx b/resources/js/components/partnership-publication.tsx
new file mode 100644
index 00000000..27adf169
--- /dev/null
+++ b/resources/js/components/partnership-publication.tsx
@@ -0,0 +1,210 @@
+import { Link } from '@inertiajs/react';
+import { useEffect } from 'react';
+import {
+ usePublication,
+ type PublicationProps,
+} from '@/lib/partnership-publication';
+import {
+ Field,
+ Errors,
+ control,
+ button,
+ labels,
+} from '@/pages/partnerships/shared';
+const actions: Record = {
+ submit: 'Submeter para publicação',
+ publish: 'Publicar',
+ return: 'Devolver para correcção',
+ reject: 'Rejeitar com fundamento',
+ suspend: 'Suspender publicação',
+ archive: 'Arquivar publicação',
+ renew: 'Renovar em rascunho',
+};
+const fields: Record = {
+ title: 'Título',
+ offer: 'Oferta',
+ seeking: 'Procura',
+ kind: 'Oferta ou procura',
+ partnership_type: 'Tipo de parceria',
+ sector_id: 'Referência do sector',
+ organization_id: 'Referência da organização',
+ deadline: 'Prazo',
+ summary: 'Resumo público',
+ requirements: 'Requisitos',
+ confidentiality: 'Partilha dos detalhes',
+ availability: 'Disponibilidade',
+ consent: 'Autorização de partilha',
+ mandatory: 'Critérios obrigatórios',
+ origins: 'Origens',
+ locations: 'Localizações',
+};
+export default function PartnershipPublication({
+ p,
+ actorId,
+ onDirty,
+}: {
+ p: PublicationProps;
+ actorId: number;
+ onDirty: (value: boolean) => void;
+}) {
+ const edit = usePublication(p, actorId);
+ useEffect(() => {
+ onDirty(edit.dirty);
+ }, [edit.dirty, onDirty]);
+ useEffect(() => () => onDirty(false), [onDirty]);
+ if (!edit.dirty && !p.owner && !p.moderator) return null;
+ const active = edit.current?.actions ?? [];
+ return (
+
+ Pré-visualização e publicação
+
+ Estado: {labels[p.record.status] ?? p.record.status}.
+ Verificação da organização, sector e localização permanecem por
+ confirmar quando não há evidência.
+
+
+ A acção aplica-se à versão revista da proposta. Submeter
+ encaminha para moderação; renovar prepara um rascunho. Estas
+ acções não decidem candidaturas nem alteram salas ou marcos.
+
+
+ Comparar com a proposta actual
+
+ {edit.problem && {edit.problem}
}
+ {edit.invalid && (
+
+ A resposta ou conta actual não corresponde a esta
+ preparação. A gravação está suspensa.
+
+ )}
+ {(edit.stale || edit.needsCompare || edit.recovery) && (
+
+
+ Reveja o contexto antes de outra acção. O motivo
+ preparado foi conservado.
+
+
+ Versão revista: {edit.base?.version} ·{' '}
+ {labels[edit.base?.status ?? '']} → Actual:{' '}
+ {edit.current?.version} ·{' '}
+ {labels[edit.current?.status ?? '']}
+
+ {edit.changes.length > 0 && (
+
+
+
+
+ Campo
+ Antes
+ Actualmente
+
+
+
+ {edit.changes.map((key) => (
+
+ {fields[key] ?? key}
+
+ {edit.base?.values[key] ||
+ 'Não indicado'}
+
+
+ {edit.current?.values[key] ||
+ 'Não indicado'}
+
+
+ ))}
+
+
+
+ )}
+
+ Adoptar esta versão conserva o motivo e permite preparar
+ uma nova tentativa. Uma tentativa anterior sem
+ confirmação deixa de ser recuperada por este formulário;
+ o seu registo no processo mantém-se.
+
+ {edit.mustRefresh && (
+
+ Compare com a proposta actual antes de adoptar uma
+ nova versão.
+
+ )}
+
+ Revi esta versão; conservar o motivo e preparar nova
+ acção
+
+
+ )}
+ {(active.length > 0 || edit.dirty) && (
+
+ edit.change(event.target.value)}
+ />
+
+ )}
+ {!active.length && edit.dirty && (
+
+ O estado ou acesso actual não permite nova acção. O motivo
+ preparado foi conservado em memória.
+
+ )}
+
+ {edit.recovery && (
+ edit.send(edit.recovery!, true)}
+ >
+ Recuperar a mesma tentativa: {actions[edit.recovery]}
+
+ )}
+
+ {active.map((action) => (
+ edit.send(action)}
+ >
+ {actions[action]}
+
+ ))}
+ {p.canEdit && (
+
+ Editar rascunho
+
+ )}
+
+
+ );
+}
diff --git a/resources/js/components/partnership-room-comparison.tsx b/resources/js/components/partnership-room-comparison.tsx
new file mode 100644
index 00000000..0663693b
--- /dev/null
+++ b/resources/js/components/partnership-room-comparison.tsx
@@ -0,0 +1,175 @@
+import type { RoomEditor } from '@/lib/partnership-room-edit';
+import { labels as states } from '@/pages/partnerships/shared';
+export default function RoomComparison({
+ editor,
+ labels,
+ display = (_key, value) => value || 'Não indicado',
+}: {
+ editor: RoomEditor;
+ labels: Record;
+ display?: (key: string, value: string) => string;
+}) {
+ return (
+
+
+ Comparar com os dados actuais da sala
+
+ {editor.problem &&
{editor.problem}
}
+ {editor.pendingAction && (
+
+
+ A acção anterior não foi confirmada. Recuperar repete a
+ tentativa original sem substituir a preparação
+ posterior.
+
+
+ Recuperar a mesma acção
+
+
+ )}
+ {editor.mustRefresh && (
+
+ Consulte o contexto actual antes de adoptar uma nova
+ tentativa.
+
+ )}
+ {editor.invalid && (
+
+ Este registo não foi recuperado correctamente. As edições
+ foram conservadas e a gravação está suspensa.
+
+ )}
+ {!editor.editable && editor.dirty && (
+
+ O estado ou o acesso actual não permite editar este registo.
+ A preparação abaixo foi conservada em memória; não foi
+ gravada.
+
+ )}
+ {editor.refreshing && (
+
A recuperar sem apagar a sua preparação.
+ )}
+ {(editor.stale || editor.pendingAction) && (
+ <>
+
+ O registo ou o contexto da sala mudou. Compare os dados
+ antes de continuar. Estado actual:{' '}
+ {states[editor.status ?? ''] ?? 'Por recuperar'}.
+
+ {editor.changed.length > 0 && (
+
+
+
+
+ Campo
+ Actualmente guardado
+ Sua edição
+ Escolha
+
+
+
+ {editor.changed.map((key) => (
+
+ {labels[key] ?? key}
+
+ {display(
+ key,
+ editor.current[key],
+ )}
+
+
+ {display(
+ key,
+ editor.values[key],
+ )}
+
+
+ {editor.conflicts.includes(
+ key,
+ ) ? (
+ <>
+
+ editor.choose(
+ key,
+ 'current',
+ )
+ }
+ >
+ Usar valor actual
+ {' '}
+
+ editor.choose(
+ key,
+ 'mine',
+ )
+ }
+ >
+ Manter minha
+ alteração
+
+ {editor.unresolved.includes(
+ key,
+ ) && (
+
+ Escolha o valor
+ a conservar.
+
+ )}
+ >
+ ) : (
+ 'Actualização compatível'
+ )}
+
+
+ ))}
+
+
+
+ )}
+
0 ||
+ editor.mustRefresh ||
+ editor.invalid
+ }
+ onClick={editor.adopt}
+ >
+ Usar este contexto e conservar as alterações escolhidas
+
+ >
+ )}
+ {editor.recovering && (
+
+ A criação não foi confirmada. Recuperar repete a chave e o
+ conteúdo originais; alterações posteriores ficam como
+ preparação de outro marco.
+
+ )}
+ {editor.created !== null && (
+
+ O marco foi confirmado na lista desta sala. Alterações
+ feitas depois do envio foram conservadas como nova
+ preparação; o marco criado pode ser editado na lista.
+
+ )}
+
+ );
+}
diff --git a/resources/js/components/proactive-supply.tsx b/resources/js/components/proactive-supply.tsx
index be81af16..00eca32e 100644
--- a/resources/js/components/proactive-supply.tsx
+++ b/resources/js/components/proactive-supply.tsx
@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react';
+import { Link } from '@inertiajs/react';
import { button, control, Field } from '@/pages/management/shared';
import { createOperationKey } from '@/lib/operation-key';
import type { ProactiveAnalysis } from './proactive-investment';
@@ -45,7 +46,9 @@ export function ProactiveSupplyBrowser({
}) {
const [activity, setActivity] = useState('');
const [sector, setSector] = useState('');
- const [result, setResult] = useState(null);
+ const [loaded, setLoaded] = useState<{ key: string; data: Result } | null>(
+ null,
+ );
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
const [query, setQuery] = useState<{
@@ -54,8 +57,14 @@ export function ProactiveSupplyBrowser({
sector: string;
page: number;
} | null>(null);
+ const requestKey =
+ query?.territory === territoryId
+ ? JSON.stringify([recordId, query])
+ : '';
+ const result =
+ requestKey && loaded?.key === requestKey ? loaded.data : null;
useEffect(() => {
- setResult(null);
+ setLoaded(null);
setQuery(null);
setSector('');
setError('');
@@ -87,10 +96,13 @@ export function ProactiveSupplyBrowser({
);
return r.json() as Promise;
})
- .then(setResult)
+ .then((data) => {
+ if (!controller.signal.aborted)
+ setLoaded({ key: JSON.stringify([recordId, query]), data });
+ })
.catch((e) => {
- if (e.name !== 'AbortError') {
- setResult(null);
+ if (!controller.signal.aborted && e.name !== 'AbortError') {
+ setLoaded(null);
setError(e.message);
}
})
@@ -143,6 +155,15 @@ export function ProactiveSupplyBrowser({
return (
Consultar oferta existente — base interna
+
+ Conferir origens, repetições e correspondências por resolver
+
Consulta a localização escolhida nesta ficha e os seus
territórios subordinados. Os filtros por sector e actividade CAE
diff --git a/resources/js/components/profile-navigation.tsx b/resources/js/components/profile-navigation.tsx
index 17232111..4e04c727 100644
--- a/resources/js/components/profile-navigation.tsx
+++ b/resources/js/components/profile-navigation.tsx
@@ -22,6 +22,19 @@ export function profileLinks(access: ProfileAccess | null | undefined) {
...(access.audit
? [{ title: 'Auditoria de acessos', href: access.audit }]
: []),
+ ...(access.technicalSupport
+ ? [
+ {
+ title:
+ typeof access.technicalSupportUnread === 'number' &&
+ Number.isSafeInteger(access.technicalSupportUnread) &&
+ access.technicalSupportUnread > 0
+ ? `Suporte técnico · ${access.technicalSupportUnread} por consultar`
+ : 'Suporte técnico',
+ href: access.technicalSupport,
+ },
+ ]
+ : []),
...(access.administration
? [{ title: 'Gestão de perfis', href: access.administration }]
: []),
diff --git a/resources/js/components/search-usage-report.tsx b/resources/js/components/search-usage-report.tsx
new file mode 100644
index 00000000..9143b01a
--- /dev/null
+++ b/resources/js/components/search-usage-report.tsx
@@ -0,0 +1,118 @@
+import { usageValue, type SearchUsageReport } from '@/lib/product-usage';
+import { card } from '@/pages/investment/shared';
+
+export default function SearchUsage({ search }: { search: SearchUsageReport }) {
+ return (
+
+
+ Pesquisas — respostas registadas
+
+
+ Uma resposta HTTP de primeira página com critérios explícitos é
+ a unidade desta medição. Repetições e actualizações contam
+ novamente; pessoas, bots e pesquisas únicas não são
+ identificados.
+
+
+ Edição: {search.definition_version}. Dias {search.from} a{' '}
+ {search.to}, em {search.timezone}. Leitura em {search.read_at}.
+ As contagens diárias usam o snapshot do relatório; o dia actual
+ é parcial e não há corte por fracção de segundo.
+
+ {!search.installed && (
+
+ Ainda não há dados de recolha disponíveis neste destino.
+
+ )}
+ {!search.enabled_now && (
+
+ A recolha está desligada neste momento. O histórico
+ registado mantém-se disponível.
+
+ )}
+ {!search.applicable && (
+
+ Estas pesquisas públicas não têm associação comprovada ao
+ serviço do Balcão seleccionado. Os valores não são
+ calculados para esse filtro.
+
+ )}
+ {search.definition_conflict_now && (
+
+ A definição desta edição foi preservada. Uma configuração
+ diferente com o mesmo identificador não acrescenta contagens
+ a esta série.
+
+ )}
+
+ Respostas: {usageValue(search.responses)}. Sem resultados
+ principais: {usageValue(search.zero_responses)}. Taxa entre
+ respostas registadas: {usageValue(search.zero_rate, '%')}.
+
+
+ Cobertura parcial: falhas de recolha podem deixar respostas por
+ contar. Sem registos de medição não significa zero pesquisas.
+
+
+
+
+ Canais públicos instrumentados nesta edição
+
+
+
+ Canal
+ Respostas
+ Sem resultados principais
+ Taxa na base registada
+
+ Primeira / última observação no período
+
+
+
+
+ {search.channels.map((channel) => (
+
+
+ {channel.label}
+
+
+ {usageValue(channel.responses)}
+
+
+ {usageValue(channel.zero_responses)}
+
+
+ {usageValue(channel.zero_rate, '%')}
+
+
+ {channel.first_recorded_at ? (
+ <>
+ {channel.first_recorded_at}
+
+ {channel.last_recorded_at}
+ >
+ ) : (
+ 'Sem registos'
+ )}
+
+
+ ))}
+
+
+
+
+
+ Âmbito, exclusões e interpretação
+
+
+ {[...search.limits, ...search.exclusions].map((text) => (
+ {text}
+ ))}
+
+
+
+ );
+}
diff --git a/resources/js/components/similar-businesses.tsx b/resources/js/components/similar-businesses.tsx
index d21b196d..cfe2ea11 100644
--- a/resources/js/components/similar-businesses.tsx
+++ b/resources/js/components/similar-businesses.tsx
@@ -7,13 +7,22 @@ type Match = {
slug: string;
title: string;
published_at?: string | null;
+ distance_km?: number | null;
+ location_recorded_at?: string | null;
+ location_source_reference?: string | null;
+ location_source_date?: string | null;
};
function publicationDate(value?: string | null): string | null {
if (typeof value !== 'string' || !value.trim()) return null;
const date = new Date(value);
return Number.isNaN(date.getTime())
? null
- : date.toLocaleDateString('pt-MZ');
+ : date.toLocaleDateString(
+ 'pt-MZ',
+ /^\d{4}-\d{2}-\d{2}$/.test(value)
+ ? { timeZone: 'UTC' }
+ : undefined,
+ );
}
type Classification = {
target_type: string;
@@ -30,13 +39,140 @@ type Props = {
catalogueUrl: string;
criteria: string[];
classifications?: Classification[];
+ radiusAvailable?: boolean;
+ areaLabel?: string;
};
+export type BusinessGeographicCoverage = {
+ origin_id: string;
+ origin_title: string;
+ radius_km: number;
+ origin_recorded_at: string | null;
+ origin_source_reference?: string | null;
+ origin_source_date?: string | null;
+ with_public_point: number;
+ without_public_point: number;
+ source: string;
+ method: string;
+};
+
+export function GeographicCoverage({
+ coverage,
+}: {
+ coverage: BusinessGeographicCoverage;
+}) {
+ return (
+
+
+ Raio de {coverage.radius_km} km a partir de{' '}
+ {coverage.origin_title}.
+
+
+ Fonte: {coverage.source}. {coverage.method}
+
+
+ Cobertura entre as fichas públicas que cumprem os restantes
+ filtros, antes de aplicar o raio: {coverage.with_public_point}{' '}
+ com ponto utilizável; {coverage.without_public_point} sem ponto
+ público exacto utilizável, excluídas da pesquisa por distância.
+ Esta contagem pode incluir a ficha de referência.
+
+
+ Localização da referência registada em:{' '}
+ {publicationDate(coverage.origin_recorded_at) ??
+ 'data não indicada'}
+ . A data de registo não confirma a actualidade dos dados de
+ origem. Cobertura incompleta não demonstra ausência de negócios.
+
+
+ Fonte de origem da localização:{' '}
+ {coverage.origin_source_reference ||
+ 'referência não divulgada ou não indicada'}
+ . Data da fonte:{' '}
+ {publicationDate(coverage.origin_source_date) ?? 'desconhecida'}
+ .
+
+
+ );
+}
+
+export function BusinessDistance({
+ record,
+}: {
+ record: Pick<
+ Match,
+ | 'distance_km'
+ | 'location_recorded_at'
+ | 'location_source_reference'
+ | 'location_source_date'
+ >;
+}) {
+ if (
+ typeof record.distance_km !== 'number' ||
+ !Number.isFinite(record.distance_km) ||
+ record.distance_km < 0
+ )
+ return null;
+ return (
+
+
+ Distância aproximada em linha recta:{' '}
+ {record.distance_km.toLocaleString('pt-MZ')} km. Localização
+ registada em:{' '}
+ {publicationDate(record.location_recorded_at) ??
+ 'data não indicada'}
+ .
+
+
+
+ );
+}
+
+export function BusinessLocationSource({
+ record,
+ showRecorded = false,
+}: {
+ record: Pick<
+ Match,
+ | 'location_recorded_at'
+ | 'location_source_reference'
+ | 'location_source_date'
+ >;
+ showRecorded?: boolean;
+}) {
+ if (
+ !record.location_recorded_at &&
+ !record.location_source_reference &&
+ !record.location_source_date
+ )
+ return null;
+ return (
+
+ Fonte de origem da localização:{' '}
+ {record.location_source_reference ||
+ 'referência não divulgada ou não indicada'}
+ . Data da fonte:{' '}
+ {publicationDate(record.location_source_date) ?? 'desconhecida'}.
+ {showRecorded && (
+ <>
+ {' '}
+ Registada em:{' '}
+ {publicationDate(record.location_recorded_at) ??
+ 'data não indicada'}
+ . A data de registo não confirma a actualidade da origem.
+ >
+ )}
+
+ );
+}
+
export default function SimilarBusinesses({
currentId,
catalogueUrl,
criteria,
classifications = [],
+ radiusAvailable = false,
+ areaLabel,
}: Props) {
const [attempt, setAttempt] = useState(0);
const [selection, setSelection] = useState({
@@ -49,7 +185,26 @@ export default function SimilarBusinesses({
(row) => classificationKey(row) === selection.value,
)
: undefined;
+ const [radiusSelection, setRadiusSelection] = useState({
+ recordId: currentId,
+ value: '',
+ });
+ const radius =
+ radiusAvailable && radiusSelection.recordId === currentId
+ ? radiusSelection.value
+ : '';
const query = new URL(catalogueUrl, 'https://portal.invalid');
+ if (radius) {
+ for (const field of [
+ 'province_id',
+ 'district_id',
+ 'admin_post_id',
+ 'locality_id',
+ ])
+ query.searchParams.delete(field);
+ query.searchParams.set('near_business', currentId);
+ query.searchParams.set('radius_km', radius);
+ }
if (selected) {
query.searchParams.set('association_type', selected.target_type);
query.searchParams.set('association_target', selected.target_id);
@@ -62,6 +217,7 @@ export default function SimilarBusinesses({
key: string;
rows: Match[];
error: boolean;
+ coverage: BusinessGeographicCoverage | null;
} | null>(null);
useEffect(() => {
const controller = new AbortController();
@@ -69,14 +225,31 @@ export default function SimilarBusinesses({
.searchParams;
params.set('per_page', '7');
params.set('page', '1');
- void portalRequest<{ data: Match[] }>(
- `/api/v1/business-opportunities?${params}`,
- { signal: controller.signal },
- )
+ void portalRequest<{
+ data: Match[];
+ geographicCoverage?: BusinessGeographicCoverage | null;
+ }>(`/api/v1/business-opportunities?${params}`, {
+ signal: controller.signal,
+ })
.then((response) => {
if (controller.signal.aborted) return;
if (!Array.isArray(response.data))
throw new Error('Invalid catalogue response');
+ const coverage = response.geographicCoverage ?? null;
+ if (
+ radius &&
+ (!coverage ||
+ coverage.origin_id !== currentId ||
+ coverage.radius_km !== Number(radius) ||
+ !Number.isInteger(coverage.with_public_point) ||
+ coverage.with_public_point < 0 ||
+ !Number.isInteger(coverage.without_public_point) ||
+ coverage.without_public_point < 0 ||
+ typeof coverage.origin_title !== 'string' ||
+ typeof coverage.source !== 'string' ||
+ typeof coverage.method !== 'string')
+ )
+ throw new Error('Invalid radius coverage');
const seen = new Set([currentId]);
if (
response.data.some(
@@ -87,7 +260,11 @@ export default function SimilarBusinesses({
typeof row.slug !== 'string' ||
!row.slug.trim() ||
typeof row.title !== 'string' ||
- !row.title.trim(),
+ !row.title.trim() ||
+ (radius &&
+ (typeof row.distance_km !== 'number' ||
+ !Number.isFinite(row.distance_km) ||
+ row.distance_km < 0)),
)
) {
throw new Error('Invalid catalogue record');
@@ -106,14 +283,14 @@ export default function SimilarBusinesses({
return true;
})
.slice(0, 6);
- setResult({ key, rows, error: false });
+ setResult({ key, rows, error: false, coverage });
})
.catch(() => {
if (!controller.signal.aborted)
- setResult({ key, rows: [], error: true });
+ setResult({ key, rows: [], error: true, coverage: null });
});
return () => controller.abort();
- }, [currentId, effectiveCatalogueUrl, key]);
+ }, [currentId, effectiveCatalogueUrl, key, radius]);
const current = result?.key === key ? result : null;
return (
Explorar negócios semelhantes
Critérios:{' '}
- {[...criteria, ...(selected ? [selected.label] : [])].join(
- ' · ',
- )}
+ {[
+ ...criteria,
+ ...(!radius && areaLabel ? [areaLabel] : []),
+ ...(radius ? [`Raio de ${radius} km`] : []),
+ ...(selected ? [selected.label] : []),
+ ].join(' · ')}
. A consulta compara os dados publicados; não avalia
- rentabilidade nem proximidade geográfica.
+ rentabilidade.{' '}
+ {radius
+ ? 'O raio substitui o filtro por área e pode atravessar limites administrativos.'
+ : 'Sem raio seleccionado, não é calculada proximidade geográfica.'}
{!current ? (
A consultar o catálogo…
@@ -171,6 +354,7 @@ export default function SimilarBusinesses({
'Data de publicação não indicada.'
)}
+
))}
@@ -181,6 +365,46 @@ export default function SimilarBusinesses({
mercado.
)}
+ {current && !current.error && current.coverage && (
+
+ )}
+ {radiusAvailable ? (
+
+ Âmbito geográfico
+
+ Pesquisar por área ou distância
+
+ setRadiusSelection({
+ recordId: currentId,
+ value: event.target.value,
+ })
+ }
+ >
+
+ {areaLabel
+ ? `Área: ${areaLabel}`
+ : 'Sem limite por distância'}
+
+ {[1, 5, 10, 25, 50, 100, 250, 500, 1000, 2000].map(
+ (value) => (
+
+ Até {value} km desta ficha
+
+ ),
+ )}
+
+
+
+ ) : (
+
+ A pesquisa por raio requer um ponto primário público exacto
+ na ficha de referência. Pode continuar por área, sector e
+ classificação.
+
+ )}
{classifications.length > 0 && (
Comparar também por uma classificação divulgada
diff --git a/resources/js/components/technical-incident-handling.tsx b/resources/js/components/technical-incident-handling.tsx
new file mode 100644
index 00000000..580baa45
--- /dev/null
+++ b/resources/js/components/technical-incident-handling.tsx
@@ -0,0 +1,122 @@
+import {
+ useTechnicalIncidentHandling,
+ type HandlingProps,
+ type Command,
+} from '@/lib/technical-incident-handling';
+import { button, control } from '@/pages/management/shared';
+import { handlingLabels, commandLabels } from '@/lib/technical-incident-labels';
+export default function TechnicalIncidentHandling(props: HandlingProps) {
+ const edit = useTechnicalIncidentHandling(props),
+ state = props.incident.handling;
+ const actions: Command[] =
+ state.status === 'resolved'
+ ? ['note', 'reopen']
+ : [
+ 'claim',
+ 'note',
+ 'resolve',
+ ...(state.status === 'in_progress'
+ ? ['release' as const]
+ : []),
+ ];
+ return (
+
+ Tratar incidente técnico
+
+ O tratamento é partilhado pela equipa autorizada neste âmbito.
+ Assumir um tratamento em curso substitui o responsável e
+ conserva o histórico.
+
+
+ Resolver este incidente não submete, publica ou aprova a
+ oportunidade.
+
+ {edit.notice && {edit.notice}
}
+ {edit.error && {edit.error}
}
+ {edit.stale && (
+
+
+ O incidente mudou. Compare antes de confirmar o estado
+ actual.
+
+
+ Analisado: {handlingLabels[edit.base.status]} ·
+ responsável {edit.base.assignee_name || 'por assumir'} ·
+ versão {edit.base.version}
+
+
+ Actual: {handlingLabels[state.status]} · responsável{' '}
+ {state.assignee_name || 'por assumir'} · versão{' '}
+ {state.version}
+
+
+ Confirmar leitura do estado actual
+
+
+ )}
+
+ Nota interna do tratamento
+ edit.change(event.target.value)}
+ />
+
+
+ A nota é visível à equipa de suporte autorizada e fica no
+ histórico. O autor da tentativa acompanha apenas o estado
+ técnico.
+
+
+ {actions
+ .filter(
+ (action) =>
+ action !== 'claim' ||
+ state.assignee_user_id !== props.actorId,
+ )
+ .map((action) => (
+ void edit.send(action)}
+ >
+ {commandLabels[action]}
+
+ ))}
+ {edit.canRetry && (
+
+ void edit.send(edit.pendingAction ?? 'note', true)
+ }
+ >
+ Repetir o registo original
+
+ )}
+
+ Actualizar incidente
+
+
+
+ );
+}
diff --git a/resources/js/components/technical-incident-notice.tsx b/resources/js/components/technical-incident-notice.tsx
new file mode 100644
index 00000000..28e25988
--- /dev/null
+++ b/resources/js/components/technical-incident-notice.tsx
@@ -0,0 +1,108 @@
+import { useEffect, useRef, useState } from 'react';
+import { router } from '@inertiajs/react';
+import { portalRequest } from '@/lib/portal-api';
+import { button } from '@/pages/management/shared';
+
+export default function TechnicalIncidentNotice({
+ actorId,
+ reference,
+ unread,
+}: {
+ actorId: number;
+ reference: string;
+ unread: boolean;
+}) {
+ const [read, setRead] = useState(!unread),
+ [busy, setBusy] = useState(false),
+ [error, setError] = useState('');
+ const scope = useRef({ actorId, reference }),
+ alive = useRef(true),
+ active = useRef(false),
+ confirmed = useRef(!unread);
+ const current = useRef({ actorId, reference });
+ current.current = { actorId, reference };
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ useEffect(() => {
+ if (!unread) {
+ confirmed.current = true;
+ setRead(true);
+ setError('');
+ }
+ }, [unread]);
+ function applicable() {
+ return (
+ alive.current &&
+ current.current.actorId === scope.current.actorId &&
+ current.current.reference === scope.current.reference
+ );
+ }
+ async function mark() {
+ if (!applicable() || active.current || confirmed.current) return;
+ active.current = true;
+ setBusy(true);
+ setError('');
+ try {
+ const value = await portalRequest(
+ '/suporte-tecnico/incidentes/' +
+ scope.current.reference +
+ '/consultado',
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: '{}',
+ },
+ );
+ if (!applicable() || confirmed.current) return;
+ if (
+ !value ||
+ typeof value !== 'object' ||
+ !('actor_id' in value) ||
+ value.actor_id !== scope.current.actorId ||
+ !('reference' in value) ||
+ value.reference !== scope.current.reference ||
+ !('read' in value) ||
+ value.read !== true
+ )
+ throw new Error('Unconfirmed receipt');
+ confirmed.current = true;
+ setRead(true);
+ router.reload({
+ only: ['incidents', 'profileAccess', 'notice'],
+ });
+ } catch {
+ if (applicable() && !confirmed.current)
+ setError(
+ 'Não foi possível confirmar a consulta. Pode repetir esta acção; o tratamento e as notas mantêm-se.',
+ );
+ } finally {
+ if (applicable()) {
+ active.current = false;
+ setBusy(false);
+ }
+ }
+ }
+ return (
+
+ {read ? (
+
Aviso consultado por si.
+ ) : (
+
void mark()}
+ >
+ {error
+ ? 'Repetir confirmação de consulta'
+ : 'Marcar aviso como consultado'}
+
+ )}
+ {error &&
{error}
}
+
+ );
+}
diff --git a/resources/js/lib/business-locations.ts b/resources/js/lib/business-locations.ts
index 712e4124..4a297d5d 100644
--- a/resources/js/lib/business-locations.ts
+++ b/resources/js/lib/business-locations.ts
@@ -5,6 +5,58 @@ export type BusinessLocationPath = {
locality_id: string;
};
+export function businessPointTerritoryKey(path: BusinessLocationPath): string {
+ return [
+ path.province_id,
+ path.district_id,
+ path.admin_post_id,
+ path.locality_id,
+ ].join('|');
+}
+
+export function businessPointTerritoryLabel(
+ payload: Record,
+ paths: string[][] = [],
+): string {
+ const index =
+ payload.geography_scope === 'specific'
+ ? 0
+ : decodeBusinessLocations(payload.locations_json).findIndex(
+ (path) =>
+ businessPointTerritoryKey(path) ===
+ payload.location_point_territory,
+ );
+ return paths[index]?.join(' / ') || 'Localização por reconciliar';
+}
+
+export function businessPointApplicable(
+ payload: Record,
+): boolean {
+ return (
+ payload.location_point_enabled === 'yes' &&
+ ['specific', 'multiple'].includes(payload.geography_scope ?? '') &&
+ payload.disclosure_precision === 'exact' &&
+ payload.location_unknown === 'no'
+ );
+}
+
+export function businessPointRequiredFields(
+ payload: Record,
+): Set {
+ if (!businessPointApplicable(payload)) return new Set();
+ return new Set([
+ 'location_latitude',
+ 'location_longitude',
+ 'location_point_source_mode',
+ ...(payload.geography_scope === 'multiple'
+ ? ['location_point_territory']
+ : []),
+ ...(payload.location_point_source_mode === 'custom'
+ ? ['location_point_source_reference']
+ : []),
+ ]);
+}
+
export const emptyBusinessLocation = (): BusinessLocationPath => ({
province_id: '',
district_id: '',
diff --git a/resources/js/lib/company-comparison.ts b/resources/js/lib/company-comparison.ts
new file mode 100644
index 00000000..009dae47
--- /dev/null
+++ b/resources/js/lib/company-comparison.ts
@@ -0,0 +1,17 @@
+export type CompanyAnswers = Record;
+export function companyComparisonUrl(
+ base: string,
+ answers: CompanyAnswers,
+ field = 'answers',
+): string {
+ return (
+ base +
+ '?' +
+ new URLSearchParams(
+ Object.entries(answers).map(([key, value]) => [
+ `${field}[${key}]`,
+ value,
+ ]),
+ )
+ );
+}
diff --git a/resources/js/lib/company-preparation.ts b/resources/js/lib/company-preparation.ts
new file mode 100644
index 00000000..4ced3094
--- /dev/null
+++ b/resources/js/lib/company-preparation.ts
@@ -0,0 +1,72 @@
+export type Party = {
+ id: string;
+ name: string | null;
+ kind: 'person' | 'entity';
+ source: string | null;
+ roles: string[];
+ represented_id: string | null;
+ cash: string | null;
+ in_kind: string | null;
+ paid: string | null;
+ share_count: string | null;
+ work: string | null;
+ commitment: string | null;
+ source_snapshot?: {
+ origin: string;
+ reference: string;
+ version: string | number | null;
+ };
+};
+export type CompanyFacts = {
+ form: string | null;
+ proposed_name: string | null;
+ seat: string | null;
+ activities: string | null;
+ regulated: string;
+ currency: string | null;
+ capital: string | null;
+ nominal_value: string | null;
+ management: string | null;
+ binding: string | null;
+ notes: string | null;
+ parties: Party[];
+};
+
+/** Read actual form values, including autofill, without serializing private provenance. */
+export function preparationValues(
+ form: HTMLFormElement,
+ facts: CompanyFacts,
+): CompanyFacts {
+ const data = new FormData(form);
+ const value = (key: string, fallback: string | null) => {
+ const v = data.get(key);
+ return typeof v === 'string' ? v.trim() || null : fallback;
+ };
+ return {
+ form: value('form', facts.form),
+ proposed_name: value('proposed_name', facts.proposed_name),
+ seat: value('seat', facts.seat),
+ activities: value('activities', facts.activities),
+ regulated: value('regulated', facts.regulated) ?? 'unknown',
+ currency: value('currency', facts.currency),
+ capital: value('capital', facts.capital),
+ nominal_value: value('nominal_value', facts.nominal_value),
+ management: value('management', facts.management),
+ binding: value('binding', facts.binding),
+ notes: value('notes', facts.notes),
+ parties: facts.parties.map((p) => ({
+ id: p.id,
+ name: value(`${p.id}.name`, p.name),
+ kind: p.kind,
+ source: p.source,
+ roles: p.roles,
+ represented_id: p.represented_id,
+ cash: value(`${p.id}.cash`, p.cash),
+ in_kind: value(`${p.id}.in_kind`, p.in_kind),
+ paid: value(`${p.id}.paid`, p.paid),
+ share_count: value(`${p.id}.share_count`, p.share_count),
+ work: value(`${p.id}.work`, p.work),
+ commitment: value(`${p.id}.commitment`, p.commitment),
+ })),
+ };
+}
diff --git a/resources/js/lib/crm-record-edit.ts b/resources/js/lib/crm-record-edit.ts
new file mode 100644
index 00000000..68ce81c2
--- /dev/null
+++ b/resources/js/lib/crm-record-edit.ts
@@ -0,0 +1,213 @@
+import { router, useForm } from '@inertiajs/react';
+import { useRef, useState } from 'react';
+
+type Values = Record;
+type Kind = 'investor' | 'contact' | 'lead' | 'task';
+function object(value: unknown): value is Record {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+function savedRecord(
+ props: Record,
+ kind: Kind,
+ id: string,
+): Record | null {
+ let candidate: unknown = kind === 'investor' ? props.investor : props.lead;
+ if (kind === 'contact')
+ candidate = Array.isArray(props.contacts)
+ ? props.contacts.find((value) => object(value) && value.id === id)
+ : null;
+ if (kind === 'task')
+ candidate =
+ object(props.lead) && Array.isArray(props.lead.tasks)
+ ? props.lead.tasks.find(
+ (value) => object(value) && value.id === id,
+ )
+ : null;
+ return object(candidate) && candidate.id === id ? candidate : null;
+}
+
+/** Keeps deliberate edits, including a deliberate return to the original value. */
+export function useCrmRecordEdit({
+ id,
+ kind,
+ version,
+ values,
+ blankAfterSave = [],
+}: {
+ id: string;
+ kind: Kind;
+ version: number;
+ values: Values;
+ blankAfterSave?: string[];
+}) {
+ const form = useForm({ version, values });
+ const live = useRef(form.data);
+ live.current = form.data;
+ const identity = useRef(id);
+ identity.current = id;
+ const base = useRef({ id, version, values: { ...values } });
+ const edited = useRef(new Set());
+ const generation = useRef>({});
+ const [choices, setChoices] = useState>(
+ {},
+ );
+ const [refreshing, setRefreshing] = useState(false);
+ const keys = Object.keys(values);
+ const stale = version !== form.data.version;
+ const changed = keys.filter(
+ (key) => values[key] !== base.current.values[key],
+ );
+ const conflicts = changed.filter(
+ (key) =>
+ edited.current.has(key) && form.data.values[key] !== values[key],
+ );
+ const unresolved = conflicts.filter(
+ (key) => choices[`${version}:${key}`] !== 'mine',
+ );
+ const invalid =
+ base.current.id !== id || !Number.isInteger(version) || version < 1;
+
+ function change(key: string, value: string) {
+ if (!keys.includes(key)) return;
+ edited.current.add(key);
+ generation.current[key] = (generation.current[key] ?? 0) + 1;
+ setChoices((previous) => {
+ const next = { ...previous };
+ delete next[`${version}:${key}`];
+ return next;
+ });
+ live.current = {
+ ...live.current,
+ values: { ...live.current.values, [key]: value },
+ };
+ form.setData((previous) => ({
+ ...previous,
+ values: { ...previous.values, [key]: value },
+ }));
+ }
+ function choose(key: string, choice: 'mine' | 'current') {
+ if (choice === 'current') change(key, values[key]);
+ setChoices((previous) => ({
+ ...previous,
+ [`${version}:${key}`]: choice,
+ }));
+ }
+ function adopt() {
+ if (!stale || invalid || refreshing || unresolved.length) return;
+ const next = Object.fromEntries(
+ keys.map((key) => [
+ key,
+ edited.current.has(key)
+ ? live.current.values[key]
+ : values[key],
+ ]),
+ );
+ base.current = { id, version, values: { ...values } };
+ live.current = { version, values: next };
+ form.setData(live.current);
+ form.clearErrors('version');
+ setChoices({});
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only:
+ kind === 'lead' || kind === 'task'
+ ? ['lead', 'owners', 'taskCreation', 'nextAction']
+ : ['investor', 'contacts'],
+ onFinish: () => setRefreshing(false),
+ });
+ }
+ const blocked = invalid || stale || refreshing || !!form.errors.version;
+ function submit(url: string) {
+ if (blocked || form.processing) return;
+ const submitted = {
+ ...live.current.values,
+ version: live.current.version,
+ };
+ const sentGeneration = { ...generation.current };
+ form.transform(() => submitted);
+ form.patch(url, {
+ preserveScroll: true,
+ onSuccess: (page) => {
+ if (identity.current !== id) return;
+ const record = savedRecord(page.props, kind, id);
+ const actualVersion = record?.version_no;
+ if (
+ !record ||
+ typeof actualVersion !== 'number' ||
+ !Number.isInteger(actualVersion) ||
+ actualVersion < 1
+ )
+ return;
+ const next: Values = {};
+ for (const key of keys) {
+ const value = record[key];
+ if (
+ blankAfterSave.includes(key) ||
+ value === null ||
+ value === undefined
+ )
+ next[key] = '';
+ else if (
+ typeof value === 'string' ||
+ typeof value === 'number'
+ )
+ next[key] = String(value);
+ else return;
+ }
+ base.current = {
+ id,
+ version: actualVersion,
+ values: { ...next },
+ };
+ edited.current.clear();
+ const merged = { ...next };
+ for (const key of keys) {
+ if (
+ (generation.current[key] ?? 0) !==
+ (sentGeneration[key] ?? 0)
+ ) {
+ merged[key] = live.current.values[key];
+ edited.current.add(key);
+ }
+ }
+ setChoices({});
+ const saved = { version: actualVersion, values: next };
+ form.setDefaults(saved);
+ live.current = { version: actualVersion, values: merged };
+ form.setData(live.current);
+ form.clearErrors();
+ },
+ });
+ }
+ function error(key: string): string | undefined {
+ const value = Object.entries(form.errors).find(
+ ([name]) => name === key,
+ )?.[1];
+ return typeof value === 'string' ? value : undefined;
+ }
+ return {
+ form,
+ values: form.data.values,
+ current: values,
+ version,
+ baseVersion: form.data.version,
+ changed,
+ conflicts,
+ unresolved,
+ stale,
+ refreshing,
+ invalid,
+ blocked,
+ change,
+ choose,
+ adopt,
+ refresh,
+ submit,
+ error,
+ };
+}
+
+export type CrmRecordEditor = ReturnType;
diff --git a/resources/js/lib/crm-task-creation.ts b/resources/js/lib/crm-task-creation.ts
new file mode 100644
index 00000000..e56b6cb4
--- /dev/null
+++ b/resources/js/lib/crm-task-creation.ts
@@ -0,0 +1,371 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+import type { Lead } from '@/pages/crm/types';
+import {
+ useCrmTaskPreparation,
+ taskDeadlineLocal,
+ taskDeadlineUtc,
+} from './crm-task-preparation';
+import type {
+ TaskPreparationView,
+ TaskPreparationSnapshot,
+} from './crm-task-preparation';
+
+export type TaskCreationContext = {
+ lead_id: string;
+ actor_id: number;
+ commands: { key: string; task_id: string; version: number }[];
+ preparation?: TaskPreparationView;
+};
+type Values = { title: string; due_at: string; assignee_user_id: string };
+type Attempt = {
+ values: Values & { client_key: string };
+ generation: Record;
+};
+const object = (value: unknown): value is Record =>
+ !!value && typeof value === 'object' && !Array.isArray(value);
+const positive = (value: unknown): value is number =>
+ typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
+
+export function useCrmTaskCreation(lead: Lead, context: TaskCreationContext) {
+ const form = useForm({
+ title: '',
+ due_at: '',
+ assignee_user_id: String(lead.owner_user_id ?? ''),
+ });
+ const live = useRef(form.data);
+ live.current = form.data;
+ const blank = context.preparation?.snapshot;
+ const sameBlank =
+ blank?.pending === null &&
+ blank.values?.title === '' &&
+ blank.values?.due_at === '' &&
+ blank.values?.assignee_user_id === String(lead.owner_user_id ?? '') &&
+ Object.values(blank.generation ?? {}).length === 3 &&
+ Object.values(blank.generation ?? {}).every(
+ (value) => Number.isSafeInteger(value) && value >= 0,
+ );
+ const generation = useRef>(
+ sameBlank ? { ...blank.generation } : {},
+ );
+ const pending = useRef(null);
+ const submitted = useRef(null);
+ const recoveredDeadline = useRef<{ local: string; utc: string } | null>(
+ null,
+ );
+ const alive = useRef(true);
+ const [waiting, setWaiting] = useState(false);
+ const [blocked, setBlocked] = useState(false);
+ const [refreshing, setRefreshing] = useState(false);
+ const [notice, setNotice] = useState('');
+ const valid =
+ context.lead_id === lead.id &&
+ positive(context.actor_id) &&
+ Array.isArray(context.commands);
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ useEffect(() => {
+ if (generation.current.assignee_user_id) return;
+ const assignee_user_id = String(lead.owner_user_id ?? '');
+ live.current = { ...live.current, assignee_user_id };
+ form.setData(live.current);
+ }, [lead.owner_user_id]);
+
+ function change(key: keyof Values, value: string) {
+ if (key === 'due_at') recoveredDeadline.current = null;
+ generation.current[key] = (generation.current[key] ?? 0) + 1;
+ live.current = { ...live.current, [key]: value };
+ form.setData(live.current);
+ }
+ function scoped(props: unknown): props is Record & {
+ taskCreation: TaskCreationContext;
+ } {
+ return (
+ object(props) &&
+ object(props.lead) &&
+ props.lead.id === lead.id &&
+ object(props.taskCreation) &&
+ props.taskCreation.lead_id === lead.id &&
+ props.taskCreation.actor_id === context.actor_id &&
+ Array.isArray(props.taskCreation.commands)
+ );
+ }
+ function acknowledge(props: unknown) {
+ const attempt = pending.current;
+ if (!alive.current || !attempt || !scoped(props)) return false;
+ const receipt = props.taskCreation.commands.find(
+ (item: unknown) =>
+ object(item) && item.key === attempt.values.client_key,
+ );
+ if (
+ !receipt ||
+ typeof receipt.task_id !== 'string' ||
+ !positive(receipt.version)
+ )
+ return false;
+ const task =
+ object(props.lead) && Array.isArray(props.lead.tasks)
+ ? props.lead.tasks.find(
+ (item: unknown) =>
+ object(item) && item.id === receipt.task_id,
+ )
+ : null;
+ if (
+ task &&
+ (!positive(task.version_no) ||
+ task.version_no < receipt.version ||
+ (task.version_no === receipt.version &&
+ (task.title !== attempt.values.title.trim() ||
+ task.assignee_user_id !==
+ Number(attempt.values.assignee_user_id) ||
+ new Date(task.due_at).getTime() !==
+ new Date(attempt.values.due_at).getTime())))
+ )
+ return false;
+ const next = { ...live.current };
+ for (const key of ['title', 'due_at'] as const) {
+ if (
+ (generation.current[key] ?? 0) ===
+ (attempt.generation[key] ?? 0)
+ )
+ next[key] = '';
+ }
+ live.current = next;
+ form.setData(next);
+ form.clearErrors();
+ pending.current = null;
+ setWaiting(false);
+ setBlocked(false);
+ setNotice(
+ task
+ ? 'Tarefa registada. As alterações posteriores ao envio foram conservadas.'
+ : 'A criação já foi registada. A tarefa já não está disponível neste lead; consulte o histórico antes de criar outra.',
+ );
+ return true;
+ }
+ function capture(): TaskPreparationSnapshot {
+ return {
+ values: {
+ ...live.current,
+ due_at:
+ recoveredDeadline.current?.local === live.current.due_at
+ ? recoveredDeadline.current.utc
+ : taskDeadlineUtc(live.current.due_at),
+ },
+ generation: {
+ title: generation.current.title ?? 0,
+ due_at: generation.current.due_at ?? 0,
+ assignee_user_id: generation.current.assignee_user_id ?? 0,
+ },
+ pending: pending.current
+ ? {
+ values: { ...pending.current.values },
+ generation: {
+ title: pending.current.generation.title ?? 0,
+ due_at: pending.current.generation.due_at ?? 0,
+ assignee_user_id:
+ pending.current.generation.assignee_user_id ?? 0,
+ },
+ }
+ : null,
+ };
+ }
+ const preparation = useCrmTaskPreparation({
+ leadId: lead.id,
+ actorId: context.actor_id,
+ view: context.preparation,
+ getSnapshot: capture,
+ onRecover: (snapshot) => {
+ if (
+ pending.current &&
+ submitted.current === pending.current.values.client_key &&
+ pending.current.values.client_key !==
+ snapshot.pending?.values.client_key
+ )
+ return false;
+ generation.current = { ...snapshot.generation };
+ generation.current.assignee_user_id = Math.max(
+ 1,
+ snapshot.generation.assignee_user_id,
+ );
+ live.current = {
+ ...snapshot.values,
+ due_at: taskDeadlineLocal(snapshot.values.due_at),
+ };
+ recoveredDeadline.current = {
+ local: live.current.due_at,
+ utc: snapshot.values.due_at,
+ };
+ form.setData(live.current);
+ pending.current = snapshot.pending;
+ submitted.current = snapshot.pending?.values.client_key ?? null;
+ setWaiting(!!snapshot.pending);
+ setBlocked(false);
+ if (snapshot.pending) {
+ if (!acknowledge({ lead, taskCreation: context }))
+ setNotice(
+ 'Foi recuperado um envio sem confirmação. Recupere a mesma criação antes de iniciar outra.',
+ );
+ }
+ return true;
+ },
+ });
+ const canReplay =
+ !!pending.current &&
+ submitted.current === pending.current.values.client_key;
+ function submit() {
+ if (
+ !valid ||
+ blocked ||
+ refreshing ||
+ form.processing ||
+ (preparation.blocked && !canReplay)
+ )
+ return;
+ if (!pending.current) {
+ let client_key: string;
+ try {
+ client_key = createOperationKey();
+ } catch {
+ setNotice(
+ 'Não foi possível preparar o envio. Reabra o portal no endereço HTTPS configurado.',
+ );
+ return;
+ }
+ pending.current = {
+ values: {
+ ...live.current,
+ due_at: capture().values.due_at,
+ client_key,
+ },
+ generation: { ...generation.current },
+ };
+ }
+ const attempt = pending.current;
+ setWaiting(true);
+ if (canReplay || !preparation.enabled) send(attempt);
+ else {
+ setNotice('A guardar a preparação antes de criar a tarefa…');
+ void preparation.ensure().then((saved) => {
+ if (!alive.current || pending.current !== attempt) return;
+ if (saved) send(attempt);
+ else
+ setNotice(
+ 'O envio ficou por confirmar. Volte a guardar a preparação antes de continuar.',
+ );
+ });
+ }
+ }
+ function send(attempt: Attempt) {
+ submitted.current = attempt.values.client_key;
+ setNotice('A aguardar confirmação da criação.');
+ form.transform(() => attempt.values);
+ form.post(`/management/crm/leads/${lead.id}/tasks`, {
+ preserveScroll: true,
+ onSuccess: (page) => {
+ if (!alive.current || pending.current !== attempt) return;
+ if (!acknowledge(page.props))
+ setNotice(
+ 'A resposta não permitiu confirmar a criação. Actualize as tarefas ou recupere o mesmo envio.',
+ );
+ },
+ onError: () => {
+ if (!alive.current || pending.current !== attempt) return;
+ pending.current = null;
+ setWaiting(false);
+ setNotice(
+ 'Reveja os campos assinalados. As suas alterações foram conservadas.',
+ );
+ },
+ onNetworkError: () => {
+ if (alive.current && pending.current === attempt)
+ setNotice(
+ 'Sem confirmação do envio. Recupere a mesma criação para evitar duplicar a tarefa.',
+ );
+ },
+ onHttpException: (response) => {
+ if (!alive.current || pending.current !== attempt) return;
+ if ([401, 403, 404, 409, 419].includes(response.status))
+ setBlocked(true);
+ setNotice(
+ 'Não foi possível confirmar a criação. Actualize as tarefas e o acesso antes de continuar. As alterações foram conservadas.',
+ );
+ },
+ onCancel: () => {
+ if (alive.current && pending.current === attempt)
+ setNotice(
+ 'Envio interrompido sem confirmação. Recupere a mesma criação.',
+ );
+ },
+ });
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: ['lead', 'owners', 'taskCreation', 'nextAction'],
+ onSuccess: (page) => {
+ if (!alive.current || !scoped(page.props)) return;
+ setBlocked(false);
+ if (pending.current && !acknowledge(page.props))
+ setNotice(
+ 'A criação ainda não foi confirmada. Recupere o mesmo envio; as edições posteriores ficam para a próxima tarefa.',
+ );
+ },
+ onFinish: () => {
+ if (alive.current) setRefreshing(false);
+ },
+ });
+ }
+ const guard = useRef(false);
+ guard.current =
+ !preparation.durable &&
+ (waiting ||
+ !!form.data.title ||
+ !!form.data.due_at ||
+ (!!generation.current.assignee_user_id &&
+ form.data.assignee_user_id !==
+ String(lead.owner_user_id ?? '')));
+ useEffect(() => {
+ const remove = router.on('before', (event) => {
+ const visit = event.detail.visit;
+ if (
+ guard.current &&
+ visit.method === 'get' &&
+ !visit.preserveState &&
+ !window.confirm(
+ 'Existem alterações ou um envio por confirmar. Sair desta página?',
+ )
+ )
+ event.preventDefault();
+ });
+ const unload = (event: BeforeUnloadEvent) => {
+ if (guard.current) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ window.addEventListener('beforeunload', unload);
+ return () => {
+ remove();
+ window.removeEventListener('beforeunload', unload);
+ };
+ }, []);
+ return {
+ form,
+ change,
+ submit,
+ refresh,
+ waiting,
+ blocked: blocked || !valid || (preparation.blocked && !canReplay),
+ refreshing,
+ notice,
+ sent: pending.current?.values,
+ preparation,
+ };
+}
diff --git a/resources/js/lib/crm-task-preparation.ts b/resources/js/lib/crm-task-preparation.ts
new file mode 100644
index 00000000..e2bb51d5
--- /dev/null
+++ b/resources/js/lib/crm-task-preparation.ts
@@ -0,0 +1,384 @@
+import { useEffect, useRef, useState } from 'react';
+import { profileJson, ProfileValidationError } from './profile-json';
+import { createOperationKey } from './operation-key';
+
+export type TaskValues = {
+ title: string;
+ due_at: string;
+ assignee_user_id: string;
+};
+export type TaskGeneration = Record;
+export type TaskAttempt = {
+ values: TaskValues & { client_key: string };
+ generation: TaskGeneration;
+};
+export type TaskPreparationSnapshot = {
+ values: TaskValues;
+ generation: TaskGeneration;
+ pending: TaskAttempt | null;
+};
+export type TaskPreparationView = {
+ installed: boolean;
+ version: number;
+ snapshot: TaskPreparationSnapshot | null;
+ operation_key: string | null;
+ unavailable: boolean;
+ updated_at: string | null;
+};
+type Save = {
+ version: number;
+ operation_key: string;
+ snapshot: TaskPreparationSnapshot;
+};
+const fields = ['title', 'due_at', 'assignee_user_id'] as const;
+const object = (value: unknown): value is Record =>
+ !!value && typeof value === 'object' && !Array.isArray(value);
+const integer = (value: unknown): value is number =>
+ typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
+const values = (value: unknown): value is TaskValues =>
+ object(value) && fields.every((field) => typeof value[field] === 'string');
+const generation = (value: unknown): value is TaskGeneration =>
+ object(value) && fields.every((field) => integer(value[field]));
+function snapshot(value: unknown): value is TaskPreparationSnapshot {
+ return (
+ object(value) &&
+ values(value.values) &&
+ generation(value.generation) &&
+ (value.pending === null ||
+ (object(value.pending) &&
+ object(value.pending.values) &&
+ typeof value.pending.values.client_key === 'string' &&
+ values(value.pending.values) &&
+ generation(value.pending.generation)))
+ );
+}
+function read(value: unknown): TaskPreparationView | null {
+ return object(value) &&
+ typeof value.installed === 'boolean' &&
+ integer(value.version) &&
+ typeof value.unavailable === 'boolean' &&
+ (value.snapshot === null || snapshot(value.snapshot)) &&
+ (value.operation_key === null ||
+ typeof value.operation_key === 'string') &&
+ (value.updated_at === null || typeof value.updated_at === 'string')
+ ? (value as TaskPreparationView)
+ : null;
+}
+const signature = (value: TaskPreparationSnapshot) =>
+ JSON.stringify({
+ values: fields.map((field) => value.values[field]),
+ generation: fields.map((field) => value.generation[field]),
+ pending: value.pending
+ ? {
+ values: [
+ ...fields.map((field) => value.pending?.values[field]),
+ value.pending.values.client_key,
+ ],
+ generation: fields.map(
+ (field) => value.pending?.generation[field],
+ ),
+ }
+ : null,
+ });
+export function taskDeadlineUtc(value: string): string {
+ const date = new Date(value);
+ return value && !Number.isNaN(date.getTime()) ? date.toISOString() : value;
+}
+export function taskDeadlineLocal(value: string): string {
+ const date = new Date(value);
+ return value && !Number.isNaN(date.getTime())
+ ? new Date(date.getTime() - date.getTimezoneOffset() * 60000)
+ .toISOString()
+ .slice(0, 16)
+ : value;
+}
+
+export function useCrmTaskPreparation({
+ leadId,
+ actorId,
+ view,
+ getSnapshot,
+ onRecover,
+}: {
+ leadId: string;
+ actorId: number;
+ view: unknown;
+ getSnapshot: () => TaskPreparationSnapshot;
+ onRecover: (value: TaskPreparationSnapshot) => boolean;
+}) {
+ const incoming = read(view);
+ const latest = useRef({ getSnapshot, onRecover });
+ latest.current = { getSnapshot, onRecover };
+ const alive = useRef(true),
+ busy = useRef(false);
+ const base = useRef(incoming);
+ const initial = getSnapshot();
+ const different =
+ incoming?.snapshot &&
+ (incoming.snapshot.pending !== null ||
+ fields.some(
+ (field) =>
+ incoming.snapshot?.values[field] !== initial.values[field],
+ ));
+ const saved = useRef(
+ different && incoming.snapshot
+ ? signature(incoming.snapshot)
+ : signature(initial),
+ );
+ const saveAttempt = useRef(null);
+ const [comparison, setComparison] = useState(
+ different ? incoming : null,
+ );
+ const [choices, setChoices] = useState<
+ Partial<
+ Record<
+ keyof TaskValues,
+ { source: 'page' | 'saved'; generation: number }
+ >
+ >
+ >({});
+ const [state, setState] = useState<
+ 'ready' | 'saving' | 'error' | 'unavailable'
+ >(incoming?.unavailable || (!!view && !incoming) ? 'unavailable' : 'ready');
+ const [memoryOnly, setMemoryOnly] = useState(false);
+ const [message, setMessage] = useState(
+ incoming?.unavailable || (!!view && !incoming)
+ ? 'A preparação guardada não pôde ser lida. Actualize para recuperar o acesso ou continue só nesta página; os dados guardados ficam preservados.'
+ : '',
+ );
+ const [, setTick] = useState(0);
+ const current = getSnapshot(),
+ currentSignature = signature(current);
+ const enabled = !!incoming?.installed && !memoryOnly;
+
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ function response(value: unknown): TaskPreparationView | null {
+ return object(value) &&
+ value.lead_id === leadId &&
+ value.actor_id === actorId
+ ? read(value.preparation)
+ : null;
+ }
+ function confirmed(next: TaskPreparationView, attempt: Save) {
+ if (
+ next.version !== attempt.version + 1 ||
+ next.operation_key !== attempt.operation_key ||
+ !next.snapshot ||
+ signature(next.snapshot) !== signature(attempt.snapshot)
+ )
+ return false;
+ base.current = next;
+ saved.current = signature(attempt.snapshot);
+ saveAttempt.current = null;
+ setState('ready');
+ setMessage(
+ 'Preparação guardada no servidor. Pode retomá-la nesta conta.',
+ );
+ return true;
+ }
+ useEffect(() => {
+ if (!incoming || !incoming.installed || memoryOnly || busy.current)
+ return;
+ if (saveAttempt.current && confirmed(incoming, saveAttempt.current))
+ return;
+ if (incoming.version > (base.current?.version ?? 0)) {
+ setComparison(incoming);
+ setChoices({});
+ setMessage(
+ 'A preparação mudou. Compare antes de substituir os dados guardados.',
+ );
+ }
+ }, [view, state, memoryOnly]);
+
+ async function ensure(forSubmission = true): Promise {
+ if (!enabled) return true;
+ const now = latest.current.getSnapshot();
+ if (
+ forSubmission &&
+ now.pending &&
+ base.current?.snapshot?.pending?.values.client_key ===
+ now.pending.values.client_key
+ )
+ return true;
+ if (busy.current || comparison || state === 'unavailable') return false;
+ if (!saveAttempt.current && signature(now) === saved.current)
+ return true;
+ let attempt = saveAttempt.current;
+ if (!attempt) {
+ try {
+ attempt = {
+ version: base.current?.version ?? 0,
+ operation_key: createOperationKey(),
+ snapshot: now,
+ };
+ } catch {
+ setState('error');
+ setMessage(
+ 'Não foi possível preparar a gravação. Reabra o portal no endereço HTTPS configurado.',
+ );
+ return false;
+ }
+ }
+ saveAttempt.current = attempt;
+ busy.current = true;
+ setState('saving');
+ setMessage('A guardar a preparação…');
+ try {
+ const result: unknown = await profileJson(
+ `/management/crm/leads/${leadId}/task-preparation`,
+ attempt,
+ );
+ if (!alive.current) return false;
+ const next = response(result);
+ if (!next || !confirmed(next, attempt))
+ throw new Error('Unconfirmed preparation');
+ // A previous automatic save may have preceded the creation attempt.
+ const pending = latest.current.getSnapshot().pending;
+ if (
+ forSubmission &&
+ pending &&
+ next.snapshot?.pending?.values.client_key !==
+ pending.values.client_key
+ ) {
+ busy.current = false;
+ return await ensure(true);
+ }
+ return true;
+ } catch (error) {
+ if (alive.current) {
+ if (
+ error instanceof ProfileValidationError &&
+ Object.keys(error.fields).length
+ )
+ saveAttempt.current = null;
+ setState('error');
+ setMessage(
+ error instanceof ProfileValidationError
+ ? Object.keys(error.fields).length
+ ? 'Reveja os campos da preparação antes de guardar. As alterações desta página foram conservadas.'
+ : error.message
+ : 'Não foi possível confirmar a preparação. Conserve esta página e volte a guardar ou actualize para comparar.',
+ );
+ }
+ return false;
+ } finally {
+ busy.current = false;
+ if (alive.current) setTick((value) => value + 1);
+ }
+ }
+ useEffect(() => {
+ const hasWork =
+ !!current.values.title ||
+ !!current.values.due_at ||
+ !!current.pending ||
+ fields.some((field) => current.generation[field] > 0);
+ if (
+ !enabled ||
+ state !== 'ready' ||
+ comparison ||
+ busy.current ||
+ !hasWork ||
+ currentSignature === saved.current
+ )
+ return;
+ const timer = setTimeout(() => {
+ void ensure(false);
+ }, 800);
+ return () => clearTimeout(timer);
+ }, [currentSignature, enabled, state, comparison]);
+
+ const source = (field: keyof TaskValues) =>
+ choices[field]?.source ??
+ (current.generation[field] > 0 ? 'page' : 'saved');
+ const unresolved = fields.filter(
+ (field) =>
+ choices[field]?.source === 'saved' &&
+ choices[field]?.generation !== current.generation[field],
+ );
+ function choose(field: keyof TaskValues, value: 'page' | 'saved') {
+ setChoices((previous) => ({
+ ...previous,
+ [field]: {
+ source: value,
+ generation: latest.current.getSnapshot().generation[field],
+ },
+ }));
+ }
+ function recover() {
+ if (
+ !comparison?.snapshot ||
+ comparison.unavailable ||
+ busy.current ||
+ unresolved.length
+ )
+ return;
+ const now = latest.current.getSnapshot(),
+ stored = comparison.snapshot;
+ const next: TaskPreparationSnapshot = {
+ values: { ...stored.values },
+ generation: { ...stored.generation },
+ pending: stored.pending,
+ };
+ for (const field of fields) {
+ if (source(field) === 'page') {
+ next.values[field] = now.values[field];
+ next.generation[field] =
+ Math.max(
+ now.generation[field],
+ stored.generation[field],
+ stored.pending?.generation[field] ?? 0,
+ ) + 1;
+ }
+ }
+ if (!latest.current.onRecover(next)) {
+ setMessage(
+ 'Existe outro envio sem confirmação nesta página. Recupere esse envio antes de adoptar a preparação guardada.',
+ );
+ return;
+ }
+ base.current = comparison;
+ saved.current = signature(stored);
+ saveAttempt.current = null;
+ setComparison(null);
+ setChoices({});
+ setState('ready');
+ setMessage(
+ 'Preparação recuperada. Compare os campos e confirme a acção pretendida.',
+ );
+ }
+ return {
+ enabled,
+ state,
+ comparison,
+ current,
+ source,
+ unresolved,
+ choose,
+ recover,
+ ensure,
+ message,
+ blocked:
+ enabled &&
+ (!!comparison ||
+ state === 'unavailable' ||
+ state === 'saving' ||
+ state === 'error'),
+ durable:
+ enabled &&
+ state === 'ready' &&
+ !saveAttempt.current &&
+ currentSignature === saved.current,
+ manual: () => {
+ setMemoryOnly(true);
+ setComparison(null);
+ setMessage(
+ 'Continua apenas nesta página. A preparação guardada no servidor foi preservada.',
+ );
+ },
+ };
+}
diff --git a/resources/js/lib/desk-checkpoints.ts b/resources/js/lib/desk-checkpoints.ts
new file mode 100644
index 00000000..b45d9858
--- /dev/null
+++ b/resources/js/lib/desk-checkpoints.ts
@@ -0,0 +1,154 @@
+import type { DeskAnswer } from './desk-field-values';
+
+export type DeskAnswers = Record;
+export type CheckpointRequest = {
+ id: string;
+ version: number;
+ status: string;
+ payload: DeskAnswers;
+ editable_fields: string[];
+ can_edit: boolean;
+ protocol: string | null;
+ analyst_id: number | null;
+ due_at: string | null;
+};
+export type CheckpointInput = {
+ version: number;
+ request_version: number;
+ operation_key: string;
+ payload: DeskAnswers;
+ edited_keys: string[];
+ reason: string;
+};
+export type DeskCheckpoint = {
+ version: number;
+ request_version: number;
+ updated_at: string;
+ payload: DeskAnswers;
+ base_payload: DeskAnswers;
+ edited_keys: string[];
+ reason: string;
+};
+export type CheckpointView = {
+ installed: boolean;
+ request: CheckpointRequest;
+ checkpoint: DeskCheckpoint | null;
+};
+export type RecoveryChoice = 'page' | 'saved' | 'current';
+
+export function checkpointSignature(values: DeskAnswers): string {
+ return JSON.stringify(
+ Object.fromEntries(
+ Object.entries(values)
+ .sort(([a], [b]) => a.localeCompare(b))
+ .map(([key, value]) => [
+ key,
+ Array.isArray(value) ? [...value].sort() : (value ?? null),
+ ]),
+ ),
+ );
+}
+export const checkpointSame = (
+ a: DeskAnswer | undefined,
+ b: DeskAnswer | undefined,
+) =>
+ checkpointSignature({ value: a ?? null }) ===
+ checkpointSignature({ value: b ?? null });
+
+const contextKeys = [
+ 'context_opportunity',
+ 'context_opportunity_snapshot',
+ 'context_reuse',
+];
+function contextLabel(values: DeskAnswers | undefined): string {
+ if (!values?.context_opportunity) return 'Sem oportunidade seleccionada';
+ try {
+ const snapshot = JSON.parse(
+ String(values.context_opportunity_snapshot ?? '{}'),
+ );
+ if (typeof snapshot.choice?.opportunity?.title === 'string')
+ return (
+ snapshot.choice.opportunity.title +
+ (Number.isInteger(snapshot.revision)
+ ? ` · revisão ${snapshot.revision}`
+ : '')
+ );
+ } catch {
+ /* A legacy context still remains recoverable. */
+ }
+ return 'Oportunidade seleccionada; designação por recuperar';
+}
+
+/** Three sources remain explicit; a deliberate revert is still an edit. */
+export function checkpointRecovery(
+ base: DeskAnswers,
+ page: DeskAnswers,
+ edited: readonly string[],
+ current: DeskAnswers,
+ saved: DeskCheckpoint | null,
+ allowed: readonly string[],
+ choices: Record = {},
+) {
+ const payload = { ...current };
+ const conflicts: string[] = [];
+ const intent: string[] = [];
+ const rows: {
+ key: string;
+ page: DeskAnswer | null;
+ saved: DeskAnswer | null;
+ current: DeskAnswer | null;
+ conflict: boolean;
+ choice: RecoveryChoice;
+ }[] = [];
+ for (const key of allowed) {
+ if (contextKeys.includes(key) && key !== 'context_opportunity')
+ continue;
+ const group =
+ key === 'context_opportunity'
+ ? contextKeys.filter((k) => allowed.includes(k))
+ : [key];
+ const same = (a: DeskAnswers | undefined, b: DeskAnswers | undefined) =>
+ group.every((k) => checkpointSame(a?.[k], b?.[k]));
+ const local =
+ group.some((k) => edited.includes(k)) || !same(page, base);
+ const remote =
+ !!saved &&
+ (group.some((k) => saved.edited_keys.includes(k)) ||
+ !same(saved.payload, saved.base_payload));
+ if (!local && !remote) continue;
+ const conflict =
+ (local && remote && !same(page, saved?.payload)) ||
+ (local && !same(base, current) && !same(page, current)) ||
+ (remote &&
+ !same(saved?.base_payload, current) &&
+ !same(saved?.payload, current));
+ const choice = choices[key] ?? (local ? 'page' : 'saved');
+ if (conflict && !choices[key]) conflicts.push(key);
+ for (const member of group)
+ payload[member] =
+ (choice === 'page'
+ ? page[member]
+ : choice === 'saved'
+ ? saved?.payload[member]
+ : current[member]) ?? null;
+ if (choice !== 'current') intent.push(...group);
+ rows.push({
+ key,
+ page:
+ key === 'context_opportunity'
+ ? contextLabel(page)
+ : (page[key] ?? null),
+ saved:
+ key === 'context_opportunity'
+ ? contextLabel(saved?.payload)
+ : (saved?.payload[key] ?? null),
+ current:
+ key === 'context_opportunity'
+ ? contextLabel(current)
+ : (current[key] ?? null),
+ conflict,
+ choice,
+ });
+ }
+ return { payload, conflicts, intent, rows };
+}
diff --git a/resources/js/lib/desk-field-values.ts b/resources/js/lib/desk-field-values.ts
new file mode 100644
index 00000000..94670d7e
--- /dev/null
+++ b/resources/js/lib/desk-field-values.ts
@@ -0,0 +1,61 @@
+export type DeskValueField = { type: string; options?: Record };
+export type DeskAnswer = string | number | boolean | string[] | null;
+
+export function deskScalar(value: unknown): string {
+ if (typeof value === 'string' || typeof value === 'number')
+ return String(value);
+ if (typeof value === 'boolean') return value ? '1' : '';
+ return '';
+}
+
+export function deskChoices(value: unknown): string[] {
+ return Array.isArray(value) && value.every((v) => typeof v === 'string')
+ ? value
+ : [];
+}
+
+export function deskEmpty(value: unknown): boolean {
+ return (
+ value === null ||
+ value === undefined ||
+ (typeof value === 'string' && value.trim() === '') ||
+ (Array.isArray(value) && value.length === 0)
+ );
+}
+
+/** Preserve typed answers and refusals; a master/profile can never supply a consent declaration. */
+export function mergeDeskPrefill(
+ current: Record,
+ patch: Record,
+ fields: Record,
+ replace = false,
+): Record {
+ const next = { ...current };
+ for (const [key, value] of Object.entries(patch)) {
+ const field = fields[key];
+ if (
+ field?.type === 'consent' ||
+ field?.type === 'attachment' ||
+ (!replace && !deskEmpty(current[key]))
+ )
+ continue;
+ if (field?.type === 'multiselect') {
+ if (
+ Array.isArray(value) &&
+ value.every(
+ (v) =>
+ typeof v === 'string' &&
+ Object.hasOwn(field.options ?? {}, v),
+ )
+ )
+ next[key] = [...value];
+ } else if (
+ value === null ||
+ typeof value === 'string' ||
+ typeof value === 'number' ||
+ typeof value === 'boolean'
+ )
+ next[key] = value;
+ }
+ return next;
+}
diff --git a/resources/js/lib/desk-field-visibility.ts b/resources/js/lib/desk-field-visibility.ts
index 5a05cdc3..b8bffdf4 100644
--- a/resources/js/lib/desk-field-visibility.ts
+++ b/resources/js/lib/desk-field-visibility.ts
@@ -1,4 +1,6 @@
-type ConditionalField = { when?: { field: string; equals: string } };
+type ConditionalField = {
+ when?: { field: string; equals: string; operator?: 'equals' | 'contains' };
+};
export function deskFieldApplies(
key: string,
@@ -10,6 +12,21 @@ export function deskFieldApplies(
if (!field || ancestors.has(key)) return false;
if (!field.when) return true;
const value = payload[field.when.field];
+ if (field.when.operator === 'contains') {
+ if (
+ !Array.isArray(value) ||
+ !value.some(
+ (v) => typeof v === 'string' && v === field.when!.equals,
+ )
+ )
+ return false;
+ return deskFieldApplies(
+ field.when.field,
+ fields,
+ payload,
+ new Set([...ancestors, key]),
+ );
+ }
if (!['string', 'number', 'boolean'].includes(typeof value)) return false;
const answer =
typeof value === 'boolean' ? (value ? '1' : '') : String(value);
diff --git a/resources/js/lib/education-review.ts b/resources/js/lib/education-review.ts
new file mode 100644
index 00000000..8ec388b3
--- /dev/null
+++ b/resources/js/lib/education-review.ts
@@ -0,0 +1,388 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+
+export type EducationDeclaration = {
+ id: string;
+ qualification: string;
+ quantity: number;
+ status: string;
+ version_no: number;
+ period_start: string;
+ period_end: string;
+ reference_date?: string;
+ valid_until: string;
+ source: string;
+ submitted_by_name?: string | null;
+ reviewed_by_name?: string | null;
+ review_reason?: string | null;
+ employer?: string;
+ can_review?: boolean;
+ review_unavailable?: 'self' | 'expired' | null;
+ review_context?: {
+ actor_id: number;
+ commands: { key: string; version: number }[];
+ };
+};
+export type EducationReviewProps = {
+ declaration: EducationDeclaration;
+ kind: 'demands' | 'capacities';
+ actorId: number;
+ today: string;
+ references?: Record;
+};
+type Values = { version_no: number; status: string; review_reason: string };
+type Snapshot = Pick<
+ EducationDeclaration,
+ | 'version_no'
+ | 'qualification'
+ | 'quantity'
+ | 'status'
+ | 'period_start'
+ | 'period_end'
+ | 'valid_until'
+ | 'source'
+> & {
+ reference_date: string;
+ employer: string;
+ references: Record;
+};
+type Attempt = {
+ values: Values & { client_key: string };
+ reasonGeneration: number;
+ statusGeneration: number;
+ base: Snapshot;
+};
+const object = (value: unknown): value is Record =>
+ !!value && typeof value === 'object' && !Array.isArray(value);
+const positive = (value: unknown): value is number =>
+ typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
+const snapshot = (
+ row: EducationDeclaration,
+ references: Record = {},
+): Snapshot => ({
+ version_no: row.version_no,
+ qualification: row.qualification,
+ quantity: row.quantity,
+ status: row.status,
+ period_start: row.period_start,
+ period_end: row.period_end,
+ valid_until: row.valid_until,
+ source: row.source,
+ reference_date: row.reference_date ?? '',
+ employer: row.employer ?? '',
+ references: { ...references },
+});
+
+export function useEducationReview({
+ declaration: row,
+ kind,
+ actorId,
+ references = {},
+}: EducationReviewProps) {
+ const form = useForm({
+ version_no: row.version_no,
+ status: 'reviewed',
+ review_reason: '',
+ });
+ const live = useRef(form.data);
+ live.current = form.data;
+ const base = useRef(snapshot(row, references)),
+ pending = useRef(null),
+ alive = useRef(true);
+ const generation = useRef({ status: 0, review_reason: 0 });
+ const [uncertain, setUncertain] = useState(false),
+ [conflict, setConflict] = useState(false),
+ [refreshing, setRefreshing] = useState(false),
+ [accessBlocked, setAccessBlocked] = useState(false),
+ [notice, setNotice] = useState('');
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ const invalid =
+ !positive(actorId) ||
+ row.review_context?.actor_id !== actorId ||
+ !positive(row.version_no) ||
+ !Array.isArray(row.review_context?.commands);
+ const stale = form.data.version_no !== row.version_no;
+ function change(field: 'status' | 'review_reason', value: string) {
+ generation.current[field]++;
+ live.current = { ...live.current, [field]: value };
+ form.setData(live.current);
+ }
+ function read(props: unknown): EducationDeclaration | null {
+ if (
+ !object(props) ||
+ props.actorId !== actorId ||
+ props.kind !== kind ||
+ !object(props.declaration) ||
+ props.declaration.id !== row.id
+ )
+ return null;
+ const value = props.declaration;
+ if (
+ !positive(value.version_no) ||
+ !object(value.review_context) ||
+ value.review_context.actor_id !== actorId ||
+ !Array.isArray(value.review_context.commands)
+ )
+ return null;
+ return value as EducationDeclaration;
+ }
+ function returnedReferences(
+ props: Record,
+ ): Record | null {
+ if (
+ !object(props.references) ||
+ Object.values(props.references).some(
+ (value) => value !== null && typeof value !== 'string',
+ )
+ )
+ return null;
+ return props.references as Record;
+ }
+ function acknowledge(
+ record: EducationDeclaration,
+ currentReferences: Record = references,
+ ) {
+ const attempt = pending.current;
+ if (
+ !alive.current ||
+ !attempt ||
+ record.review_context?.actor_id !== actorId
+ )
+ return false;
+ const receipt = record.review_context.commands.find(
+ (item) => item.key === attempt.values.client_key,
+ );
+ if (
+ !receipt ||
+ receipt.version !== attempt.values.version_no + 1 ||
+ record.version_no < receipt.version
+ )
+ return false;
+ base.current =
+ record.version_no === receipt.version
+ ? snapshot(record, currentReferences)
+ : {
+ ...attempt.base,
+ version_no: receipt.version,
+ status: attempt.values.status,
+ };
+ live.current = {
+ version_no: receipt.version,
+ status:
+ generation.current.status === attempt.statusGeneration
+ ? 'reviewed'
+ : live.current.status,
+ review_reason:
+ generation.current.review_reason === attempt.reasonGeneration
+ ? ''
+ : live.current.review_reason,
+ };
+ form.setData(live.current);
+ form.clearErrors();
+ pending.current = null;
+ setUncertain(false);
+ setConflict(false);
+ setAccessBlocked(false);
+ setNotice(
+ 'Revisão registada. As alterações posteriores ao envio foram conservadas.',
+ );
+ return true;
+ }
+ useEffect(() => {
+ if (!invalid && pending.current) acknowledge(row);
+ }, [row, actorId, invalid]);
+ function submit() {
+ if (
+ invalid ||
+ accessBlocked ||
+ refreshing ||
+ form.processing ||
+ (!pending.current && (row.can_review !== true || stale || conflict))
+ )
+ return;
+ if (!pending.current) {
+ let key: string;
+ try {
+ key = createOperationKey();
+ } catch {
+ setNotice(
+ 'Não foi possível preparar a decisão. Reabra o portal no endereço HTTPS configurado.',
+ );
+ return;
+ }
+ pending.current = {
+ values: { ...live.current, client_key: key },
+ reasonGeneration: generation.current.review_reason,
+ statusGeneration: generation.current.status,
+ base: { ...base.current },
+ };
+ }
+ const attempt = pending.current;
+ setUncertain(true);
+ setNotice('A aguardar confirmação da revisão.');
+ form.transform(() => attempt.values);
+ form.post(`/management/education/${kind}/${row.id}/review`, {
+ preserveScroll: true,
+ onSuccess: (page) => {
+ if (!alive.current || pending.current !== attempt) return;
+ const record = read(page.props),
+ labels = returnedReferences(page.props);
+ if (!record || !labels || !acknowledge(record, labels))
+ setNotice(
+ 'A resposta não permitiu confirmar a revisão. Actualize a declaração ou recupere o mesmo envio.',
+ );
+ },
+ onError: () => {
+ if (!alive.current || pending.current !== attempt) return;
+ pending.current = null;
+ setUncertain(false);
+ setNotice(
+ 'Reveja os campos assinalados. A decisão preparada foi conservada.',
+ );
+ },
+ onNetworkError: () => {
+ if (alive.current && pending.current === attempt)
+ setNotice(
+ 'Sem confirmação da revisão. Recupere o mesmo envio antes de preparar outra decisão.',
+ );
+ },
+ onCancel: () => {
+ if (alive.current && pending.current === attempt)
+ setNotice(
+ 'Envio interrompido sem confirmação. Recupere o mesmo envio.',
+ );
+ },
+ onHttpException: (response) => {
+ if (!alive.current || pending.current !== attempt) return;
+ if ([401, 403, 419].includes(response.status))
+ setAccessBlocked(true);
+ if (response.status === 422) {
+ pending.current = null;
+ setUncertain(false);
+ }
+ if ([409, 422].includes(response.status)) setConflict(true);
+ setNotice(
+ 'Não foi possível confirmar a revisão. Actualize a declaração e o acesso antes de continuar. A decisão preparada foi conservada.',
+ );
+ },
+ });
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: [
+ 'declaration',
+ 'references',
+ 'today',
+ 'actorId',
+ 'kind',
+ 'history',
+ ],
+ onSuccess: (page) => {
+ if (!alive.current) return;
+ const record = read(page.props),
+ labels = returnedReferences(page.props);
+ if (!record || !labels) return;
+ setAccessBlocked(false);
+ if (pending.current) acknowledge(record, labels);
+ },
+ onFinish: () => {
+ if (alive.current) setRefreshing(false);
+ },
+ });
+ }
+ function adopt() {
+ if (
+ invalid ||
+ !stale ||
+ row.can_review !== true ||
+ refreshing ||
+ form.processing
+ )
+ return;
+ const attempt = pending.current;
+ if (attempt) {
+ if (acknowledge(row)) return;
+ if (
+ row.version_no <= attempt.values.version_no ||
+ row.review_context?.commands.some(
+ (item) => item.key === attempt.values.client_key,
+ )
+ )
+ return;
+ pending.current = null;
+ setUncertain(false);
+ }
+ base.current = snapshot(row, references);
+ live.current = { ...live.current, version_no: row.version_no };
+ form.setData(live.current);
+ setConflict(false);
+ form.clearErrors('version_no');
+ setNotice(
+ 'Versão actual confirmada. A sua decisão preparada foi conservada para rever antes de enviar.',
+ );
+ }
+ const guard = useRef(false);
+ guard.current =
+ uncertain ||
+ !!form.data.review_reason ||
+ form.data.status !== 'reviewed';
+ useEffect(() => {
+ const remove = router.on('before', (event) => {
+ if (
+ guard.current &&
+ event.detail.visit.method === 'get' &&
+ !event.detail.visit.preserveState &&
+ !window.confirm(
+ 'Existe uma revisão preparada ou um envio sem confirmação. Sair desta página?',
+ )
+ )
+ event.preventDefault();
+ });
+ const unload = (event: BeforeUnloadEvent) => {
+ if (guard.current) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ window.addEventListener('beforeunload', unload);
+ return () => {
+ remove();
+ window.removeEventListener('beforeunload', unload);
+ };
+ }, []);
+ return {
+ form,
+ change,
+ submit,
+ refresh,
+ adopt,
+ base: base.current,
+ current: snapshot(row, references),
+ stale,
+ conflict,
+ refreshing,
+ uncertain,
+ notice,
+ canAdopt:
+ !invalid &&
+ stale &&
+ row.can_review === true &&
+ !refreshing &&
+ !form.processing,
+ blocked:
+ invalid ||
+ accessBlocked ||
+ refreshing ||
+ (!pending.current &&
+ (row.can_review !== true || stale || conflict)),
+ sent: pending.current?.values,
+ };
+}
diff --git a/resources/js/lib/investment-guides.ts b/resources/js/lib/investment-guides.ts
new file mode 100644
index 00000000..34bac561
--- /dev/null
+++ b/resources/js/lib/investment-guides.ts
@@ -0,0 +1,34 @@
+export type GuideSelection = {
+ slug: string;
+ sha256: string;
+ instruments: string[];
+};
+
+export function guideUrl(
+ base: string,
+ selection: GuideSelection,
+ choosingDossier = false,
+): string {
+ const query = new URLSearchParams();
+ if (choosingDossier) {
+ query.set('investment_guide[slug]', selection.slug);
+ query.set('investment_guide[sha256]', selection.sha256);
+ selection.instruments.forEach((code) =>
+ query.append('investment_guide[instruments][]', code),
+ );
+ } else {
+ query.set('current', '1');
+ query.set('selection', '1');
+ query.set('sha256', selection.sha256);
+ selection.instruments.forEach((code) =>
+ query.append('instruments[]', code),
+ );
+ }
+ return `${base}?${query}`;
+}
+
+export function guideChoices(form: HTMLFormElement): string[] {
+ return new FormData(form)
+ .getAll('instruments[]')
+ .filter((v): v is string => typeof v === 'string');
+}
diff --git a/resources/js/lib/investment-profile-editor.ts b/resources/js/lib/investment-profile-editor.ts
new file mode 100644
index 00000000..d8e37638
--- /dev/null
+++ b/resources/js/lib/investment-profile-editor.ts
@@ -0,0 +1,433 @@
+import { router } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+import { portalRequest, PortalApiError } from './portal-api';
+
+export type ProfileRecord = {
+ id?: string;
+ version: number;
+ payload: Record;
+};
+export type OrganizationRecord = {
+ id: string;
+ name: string;
+ version: number;
+ country: string | null;
+ canEdit: boolean;
+ provenance: { reference: string; kind: string } | null;
+};
+type Attempt = {
+ version: number;
+ payload: Record;
+ operation_key: string;
+};
+const values = (record: ProfileRecord, fields: string[]) =>
+ Object.fromEntries(
+ [...fields, 'country'].map((key) => [key, record.payload[key] ?? '']),
+ );
+const same = (left: Record, right: Record) =>
+ JSON.stringify(left) === JSON.stringify(right);
+
+export function useInvestmentProfileEditor(
+ record: ProfileRecord,
+ fields: string[],
+ company: boolean,
+ actorId: number,
+ editorId: string,
+ reportDirty: (id: string, dirty: boolean) => void,
+ organization?: { id: string; canEdit: boolean },
+) {
+ const [base, setBase] = useState(() => ({
+ ...record,
+ payload: values(record, fields),
+ })),
+ [draft, setDraft] = useState(() => values(record, fields)),
+ [remote, setRemote] = useState(null),
+ [busy, setBusy] = useState(false),
+ [reading, setReading] = useState(false),
+ [uncertain, setUncertain] = useState(false),
+ [blocked, setBlocked] = useState(false),
+ [errors, setErrors] = useState>({}),
+ [error, setError] = useState(''),
+ [notice, setNotice] = useState(''),
+ [externalBusy, setExternalBusy] = useState(false),
+ [permission, setPermission] = useState<{
+ editable: boolean;
+ propVersion: number;
+ propCanEdit: boolean;
+ } | null>(null);
+ const pending = useRef(null),
+ externalLock = useRef(false),
+ readInFlight = useRef(false),
+ active = useRef(false),
+ alive = useRef(true),
+ origin = useRef({ actorId, id: record.id }),
+ current = useRef({ actorId, id: record.id });
+ current.current = { actorId, id: record.id };
+ const valid = () =>
+ alive.current &&
+ Number.isSafeInteger(actorId) &&
+ actorId > 0 &&
+ origin.current.actorId === current.current.actorId &&
+ origin.current.id === current.current.id;
+ const dirty =
+ !same(draft, base.payload) || busy || uncertain || externalBusy;
+ const stale = (!company || !!record.id) && record.version > base.version;
+ const mayEdit =
+ !organization ||
+ (permission &&
+ permission.propVersion === record.version &&
+ permission.propCanEdit === organization.canEdit
+ ? permission.editable
+ : organization.canEdit);
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ useEffect(() => {
+ reportDirty(editorId, dirty);
+ }, [dirty, editorId, reportDirty]);
+ useEffect(
+ () => () => reportDirty(editorId, false),
+ [editorId, reportDirty],
+ );
+ function change(key: string, value: string) {
+ if (
+ active.current ||
+ externalLock.current ||
+ uncertain ||
+ blocked ||
+ !mayEdit ||
+ !valid()
+ )
+ return;
+ setDraft((prior) => ({ ...prior, [key]: value }));
+ setErrors((prior) => {
+ const next = { ...prior };
+ delete next['payload.' + key];
+ delete next[key];
+ return next;
+ });
+ setNotice('');
+ }
+ async function save() {
+ if (
+ active.current ||
+ externalLock.current ||
+ readInFlight.current ||
+ reading ||
+ blocked ||
+ !mayEdit ||
+ !valid() ||
+ (stale && !pending.current)
+ )
+ return;
+ try {
+ pending.current ??= {
+ version: base.version,
+ payload: { ...draft },
+ operation_key: createOperationKey(),
+ };
+ } catch (failure) {
+ setError(
+ failure instanceof Error
+ ? failure.message
+ : 'Não foi possível preparar o pedido.',
+ );
+ return;
+ }
+ const attempt = pending.current;
+ active.current = true;
+ setBusy(true);
+ setError('');
+ setErrors({});
+ setNotice('');
+ try {
+ const result = await portalRequest<{
+ version: number;
+ id?: string;
+ country?: string;
+ }>(
+ organization
+ ? '/api/v1/investment/organizations/' +
+ organization.id +
+ '/country'
+ : company
+ ? '/api/v1/investment/companies' +
+ (record.id ? '/' + record.id : '')
+ : '/api/v1/investment/profile',
+ {
+ method: company ? 'POST' : 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(
+ organization
+ ? {
+ version: attempt.version,
+ operation_key: attempt.operation_key,
+ ...attempt.payload,
+ }
+ : attempt,
+ ),
+ },
+ );
+ if (!valid() || pending.current !== attempt) return;
+ if (
+ !Number.isSafeInteger(result.version) ||
+ result.version !== attempt.version + 1 ||
+ (organization && result.country !== attempt.payload.country) ||
+ (company &&
+ (typeof result.id !== 'string' ||
+ !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(
+ result.id,
+ ) ||
+ (record.id && result.id !== record.id)))
+ )
+ throw new Error('Unconfirmed response');
+ pending.current = null;
+ setUncertain(false);
+ setRemote(null);
+ if (company && !record.id) {
+ const empty = values({ version: 0, payload: {} }, fields);
+ setDraft(empty);
+ setBase({ version: 0, payload: empty });
+ } else
+ setBase({
+ ...record,
+ version: result.version,
+ payload: { ...attempt.payload },
+ });
+ setNotice('Gravação confirmada.');
+ router.reload({
+ only: organization
+ ? ['organizations']
+ : ['account', 'companies'],
+ });
+ } catch (failure) {
+ if (!valid() || pending.current !== attempt) return;
+ if (failure instanceof PortalApiError && failure.status === 422) {
+ pending.current = null;
+ setUncertain(false);
+ setErrors(
+ Object.fromEntries(
+ Object.entries(failure.errors).map(
+ ([key, messages]) => [
+ key,
+ messages[0] ?? 'Verifique este campo.',
+ ],
+ ),
+ ),
+ );
+ setError('Verifique os campos assinalados.');
+ } else if (
+ failure instanceof PortalApiError &&
+ failure.status === 409
+ ) {
+ pending.current = null;
+ setUncertain(false);
+ setBlocked(true);
+ setError(
+ 'O registo mudou ou este pedido já tem outro conteúdo. Consulte e compare o registo guardado antes de voltar a gravar.',
+ );
+ } else if (
+ failure instanceof PortalApiError &&
+ [401, 403, 404, 419].includes(failure.status)
+ ) {
+ setBlocked(true);
+ setUncertain(true);
+ setError(
+ 'A sessão ou o acesso já não permite confirmar o pedido. A preparação permanece nesta página. Restabeleça o acesso e consulte o registo.',
+ );
+ } else {
+ setUncertain(true);
+ setError(
+ 'Não foi possível confirmar a gravação. A preparação foi conservada. Repita o mesmo pedido para confirmar o resultado antes de editar.',
+ );
+ }
+ } finally {
+ if (valid()) {
+ active.current = false;
+ setBusy(false);
+ }
+ }
+ }
+ async function refresh() {
+ if (
+ active.current ||
+ externalLock.current ||
+ readInFlight.current ||
+ !valid()
+ )
+ return;
+ readInFlight.current = true;
+ setReading(true);
+ setError('');
+ try {
+ const response = await portalRequest<{
+ actorId: number;
+ account: ProfileRecord;
+ companies: ProfileRecord[];
+ organizations?: OrganizationRecord[];
+ }>('/api/v1/investment/profile');
+ if (!valid()) return;
+ if (
+ response.actorId !== actorId ||
+ !Array.isArray(response.companies)
+ )
+ throw new Error('Context changed');
+ const org = organization
+ ? response.organizations?.find(
+ (item) => item.id === organization.id,
+ )
+ : undefined;
+ if (
+ organization &&
+ (!org ||
+ typeof org.canEdit !== 'boolean' ||
+ (org.country !== null && typeof org.country !== 'string') ||
+ (org.provenance !== null &&
+ typeof org.provenance?.reference !== 'string'))
+ ) {
+ setBlocked(true);
+ throw new Error('Organisation unavailable');
+ }
+ if (org && organization)
+ setPermission({
+ editable: org.canEdit,
+ propVersion: record.version,
+ propCanEdit: organization.canEdit,
+ });
+ const next = org
+ ? {
+ id: org.id,
+ version: org.version,
+ payload: {
+ country: org.country ?? '',
+ source_reference: org.provenance?.reference ?? '',
+ },
+ }
+ : company
+ ? record.id
+ ? response.companies.find((item) => item.id === record.id)
+ : { version: 0, payload: {} }
+ : response.account;
+ if (
+ !next ||
+ !Number.isSafeInteger(next.version) ||
+ next.version < 0 ||
+ !next.payload ||
+ typeof next.payload !== 'object' ||
+ Array.isArray(next.payload) ||
+ fields.some(
+ (key) =>
+ next.payload[key] != null &&
+ typeof next.payload[key] !== 'string',
+ )
+ )
+ throw new Error('Record unavailable');
+ setRemote({ ...next, payload: values(next, fields) });
+ setBlocked(pending.current === null);
+ setNotice(
+ uncertain
+ ? 'Registo consultado. Confirme primeiro o pedido sem resposta; a preparação não foi alterada.'
+ : 'Registo consultado. Compare os valores antes de escolher como continuar.',
+ );
+ } catch {
+ if (valid())
+ setError(
+ 'Não foi possível consultar o registo nesta sessão. A preparação foi conservada.',
+ );
+ } finally {
+ if (valid()) {
+ readInFlight.current = false;
+ setReading(false);
+ }
+ }
+ }
+ function adopt(keepDraft: boolean) {
+ if (
+ !remote ||
+ active.current ||
+ externalLock.current ||
+ readInFlight.current ||
+ busy ||
+ reading ||
+ uncertain ||
+ pending.current ||
+ !mayEdit ||
+ !valid()
+ )
+ return;
+ setBase(remote);
+ if (!keepDraft) setDraft({ ...remote.payload });
+ setRemote(null);
+ setBlocked(false);
+ setError('');
+ setErrors({});
+ setNotice(
+ keepDraft
+ ? 'Versão actual adoptada; a sua preparação foi conservada. Reveja antes de guardar.'
+ : 'Valores guardados carregados.',
+ );
+ }
+ function beginCountryReuse(): boolean {
+ if (
+ !company ||
+ !record.id ||
+ dirty ||
+ blocked ||
+ stale ||
+ active.current ||
+ readInFlight.current ||
+ externalLock.current ||
+ pending.current ||
+ !valid()
+ )
+ return false;
+ externalLock.current = true;
+ setExternalBusy(true);
+ return true;
+ }
+ function endCountryReuse(result?: {
+ version: number;
+ country: string;
+ }): void {
+ if (!externalLock.current || !valid()) return;
+ if (result) {
+ const payload = {
+ ...base.payload,
+ incorporation_country_code: result.country,
+ };
+ setBase({ ...base, version: result.version, payload });
+ setDraft(payload);
+ setRemote(null);
+ setErrors({});
+ setError('');
+ }
+ externalLock.current = false;
+ setExternalBusy(false);
+ }
+ return {
+ base,
+ draft,
+ busy,
+ reading,
+ uncertain,
+ blocked,
+ errors,
+ error,
+ notice,
+ stale,
+ remote,
+ dirty,
+ externalBusy,
+ beginCountryReuse,
+ endCountryReuse,
+ mayEdit,
+ change,
+ save,
+ refresh,
+ adopt,
+ };
+}
diff --git a/resources/js/lib/organization-country-reuse.ts b/resources/js/lib/organization-country-reuse.ts
new file mode 100644
index 00000000..73416444
--- /dev/null
+++ b/resources/js/lib/organization-country-reuse.ts
@@ -0,0 +1,325 @@
+import { router } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+import { portalRequest, PortalApiError } from './portal-api';
+import type {
+ useInvestmentProfileEditor,
+ OrganizationRecord,
+} from './investment-profile-editor';
+
+export type CountryReusePreview = {
+ organizationId: string;
+ organizationName: string;
+ organizationVersion: number;
+ country: string;
+ reference: string;
+ companyVersion: number;
+ companyCountry: string;
+};
+type Attempt = {
+ version: number;
+ organization_id: string;
+ organization_version: number;
+ operation_key: string;
+ country: string;
+};
+type Editor = ReturnType;
+const object = (value: unknown): value is Record =>
+ !!value && typeof value === 'object' && !Array.isArray(value);
+const version = (value: unknown): value is number =>
+ typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;
+
+export function useOrganizationCountryReuse(
+ companyId: string,
+ actorId: number,
+ editor: Editor,
+ reportDirty: (id: string, dirty: boolean) => void,
+ organizations: OrganizationRecord[],
+) {
+ const [preview, setPreview] = useState(null),
+ [busy, setBusy] = useState(false),
+ [reading, setReading] = useState(false),
+ [uncertain, setUncertain] = useState(false),
+ [blocked, setBlocked] = useState(false),
+ [error, setError] = useState(''),
+ [notice, setNotice] = useState('');
+ const pending = useRef(null),
+ active = useRef(false),
+ alive = useRef(true),
+ liveEditor = useRef(editor),
+ sources = useRef(organizations),
+ origin = useRef({ companyId, actorId }),
+ current = useRef({ companyId, actorId });
+ current.current = { companyId, actorId };
+ liveEditor.current = editor;
+ sources.current = organizations;
+ const valid = () =>
+ alive.current &&
+ Number.isSafeInteger(actorId) &&
+ actorId > 0 &&
+ origin.current.actorId === current.current.actorId &&
+ origin.current.companyId === current.current.companyId;
+ const changedSource = () => {
+ if (!preview || pending.current) return false;
+ const source = sources.current.find(
+ (item) => item.id === preview.organizationId,
+ );
+ return (
+ !source ||
+ source.version > preview.organizationVersion ||
+ (source.version === preview.organizationVersion &&
+ source.country !== preview.country)
+ );
+ };
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ useEffect(() => {
+ reportDirty(
+ 'country-reuse-' + companyId,
+ !!preview || busy || uncertain,
+ );
+ }, [preview, busy, uncertain, companyId, reportDirty]);
+ useEffect(
+ () => () => reportDirty('country-reuse-' + companyId, false),
+ [companyId, reportDirty],
+ );
+
+ async function inspect(organizationId: string) {
+ if (active.current || !valid()) return;
+ if (
+ !pending.current &&
+ (liveEditor.current.dirty ||
+ liveEditor.current.blocked ||
+ liveEditor.current.stale)
+ ) {
+ setError(
+ 'Guarde ou confirme a preparação desta declaração antes de reutilizar o país.',
+ );
+ return;
+ }
+ active.current = true;
+ setReading(true);
+ setError('');
+ setNotice('');
+ try {
+ const data = await portalRequest(
+ '/api/v1/investment/profile',
+ );
+ if (!valid()) return;
+ if (
+ !object(data) ||
+ data.actorId !== actorId ||
+ !Array.isArray(data.companies) ||
+ !Array.isArray(data.organizations)
+ )
+ throw new Error('Invalid context');
+ const company = data.companies.find(
+ (item) => object(item) && item.id === companyId,
+ ),
+ source = data.organizations.find(
+ (item) => object(item) && item.id === organizationId,
+ );
+ if (
+ !object(company) ||
+ !version(company.version) ||
+ !object(company.payload) ||
+ !object(source) ||
+ !version(source.version) ||
+ typeof source.name !== 'string'
+ ) {
+ setBlocked(true);
+ throw new Error('Source unavailable');
+ }
+ if (pending.current) {
+ setBlocked(false);
+ setNotice(
+ 'Estado consultado: declaração na versão ' +
+ company.version +
+ '. Confirme o pedido sem resposta antes de preparar outra reutilização.',
+ );
+ return;
+ }
+ if (
+ company.version !== liveEditor.current.base.version ||
+ liveEditor.current.dirty
+ ) {
+ setPreview(null);
+ setError(
+ 'A declaração ou a preparação mudou. Consulte e compare o registo no formulário antes de reutilizar.',
+ );
+ router.reload({ only: ['companies', 'organizations'] });
+ return;
+ }
+ if (
+ typeof source.country !== 'string' ||
+ !/^[A-Z]{2}$/.test(source.country)
+ ) {
+ setPreview(null);
+ setError(
+ 'O país de constituição ainda não está disponível nesta organização.',
+ );
+ return;
+ }
+ const reference =
+ object(source.provenance) &&
+ typeof source.provenance.reference === 'string'
+ ? source.provenance.reference
+ : '';
+ setPreview({
+ organizationId,
+ organizationName: source.name,
+ organizationVersion: source.version,
+ country: source.country,
+ reference,
+ companyVersion: company.version,
+ companyCountry:
+ typeof company.payload.incorporation_country_code ===
+ 'string'
+ ? company.payload.incorporation_country_code
+ : '',
+ });
+ setBlocked(false);
+ } catch {
+ if (valid())
+ setError(
+ 'Não foi possível consultar a declaração e a organização nesta sessão. A preparação foi conservada.',
+ );
+ } finally {
+ if (valid()) {
+ active.current = false;
+ setReading(false);
+ }
+ }
+ }
+ async function confirm() {
+ if (active.current || blocked || !valid()) return;
+ if (!pending.current) {
+ if (changedSource()) {
+ setError(
+ 'A organização mudou. Consulte novamente o país antes de confirmar.',
+ );
+ return;
+ }
+ if (
+ !preview ||
+ preview.companyVersion !== liveEditor.current.base.version
+ ) {
+ setError('Volte a consultar os valores antes de confirmar.');
+ return;
+ }
+ let key: string;
+ try {
+ key = createOperationKey();
+ } catch (failure) {
+ setError(
+ failure instanceof Error
+ ? failure.message
+ : 'Não foi possível preparar o pedido.',
+ );
+ return;
+ }
+ if (!liveEditor.current.beginCountryReuse()) {
+ setError(
+ 'Guarde ou confirme a preparação desta declaração antes de reutilizar o país.',
+ );
+ return;
+ }
+ pending.current = {
+ version: preview.companyVersion,
+ organization_id: preview.organizationId,
+ organization_version: preview.organizationVersion,
+ operation_key: key,
+ country: preview.country,
+ };
+ }
+ const attempt = pending.current;
+ active.current = true;
+ setBusy(true);
+ setError('');
+ setNotice('');
+ try {
+ const { country: expectedCountry, ...command } = attempt;
+ const result = await portalRequest(
+ '/api/v1/investment/companies/' +
+ companyId +
+ '/organization-country',
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(command),
+ },
+ );
+ if (!valid() || pending.current !== attempt) return;
+ if (
+ !object(result) ||
+ !version(result.version) ||
+ result.version !== attempt.version + 1 ||
+ result.country !== expectedCountry
+ )
+ throw new Error('Unconfirmed result');
+ liveEditor.current.endCountryReuse({
+ version: result.version,
+ country: expectedCountry,
+ });
+ pending.current = null;
+ setPreview(null);
+ setUncertain(false);
+ setBlocked(false);
+ setNotice('País reutilizado e gravação confirmada.');
+ router.reload({ only: ['companies', 'organizations'] });
+ } catch (failure) {
+ if (!valid() || pending.current !== attempt) return;
+ if (
+ failure instanceof PortalApiError &&
+ [409, 422].includes(failure.status)
+ ) {
+ pending.current = null;
+ liveEditor.current.endCountryReuse();
+ setUncertain(false);
+ setPreview(null);
+ setError(
+ 'A declaração ou a fonte já não corresponde ao pedido. Consulte os valores guardados antes de preparar outra reutilização.',
+ );
+ router.reload({ only: ['companies', 'organizations'] });
+ } else {
+ setUncertain(true);
+ setBlocked(
+ failure instanceof PortalApiError &&
+ [401, 403, 404, 419].includes(failure.status),
+ );
+ setError(
+ 'Não foi possível confirmar a reutilização. O pedido original foi conservado. Consulte o estado ou repita o mesmo pedido antes de editar.',
+ );
+ }
+ } finally {
+ if (valid()) {
+ active.current = false;
+ setBusy(false);
+ }
+ }
+ }
+ function cancel() {
+ if (pending.current || active.current || !valid()) return;
+ setPreview(null);
+ setError('');
+ setNotice('');
+ }
+ return {
+ preview,
+ busy,
+ reading,
+ uncertain,
+ blocked,
+ error,
+ notice,
+ inspect,
+ confirm,
+ cancel,
+ sourceChanged: changedSource(),
+ pendingOrganizationId: pending.current?.organization_id,
+ };
+}
diff --git a/resources/js/lib/page-preparation-guard.ts b/resources/js/lib/page-preparation-guard.ts
new file mode 100644
index 00000000..6cf13252
--- /dev/null
+++ b/resources/js/lib/page-preparation-guard.ts
@@ -0,0 +1,28 @@
+import { router } from '@inertiajs/react';
+import { useEffect, useRef } from 'react';
+export function usePagePreparationGuard(dirty: boolean, message: string) {
+ const guard = useRef({ dirty, message });
+ guard.current = { dirty, message };
+ useEffect(() => {
+ const remove = router.on('before', (event) => {
+ if (
+ guard.current.dirty &&
+ event.detail.visit.method === 'get' &&
+ !event.detail.visit.preserveState &&
+ !window.confirm(guard.current.message)
+ )
+ event.preventDefault();
+ });
+ const unload = (event: BeforeUnloadEvent) => {
+ if (guard.current.dirty) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ window.addEventListener('beforeunload', unload);
+ return () => {
+ remove();
+ window.removeEventListener('beforeunload', unload);
+ };
+ }, []);
+}
diff --git a/resources/js/lib/partnership-agreement.ts b/resources/js/lib/partnership-agreement.ts
new file mode 100644
index 00000000..3ebf94b0
--- /dev/null
+++ b/resources/js/lib/partnership-agreement.ts
@@ -0,0 +1,63 @@
+export type Confirmation = {
+ actorId: number | null;
+ actorName: string | null;
+ date: string | null;
+ reason: string | null;
+};
+export const agreementParties = ['proponent', 'candidate'] as const;
+export function agreementObject(
+ value: unknown,
+): value is Record {
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
+}
+const text = (value: unknown) => (typeof value === 'string' ? value : null);
+export function readAgreement(value: unknown) {
+ const record = agreementObject(value) ? value : null;
+ const map =
+ record && agreementObject(record.confirmations)
+ ? record.confirmations
+ : record &&
+ Array.isArray(record.confirmations) &&
+ record.confirmations.length === 0
+ ? {}
+ : null;
+ const confirmations: Partial<
+ Record<(typeof agreementParties)[number], Confirmation>
+ > = {};
+ for (const party of agreementParties) {
+ if (!map || !Object.hasOwn(map, party)) continue;
+ const stamp = agreementObject(map[party]) ? map[party] : {};
+ const id = stamp.actor_id;
+ confirmations[party] = {
+ actorId:
+ typeof id === 'number' && Number.isSafeInteger(id) && id > 0
+ ? id
+ : null,
+ actorName: text(stamp.actor_name),
+ date: text(stamp.date),
+ reason: text(stamp.reason),
+ };
+ }
+ return {
+ kind:
+ value == null
+ ? ('absent' as const)
+ : record
+ ? ('recorded' as const)
+ : ('malformed' as const),
+ title: text(record?.title),
+ terms: text(record?.terms),
+ confirmationsState: map
+ ? ('recorded' as const)
+ : record?.confirmations == null
+ ? ('absent' as const)
+ : ('malformed' as const),
+ confirmations,
+ extraConfirmations:
+ !!map &&
+ Object.keys(map).some(
+ (key) => !agreementParties.some((party) => party === key),
+ ),
+ legalStatus: text(record?.legal_signature_status),
+ };
+}
diff --git a/resources/js/lib/partnership-candidacy-edit.ts b/resources/js/lib/partnership-candidacy-edit.ts
new file mode 100644
index 00000000..51a3b5b5
--- /dev/null
+++ b/resources/js/lib/partnership-candidacy-edit.ts
@@ -0,0 +1,805 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+type Values = Record;
+type Criterion = {
+ code: string;
+ label: string;
+ weight: number;
+ mandatory: boolean;
+};
+type Snapshot = {
+ id: number | null;
+ version: number | null;
+ parentVersion: number;
+ status: string;
+ context: string;
+ weightsHash: string;
+ criteria: Criterion[];
+ owner: boolean;
+ canSubmit: boolean;
+ canDecide: boolean;
+ canWithdraw: boolean;
+ values: Values;
+ commands: { key: string; version: number; action: string }[];
+};
+function object(value: unknown): value is Record {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+function dictionary(value: unknown): Record | null {
+ return object(value)
+ ? value
+ : Array.isArray(value) && value.length === 0
+ ? {}
+ : null;
+}
+function positive(value: unknown): value is number {
+ return (
+ typeof value === 'number' && Number.isSafeInteger(value) && value > 0
+ );
+}
+function text(value: unknown): string | null {
+ return value == null ? '' : typeof value === 'string' ? value : null;
+}
+export function criterionValue(value: string | undefined): {
+ state: string;
+ evidence: string;
+} {
+ try {
+ const item: unknown = JSON.parse(value ?? '');
+ if (
+ object(item) &&
+ ['unknown', 'met', 'unmet'].includes(String(item.state)) &&
+ typeof item.evidence === 'string'
+ )
+ return { state: String(item.state), evidence: item.evidence };
+ } catch {
+ /* An invalid preparation is not an assessment. */
+ }
+ return { state: 'unknown', evidence: '' };
+}
+const pack = (state: string, evidence: string) =>
+ JSON.stringify({ state, evidence });
+function read(
+ props: unknown,
+ recordId: number,
+ target: number | null,
+ mode: 'submission' | 'decision',
+ actorId: number | null,
+ key?: string,
+ action?: string,
+): Snapshot | null {
+ if (
+ !object(props) ||
+ !object(props.record) ||
+ props.record.id !== recordId ||
+ !positive(props.record.version) ||
+ typeof props.record.status !== 'string' ||
+ typeof props.owner !== 'boolean' ||
+ typeof props.canEdit !== 'boolean' ||
+ typeof props.acceptingInterests !== 'boolean' ||
+ !Array.isArray(props.interests)
+ )
+ return null;
+ const record = props.record;
+ const item = key
+ ? props.interests.find(
+ (item) =>
+ object(item) &&
+ Array.isArray(item.commands) &&
+ item.commands.some(
+ (command) =>
+ object(command) &&
+ command.key === key &&
+ command.action === action,
+ ),
+ )
+ : target === null
+ ? null
+ : props.interests.find((item) => object(item) && item.id === target);
+ if ((target !== null && !object(item)) || (key && !object(item)))
+ return null;
+ const entry = object(item) ? item : null;
+ if (
+ entry &&
+ (!positive(entry.id) ||
+ !positive(entry.version) ||
+ typeof entry.status !== 'string' ||
+ typeof entry.can_edit !== 'boolean' ||
+ !dictionary(entry.payload) ||
+ !dictionary(entry.assessment) ||
+ !object(entry.match) ||
+ !Array.isArray(entry.match.criteria) ||
+ typeof entry.match.weights_hash !== 'string' ||
+ !/^[a-f0-9]{64}$/.test(entry.match.weights_hash))
+ )
+ return null;
+ const match = entry && object(entry.match) ? entry.match : null;
+ const criteria: Criterion[] = [];
+ for (const candidate of match && Array.isArray(match.criteria)
+ ? match.criteria
+ : []) {
+ if (
+ !object(candidate) ||
+ typeof candidate.code !== 'string' ||
+ typeof candidate.label !== 'string' ||
+ typeof candidate.weight !== 'number' ||
+ typeof candidate.mandatory !== 'boolean'
+ )
+ return null;
+ criteria.push({
+ code: candidate.code,
+ label: candidate.label,
+ weight: candidate.weight,
+ mandatory: candidate.mandatory,
+ });
+ }
+ const values: Values = {};
+ if (mode === 'submission') {
+ const payload = entry ? (dictionary(entry.payload) ?? {}) : {};
+ for (const field of ['organization_id', 'proposal']) {
+ const value = text(entry?.[field]);
+ if (value === null) return null;
+ values[field] = value;
+ }
+ for (const field of [
+ 'capacity',
+ 'availability',
+ 'contribution',
+ 'conflicts',
+ ]) {
+ const value = text(payload[field]);
+ if (value === null) return null;
+ values[field] = value;
+ }
+ values.consent = [true, 1, '1', 'yes', 'on'].includes(
+ payload.consent as string | number | boolean,
+ )
+ ? 'yes'
+ : 'no';
+ } else {
+ values.reason = '';
+ const assessment = entry ? (dictionary(entry.assessment) ?? {}) : {};
+ for (const criterion of props.owner ? criteria : []) {
+ const data = assessment[criterion.code];
+ const assessed = object(data) ? data : {};
+ const state = assessed.state ?? 'unknown',
+ evidence = text(assessed.evidence);
+ if (
+ typeof state !== 'string' ||
+ !['met', 'unmet', 'unknown'].includes(state) ||
+ evidence === null
+ )
+ return null;
+ values['criterion:' + criterion.code] = pack(state, evidence);
+ }
+ }
+ const commands: Snapshot['commands'] = [];
+ for (const candidate of entry && Array.isArray(entry.commands)
+ ? entry.commands
+ : [])
+ if (
+ object(candidate) &&
+ typeof candidate.key === 'string' &&
+ positive(candidate.version) &&
+ typeof candidate.action === 'string'
+ )
+ commands.push({
+ key: candidate.key,
+ version: candidate.version,
+ action: candidate.action,
+ });
+ const id = entry && positive(entry.id) ? entry.id : null,
+ version = entry && positive(entry.version) ? entry.version : null,
+ status =
+ entry && typeof entry.status === 'string' ? entry.status : 'new';
+ const effectiveRepresentation = entry
+ ? entry.can_edit === true
+ : !!actorId && !props.owner;
+ const context =
+ mode === 'submission'
+ ? [
+ record.version,
+ record.status,
+ record.deadline,
+ props.owner,
+ effectiveRepresentation,
+ props.acceptingInterests,
+ ]
+ : props.owner
+ ? [
+ record.version,
+ record.status,
+ record.deadline,
+ props.owner,
+ props.canEdit,
+ match?.weights_hash,
+ criteria,
+ ]
+ : [recordId, props.owner, effectiveRepresentation];
+ return {
+ id,
+ version,
+ parentVersion: record.version as number,
+ status,
+ context: JSON.stringify(context),
+ weightsHash:
+ typeof match?.weights_hash === 'string' ? match.weights_hash : '',
+ criteria,
+ owner: props.owner,
+ canSubmit:
+ !!actorId &&
+ !props.owner &&
+ props.acceptingInterests &&
+ (entry
+ ? entry.can_edit === true &&
+ ['submitted', 'clarification', 'withdrawn'].includes(status)
+ : props.canStartInterest === true),
+ canDecide: props.owner && props.canEdit && !!entry,
+ canWithdraw: !!entry && entry.can_edit === true,
+ values,
+ commands,
+ };
+}
+const same = (a: Values, b: Values) =>
+ [...new Set([...Object.keys(a), ...Object.keys(b)])].every(
+ (key) => a[key] === b[key],
+ );
+function normal(values: Values): Values {
+ return Object.fromEntries(
+ Object.entries(values).map(([key, value]) => [
+ key,
+ key.startsWith('criterion:')
+ ? pack(
+ criterionValue(value).state,
+ criterionValue(value).evidence.trim(),
+ )
+ : value.trim(),
+ ]),
+ );
+}
+type Pending = {
+ command: Record;
+ values: Values;
+ generations: Record;
+ action: string;
+ base: Snapshot;
+ ambiguous: boolean;
+};
+export function useCandidacyEdit({
+ props,
+ recordId,
+ interestId = null,
+ mode,
+ actorId,
+}: {
+ props: unknown;
+ recordId: number;
+ interestId?: number | null;
+ mode: 'submission' | 'decision';
+ actorId: number | null;
+}) {
+ const [resolved, setResolved] = useState(interestId);
+ const target = interestId ?? resolved;
+ const current = read(props, recordId, target, mode, actorId);
+ const initial = useRef(current);
+ const criterionLabels = useRef(
+ new Map(
+ (current?.criteria ?? []).map((criterion) => [
+ criterion.code,
+ criterion.label,
+ ]),
+ ),
+ );
+ for (const criterion of current?.criteria ?? [])
+ criterionLabels.current.set(criterion.code, criterion.label);
+ const identity = JSON.stringify([recordId, interestId, mode, actorId]);
+ const opened = useRef(identity);
+ const observed = useRef(identity);
+ observed.current = identity;
+ const empty: Values =
+ mode === 'submission'
+ ? {
+ organization_id: '',
+ proposal: '',
+ capacity: '',
+ availability: '',
+ contribution: '',
+ conflicts: '',
+ consent: 'no',
+ }
+ : { reason: '' };
+ const form = useForm<{ values: Values }>({
+ values: current?.values ?? empty,
+ });
+ const live = useRef(form.data.values);
+ live.current = form.data.values;
+ const edited = useRef(new Set()),
+ generations = useRef>({});
+ const pending = useRef(null);
+ const [choices, setChoices] = useState>(
+ {},
+ );
+ const [refreshing, setRefreshing] = useState(false),
+ [needsCompare, setNeedsCompare] = useState(false),
+ [problem, setProblem] = useState(null);
+ const base = initial.current;
+ const keys = [
+ ...new Set([
+ ...Object.keys(base?.values ?? empty),
+ ...Object.keys(current?.values ?? {}),
+ ]),
+ ];
+ const invalid =
+ !current ||
+ !base ||
+ opened.current !== observed.current ||
+ current.id !== base.id;
+ const stale =
+ !!current &&
+ !!base &&
+ (current.version !== base.version ||
+ current.context !== base.context ||
+ current.status !== base.status ||
+ !same(current.values, base.values));
+ const changed =
+ current && base
+ ? keys.filter((key) => current.values[key] !== base.values[key])
+ : [];
+ const conflicts = current
+ ? changed.filter(
+ (key) =>
+ Object.hasOwn(current.values, key) &&
+ edited.current.has(key) &&
+ live.current[key] !== current.values[key],
+ )
+ : [];
+ const choiceKey = (key: string) =>
+ JSON.stringify([
+ current?.id,
+ current?.version,
+ current?.context,
+ key,
+ current?.values[key],
+ ]);
+ const unresolved = conflicts.filter(
+ (key) => choices[choiceKey(key)] !== 'mine',
+ );
+ const active =
+ !!current &&
+ ['submitted', 'clarification', 'shortlisted'].includes(current.status);
+ const editable =
+ !!current &&
+ (mode === 'submission'
+ ? current.canSubmit
+ : active &&
+ (current.owner ? current.canDecide : current.canWithdraw));
+ const canRecover = (action: string) =>
+ !!current &&
+ (action === 'submit'
+ ? current.id === null
+ ? !!actorId && !current.owner
+ : current.canWithdraw
+ : action === 'withdraw'
+ ? current.canWithdraw
+ : current.canDecide);
+ const recovering = !!pending.current?.ambiguous;
+ const blocked =
+ invalid ||
+ refreshing ||
+ form.processing ||
+ (recovering && pending.current
+ ? !canRecover(pending.current.action)
+ : stale || needsCompare || !editable);
+ const dirty =
+ !!pending.current ||
+ (!!base &&
+ (!same(live.current, base.values) ||
+ keys.some(
+ (key) =>
+ edited.current.has(key) &&
+ current &&
+ live.current[key] !== current.values[key],
+ )));
+ const retired = Object.keys(live.current).filter(
+ (key) =>
+ key.startsWith('criterion:') &&
+ !current?.criteria.some(
+ (criterion) => 'criterion:' + criterion.code === key,
+ ),
+ );
+ useEffect(() => {
+ if (
+ !current ||
+ invalid ||
+ !stale ||
+ dirty ||
+ edited.current.size > 0 ||
+ pending.current ||
+ form.processing ||
+ needsCompare
+ )
+ return;
+ initial.current = current;
+ live.current = { ...current.values };
+ form.setDefaults({ values: live.current });
+ form.setData({ values: live.current });
+ }, [current, invalid, stale, dirty, form.processing, needsCompare]);
+ function change(key: string, value: string) {
+ if (!keys.includes(key)) return;
+ edited.current.add(key);
+ generations.current[key] = (generations.current[key] ?? 0) + 1;
+ live.current = { ...live.current, [key]: value };
+ form.setData({ values: live.current });
+ setChoices((previous) => {
+ const next = { ...previous };
+ delete next[choiceKey(key)];
+ return next;
+ });
+ }
+ function changeCriterion(
+ code: string,
+ field: 'state' | 'evidence',
+ value: string,
+ ) {
+ const key = 'criterion:' + code,
+ data = criterionValue(live.current[key]);
+ change(key, JSON.stringify({ ...data, [field]: value }));
+ }
+ function discardRetired() {
+ if (form.processing || pending.current) return;
+ const values = { ...live.current };
+ for (const key of retired) {
+ delete values[key];
+ edited.current.delete(key);
+ }
+ live.current = values;
+ form.setData({ values });
+ }
+ function choose(key: string, value: 'mine' | 'current') {
+ if (!current) return;
+ if (value === 'current') change(key, current.values[key] ?? '');
+ setChoices((previous) => ({ ...previous, [choiceKey(key)]: value }));
+ }
+ function adopt() {
+ if (
+ !current ||
+ invalid ||
+ !stale ||
+ unresolved.length ||
+ refreshing ||
+ form.processing
+ )
+ return;
+ const values = { ...current.values };
+ for (const key of Object.keys(live.current))
+ if (edited.current.has(key)) values[key] = live.current[key];
+ initial.current = current;
+ live.current = values;
+ pending.current = null;
+ form.setDefaults({ values: current.values });
+ form.setData({ values });
+ form.clearErrors();
+ setChoices({});
+ setNeedsCompare(false);
+ setProblem(null);
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: [
+ 'record',
+ 'interests',
+ 'owner',
+ 'canEdit',
+ 'moderator',
+ 'publicationActions',
+ 'publicationCommands',
+ 'historySummary',
+ 'acceptingInterests',
+ 'organizations',
+ ],
+ onSuccess: (page) => {
+ const fresh = read(page.props, recordId, target, mode, actorId);
+ if (
+ fresh &&
+ initial.current &&
+ fresh.id === initial.current.id &&
+ fresh.version === initial.current.version &&
+ fresh.context === initial.current.context &&
+ fresh.status === initial.current.status &&
+ same(fresh.values, initial.current.values)
+ ) {
+ setNeedsCompare(false);
+ setProblem(null);
+ }
+ },
+ onHttpException: () => {
+ setProblem(
+ 'Não foi possível recuperar esta candidatura com o acesso actual. A preparação foi conservada.',
+ );
+ return false;
+ },
+ onNetworkError: () => {
+ setProblem(
+ 'A recuperação não foi confirmada. A preparação foi conservada.',
+ );
+ return false;
+ },
+ onFinish: () => setRefreshing(false),
+ });
+ }
+ function submit(
+ requestedAction = mode === 'submission' ? 'submit' : 'assess',
+ ) {
+ if (blocked || !current || !base) return;
+ const action = pending.current?.action ?? requestedAction;
+ if (!recovering) {
+ if (
+ mode === 'decision' &&
+ (action === 'withdraw'
+ ? !current.canWithdraw
+ : !current.canDecide)
+ )
+ return;
+ if (action === 'connect' && current.status !== 'shortlisted')
+ return;
+ }
+ let operation = pending.current;
+ if (!operation) {
+ const values = { ...live.current };
+ const command: Record =
+ mode === 'submission'
+ ? {
+ interest_id: target,
+ version: current.version,
+ partnership_version: current.parentVersion,
+ organization_id: values.organization_id,
+ proposal: values.proposal,
+ payload: {
+ capacity: values.capacity,
+ availability: values.availability,
+ contribution: values.contribution,
+ conflicts: values.conflicts,
+ consent: values.consent === 'yes',
+ },
+ }
+ : {
+ version: current.version,
+ action,
+ reason: values.reason,
+ assessment:
+ action === 'assess'
+ ? Object.fromEntries(
+ current.criteria.map((criterion) => [
+ criterion.code,
+ criterionValue(
+ values[
+ 'criterion:' +
+ criterion.code
+ ],
+ ),
+ ]),
+ )
+ : {},
+ ...(action === 'withdraw'
+ ? {}
+ : {
+ partnership_version: current.parentVersion,
+ weights_hash: current.weightsHash,
+ }),
+ };
+ command.client_key = createOperationKey();
+ operation = {
+ command,
+ values,
+ generations: { ...generations.current },
+ base: current,
+ action,
+ ambiguous: false,
+ };
+ pending.current = operation;
+ }
+ const sent = operation;
+ setProblem(null);
+ form.transform(() => sent.command);
+ const unknown = () => {
+ if (pending.current) pending.current.ambiguous = true;
+ setProblem(
+ 'A operação não foi confirmada. Recuperar repete o pedido original; as alterações posteriores foram conservadas.',
+ );
+ return false;
+ };
+ form.post(
+ mode === 'submission'
+ ? `/parcerias/${recordId}/interesses`
+ : `/parcerias/candidaturas/${target}`,
+ {
+ preserveScroll: true,
+ onSuccess: (page) => {
+ if (observed.current !== opened.current) return;
+ const saved = read(
+ page.props,
+ recordId,
+ target,
+ mode,
+ actorId,
+ String(sent.command.client_key),
+ sent.action,
+ );
+ const acknowledgement = saved?.commands.find(
+ (command) =>
+ command.key === sent.command.client_key &&
+ command.action === sent.action,
+ );
+ if (!saved || saved.id === null || !acknowledgement) {
+ unknown();
+ return;
+ }
+ const acknowledgedKeys =
+ mode === 'decision' && sent.action === 'assess'
+ ? [
+ 'reason',
+ ...sent.base.criteria.map(
+ (criterion) =>
+ 'criterion:' + criterion.code,
+ ),
+ ]
+ : null;
+ const submittedValues = acknowledgedKeys
+ ? Object.fromEntries(
+ acknowledgedKeys.map((key) => [
+ key,
+ sent.values[key],
+ ]),
+ )
+ : mode === 'submission'
+ ? sent.values
+ : sent.base.values;
+ const expected = normal(submittedValues);
+ if (mode === 'decision') expected.reason = '';
+ const actualExpectedVersion =
+ sent.base.version === null ? 1 : sent.base.version + 1;
+ if (
+ acknowledgement.version !== actualExpectedVersion ||
+ (target !== null && saved.id !== target)
+ ) {
+ unknown();
+ return;
+ }
+ const exact =
+ saved.version === acknowledgement.version &&
+ saved.context === sent.base.context &&
+ same(saved.values, expected);
+ const merged = { ...expected };
+ const oldEdited = new Set(edited.current);
+ edited.current.clear();
+ for (const key of Object.keys(live.current)) {
+ const sentCriterion =
+ !key.startsWith('criterion:') ||
+ sent.base.criteria.some(
+ (criterion) =>
+ 'criterion:' + criterion.code === key,
+ );
+ if (
+ (generations.current[key] ?? 0) !==
+ (sent.generations[key] ?? 0) ||
+ (mode === 'decision' &&
+ (sent.action !== 'assess' || !sentCriterion) &&
+ key !== 'reason' &&
+ oldEdited.has(key))
+ ) {
+ merged[key] = live.current[key];
+ edited.current.add(key);
+ }
+ }
+ initial.current = exact
+ ? saved
+ : {
+ ...saved,
+ version: acknowledgement.version,
+ context: sent.base.context,
+ parentVersion: sent.base.parentVersion,
+ values: expected,
+ };
+ if (target === null) setResolved(saved.id);
+ pending.current = null;
+ live.current = merged;
+ form.setDefaults({ values: expected });
+ form.setData({ values: merged });
+ form.clearErrors();
+ setChoices({});
+ setNeedsCompare(!exact);
+ setProblem(
+ exact
+ ? null
+ : 'A operação original foi identificada, mas a candidatura ou o contexto tem dados posteriores. Compare antes de continuar; a preparação foi conservada.',
+ );
+ },
+ onError: () => {
+ if (!pending.current?.ambiguous) pending.current = null;
+ },
+ onHttpException: (response) => {
+ if (
+ response.status >= 500 ||
+ response.status === 409 ||
+ pending.current?.ambiguous
+ ) {
+ if (response.status === 409) setNeedsCompare(true);
+ return unknown();
+ }
+ pending.current = null;
+ setProblem(
+ 'Não foi possível confirmar esta operação com o acesso actual. A preparação foi conservada.',
+ );
+ return false;
+ },
+ onNetworkError: unknown,
+ onCancel: unknown,
+ },
+ );
+ }
+ return {
+ form,
+ values: form.data.values,
+ current: current?.values ?? empty,
+ currentSnapshot: current,
+ criteria: current?.criteria ?? base?.criteria ?? [],
+ criterionLabels: Object.fromEntries(criterionLabels.current),
+ retired,
+ activeId: target,
+ editable,
+ ownerMode: current?.owner ?? base?.owner ?? false,
+ status: current?.status,
+ version: current?.version,
+ baseVersion: base?.version,
+ stale,
+ invalid,
+ changed,
+ conflicts,
+ unresolved,
+ refreshing,
+ blocked,
+ dirty,
+ problem,
+ recovering,
+ pendingAction: pending.current?.action,
+ change,
+ changeCriterion,
+ discardRetired,
+ choose,
+ adopt,
+ refresh,
+ submit,
+ };
+}
+export type CandidacyEditor = ReturnType;
+export function useCandidacyLeaveGuard(dirty: boolean) {
+ const current = useRef(dirty);
+ current.current = dirty;
+ useEffect(() => {
+ const leave = (event: BeforeUnloadEvent) => {
+ if (current.current) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ const stop = router.on('before', (event) => {
+ if (
+ current.current &&
+ event.detail.visit.method === 'get' &&
+ event.detail.visit.preserveState !== true &&
+ !window.confirm(
+ 'Há preparação ou acções por confirmar nesta parceria. Pretende sair sem as conservar?',
+ )
+ )
+ event.preventDefault();
+ });
+ window.addEventListener('beforeunload', leave);
+ return () => {
+ stop();
+ window.removeEventListener('beforeunload', leave);
+ };
+ }, []);
+}
diff --git a/resources/js/lib/partnership-edit.ts b/resources/js/lib/partnership-edit.ts
new file mode 100644
index 00000000..a8a8bb3a
--- /dev/null
+++ b/resources/js/lib/partnership-edit.ts
@@ -0,0 +1,862 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from '@/lib/operation-key';
+import type { Partnership } from '@/pages/partnerships/shared';
+
+export type PartnershipLocation = {
+ geo_location_id: string;
+ role: string;
+ source_reference: string;
+};
+export type PartnershipOrigin = { type: string; target_id: string };
+export type PartnershipEditProps = {
+ editorActorId?: number;
+ saveCommands?: { key: string; version: number }[];
+ record: Partnership | null;
+ locations: PartnershipLocation[];
+ origins: PartnershipOrigin[];
+};
+type Payload = {
+ summary: string;
+ requirements: string;
+ mandatory: string[];
+ confidentiality: string;
+ consent: boolean;
+ availability: string;
+};
+type Sections = Payload & {
+ title: string;
+ offer: string;
+ seeking: string;
+ organization_id: string;
+ sector_id: string;
+ kind: string;
+ partnership_type: string;
+ deadline: string;
+ locations: PartnershipLocation[];
+ origins: PartnershipOrigin[];
+};
+type Draft = Omit & {
+ payload: Payload;
+ client_key: string;
+ version: number | null;
+};
+type Snapshot = {
+ actorId: number | null;
+ commands: { key: string; version: number }[];
+ id: number | null;
+ version: number | null;
+ status: string;
+ clientKey: string | null;
+ values: Sections;
+};
+const textKeys = [
+ 'title',
+ 'offer',
+ 'seeking',
+ 'organization_id',
+ 'sector_id',
+ 'kind',
+ 'partnership_type',
+ 'deadline',
+ 'summary',
+ 'requirements',
+ 'confidentiality',
+ 'availability',
+] as const;
+const keys = [
+ ...textKeys,
+ 'mandatory',
+ 'consent',
+ 'locations',
+ 'origins',
+] as const;
+export type PartnershipSection = (typeof keys)[number];
+const editableStates = ['draft', 'returned', 'rejected', 'published'];
+function object(value: unknown): value is Record {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+function text(value: unknown, fallback = '') {
+ return value == null
+ ? fallback
+ : typeof value === 'string'
+ ? value
+ : undefined;
+}
+function bool(value: unknown) {
+ return value == null
+ ? false
+ : value === true || value === 1 || value === '1'
+ ? true
+ : value === false || value === 0 || value === '0'
+ ? false
+ : undefined;
+}
+function location(value: unknown): value is PartnershipLocation {
+ return (
+ object(value) &&
+ typeof value.geo_location_id === 'string' &&
+ typeof value.role === 'string' &&
+ typeof value.source_reference === 'string'
+ );
+}
+function origin(value: unknown): value is PartnershipOrigin {
+ return (
+ object(value) &&
+ typeof value.type === 'string' &&
+ typeof value.target_id === 'string'
+ );
+}
+function validSections(value: unknown): value is Sections {
+ return (
+ object(value) &&
+ textKeys.every((key) => typeof value[key] === 'string') &&
+ typeof value.consent === 'boolean' &&
+ Array.isArray(value.mandatory) &&
+ value.mandatory.every((item) => typeof item === 'string') &&
+ Array.isArray(value.locations) &&
+ value.locations.every(location) &&
+ Array.isArray(value.origins) &&
+ value.origins.every(origin)
+ );
+}
+function readSnapshot(props: unknown): Snapshot | null {
+ if (
+ !object(props) ||
+ !Array.isArray(props.locations) ||
+ !Array.isArray(props.origins)
+ )
+ return null;
+ if (
+ props.editorActorId !== undefined &&
+ (typeof props.editorActorId !== 'number' ||
+ !Number.isSafeInteger(props.editorActorId) ||
+ props.editorActorId < 1)
+ )
+ return null;
+ if (
+ props.saveCommands !== undefined &&
+ (!Array.isArray(props.saveCommands) ||
+ !props.saveCommands.every(
+ (value) =>
+ object(value) &&
+ typeof value.key === 'string' &&
+ typeof value.version === 'number' &&
+ Number.isSafeInteger(value.version) &&
+ value.version > 0,
+ ))
+ )
+ return null;
+ const record = props.record;
+ if (
+ record !== null &&
+ (!object(record) ||
+ !Number.isSafeInteger(record.id) ||
+ typeof record.id !== 'number' ||
+ record.id < 1 ||
+ !Number.isSafeInteger(record.version) ||
+ typeof record.version !== 'number' ||
+ record.version < 1 ||
+ typeof record.status !== 'string' ||
+ (!object(record.payload) &&
+ !(
+ Array.isArray(record.payload) && record.payload.length === 0
+ )))
+ )
+ return null;
+ const row = object(record) ? record : {};
+ const payload = object(row.payload) ? row.payload : {};
+ const values = {
+ title: text(row.title),
+ offer: text(row.offer),
+ seeking: text(row.seeking),
+ organization_id: text(row.organization_id),
+ sector_id:
+ row.sector_id == null
+ ? ''
+ : typeof row.sector_id === 'number'
+ ? String(row.sector_id)
+ : undefined,
+ kind: text(row.kind, 'seeking'),
+ partnership_type: text(row.partnership_type),
+ deadline: text(row.deadline),
+ summary: text(payload.summary),
+ requirements: text(payload.requirements),
+ mandatory: payload.mandatory ?? [],
+ confidentiality: text(payload.confidentiality, 'public'),
+ consent: bool(payload.consent),
+ availability: text(payload.availability),
+ locations: props.locations.map((item) =>
+ object(item)
+ ? {
+ geo_location_id: item.geo_location_id,
+ role: item.role,
+ source_reference: text(item.source_reference),
+ }
+ : null,
+ ),
+ origins: props.origins.map((item) =>
+ object(item)
+ ? { type: item.type, target_id: item.target_id }
+ : null,
+ ),
+ };
+ if (!validSections(values)) return null;
+ return {
+ actorId:
+ typeof props.editorActorId === 'number'
+ ? props.editorActorId
+ : null,
+ commands: Array.isArray(props.saveCommands)
+ ? props.saveCommands.map((value) => ({
+ key: value.key,
+ version: value.version,
+ }))
+ : [],
+ id: typeof row.id === 'number' ? row.id : null,
+ version: typeof row.version === 'number' ? row.version : null,
+ status: typeof row.status === 'string' ? row.status : 'draft',
+ clientKey: typeof row.client_key === 'string' ? row.client_key : null,
+ values,
+ };
+}
+function toDraft(
+ values: Sections,
+ client_key: string,
+ version: number | null,
+): Draft {
+ const {
+ summary,
+ requirements,
+ mandatory,
+ confidentiality,
+ consent,
+ availability,
+ ...fields
+ } = values;
+ return {
+ ...fields,
+ client_key,
+ version,
+ payload: {
+ summary,
+ requirements,
+ mandatory,
+ confidentiality,
+ consent,
+ availability,
+ },
+ };
+}
+function sections({
+ payload,
+ client_key: _key,
+ version: _version,
+ ...fields
+}: Draft): Sections {
+ return { ...fields, ...payload };
+}
+function canonical(value: Sections[PartnershipSection]) {
+ return JSON.stringify(
+ Array.isArray(value)
+ ? value.map((item) => JSON.stringify(item)).sort()
+ : value,
+ );
+}
+function equal(
+ a: Sections[PartnershipSection],
+ b: Sections[PartnershipSection],
+) {
+ return canonical(a) === canonical(b);
+}
+function same(a: Sections, b: Sections) {
+ return keys.every((key) => equal(a[key], b[key]));
+}
+function normalised(values: Sections): Sections {
+ const result = { ...values };
+ for (const key of textKeys) result[key] = result[key].trim();
+ return {
+ ...result,
+ locations: result.locations.map((item) => ({
+ geo_location_id: item.geo_location_id.trim(),
+ role: item.role.trim(),
+ source_reference: item.source_reference.trim(),
+ })),
+ origins: result.origins.map((item) => ({
+ type: item.type.trim(),
+ target_id: item.target_id.trim(),
+ })),
+ };
+}
+const empty = readSnapshot({ record: null, locations: [], origins: [] });
+if (!empty) throw new Error('Empty partnership editor definition is invalid.');
+const emptyValues = empty.values;
+export function usePartnershipEdit(props: PartnershipEditProps) {
+ const alive = useRef(true);
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ const current = readSnapshot(props);
+ const operationKey = useRef(createOperationKey());
+ const form = useForm(
+ toDraft(
+ current?.values ?? emptyValues,
+ operationKey.current,
+ current?.version ?? null,
+ ),
+ );
+ const base = useRef(current);
+ const live = useRef(form.data);
+ live.current = form.data;
+ const identity = useRef(current?.id ?? null);
+ identity.current = current?.id ?? null;
+ const edited = useRef(new Set());
+ const generation = useRef>>({});
+ const pendingCreation = useRef<{
+ command: Draft;
+ generation: Partial>;
+ ambiguous: boolean;
+ } | null>(null);
+ const createdId = useRef(null);
+ const pendingUpdate = useRef<{
+ id: number;
+ command: Draft & { operation_key: string };
+ generation: Partial>;
+ base: Snapshot;
+ ambiguous: boolean;
+ } | null>(null);
+ const [choices, setChoices] = useState>(
+ {},
+ );
+ const [refreshing, setRefreshing] = useState(false);
+ const [problem, setProblem] = useState(null);
+ const [needsCompare, setNeedsCompare] = useState(false);
+ const [mustRefresh, setMustRefresh] = useState(false),
+ [accessDenied, setAccessDenied] = useState(false);
+ const own = sections(form.data);
+ const invalid =
+ !current ||
+ !base.current ||
+ current.actorId !== base.current.actorId ||
+ (current.id !== base.current.id &&
+ !(
+ base.current.id === null &&
+ (current.id === createdId.current ||
+ current.clientKey ===
+ pendingCreation.current?.command.client_key)
+ ));
+ const stale =
+ !!current &&
+ !!base.current &&
+ (current.id !== base.current.id ||
+ current.version !== base.current.version ||
+ current.status !== base.current.status ||
+ !same(current.values, base.current.values));
+ const baseline = base.current;
+ const changed =
+ current && baseline
+ ? keys.filter(
+ (key) => !equal(current.values[key], baseline.values[key]),
+ )
+ : [];
+ const conflicts = current
+ ? changed.filter(
+ (key) =>
+ edited.current.has(key) &&
+ !equal(own[key], current.values[key]),
+ )
+ : [];
+ const choiceKey = (key: PartnershipSection) =>
+ JSON.stringify([
+ current?.id,
+ current?.version,
+ current?.status,
+ key,
+ current ? canonical(current.values[key]) : '',
+ ]);
+ const unresolved = conflicts.filter(
+ (key) => choices[choiceKey(key)] !== 'mine',
+ );
+ const editable = !!current && editableStates.includes(current.status);
+ const blocked =
+ invalid ||
+ stale ||
+ refreshing ||
+ needsCompare ||
+ accessDenied ||
+ !!pendingUpdate.current ||
+ !editable;
+ const dirty =
+ !!baseline &&
+ (!!pendingUpdate.current ||
+ !!pendingCreation.current ||
+ !same(own, baseline.values) ||
+ (!!current &&
+ keys.some(
+ (key) =>
+ edited.current.has(key) &&
+ !equal(own[key], current.values[key]),
+ )));
+ useEffect(() => {
+ const leave = (event: BeforeUnloadEvent) => {
+ if (dirty) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ const stop = router.on('before', (event) => {
+ if (
+ dirty &&
+ event.detail.visit.method === 'get' &&
+ event.detail.visit.preserveState !== true &&
+ !window.confirm(
+ 'Há alterações por guardar na parceria. Pretende sair sem as guardar?',
+ )
+ )
+ event.preventDefault();
+ });
+ window.addEventListener('beforeunload', leave);
+ return () => {
+ stop();
+ window.removeEventListener('beforeunload', leave);
+ };
+ }, [dirty]);
+ function replace(next: Draft) {
+ const previous = sections(live.current),
+ after = sections(next);
+ const changed = keys.filter((key) => !equal(previous[key], after[key]));
+ for (const key of changed) {
+ edited.current.add(key);
+ generation.current[key] = (generation.current[key] ?? 0) + 1;
+ }
+ live.current = next;
+ form.setData(() => next);
+ setChoices((previous) => {
+ const next = { ...previous };
+ for (const key of changed) delete next[choiceKey(key)];
+ return next;
+ });
+ }
+ function setData(
+ key: K,
+ value: Draft[K] | ((previous: Draft[K]) => Draft[K]),
+ ) {
+ const next =
+ typeof value === 'function' ? value(live.current[key]) : value;
+ replace({ ...live.current, [key]: next });
+ }
+ function choose(key: PartnershipSection, choice: 'mine' | 'current') {
+ if (!current) return;
+ if (choice === 'current')
+ replace(
+ toDraft(
+ { ...sections(live.current), [key]: current.values[key] },
+ live.current.client_key,
+ live.current.version,
+ ),
+ );
+ setChoices((previous) => ({ ...previous, [choiceKey(key)]: choice }));
+ }
+ function adopt() {
+ if (
+ !current ||
+ (!stale && !pendingUpdate.current?.ambiguous && !needsCompare) ||
+ invalid ||
+ refreshing ||
+ form.processing ||
+ unresolved.length
+ )
+ return;
+ if (mustRefresh) return;
+ const selected = { ...current.values };
+ for (const key of keys)
+ if (edited.current.has(key))
+ Object.assign(selected, { [key]: sections(live.current)[key] });
+ const saved = toDraft(
+ current.values,
+ current.clientKey ?? live.current.client_key,
+ current.version,
+ );
+ base.current = current;
+ createdId.current = null;
+ pendingCreation.current = null;
+ pendingUpdate.current = null;
+ form.setDefaults(saved);
+ live.current = toDraft(selected, saved.client_key, saved.version);
+ form.setData(live.current);
+ form.clearErrors();
+ setProblem(null);
+ setNeedsCompare(false);
+ setChoices({});
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: [
+ 'record',
+ 'locations',
+ 'origins',
+ 'editorActorId',
+ 'saveCommands',
+ ],
+ onSuccess: (page) => {
+ if (!alive.current) return;
+ if (
+ pendingUpdate.current &&
+ acknowledgeUpdate(page.props, pendingUpdate.current)
+ )
+ return;
+ const fresh = readSnapshot(page.props);
+ if (
+ !fresh ||
+ fresh.actorId !== base.current?.actorId ||
+ fresh.id !== base.current?.id
+ ) {
+ setProblem(
+ 'A resposta não corresponde a esta conta e parceria. A preparação foi conservada.',
+ );
+ return;
+ }
+ setMustRefresh(false);
+ setAccessDenied(false);
+ if (
+ fresh &&
+ base.current &&
+ fresh.id === base.current.id &&
+ fresh.version === base.current.version &&
+ fresh.status === base.current.status &&
+ same(fresh.values, base.current.values)
+ ) {
+ setNeedsCompare(false);
+ setProblem(null);
+ }
+ },
+ onHttpException: () => {
+ if (!alive.current) return false;
+ setAccessDenied(true);
+ setMustRefresh(true);
+ setProblem(
+ 'Não foi possível recuperar esta parceria com o acesso actual. As suas edições foram conservadas.',
+ );
+ return false;
+ },
+ onNetworkError: () => {
+ if (!alive.current) return false;
+ setProblem(
+ 'A recuperação não foi confirmada. As suas edições foram conservadas.',
+ );
+ return false;
+ },
+ onFinish: () => {
+ if (alive.current) setRefreshing(false);
+ },
+ });
+ }
+ function applySaved(
+ saved: Snapshot,
+ command: Draft,
+ sentGeneration: Partial>,
+ later = false,
+ ) {
+ const merged = { ...saved.values };
+ edited.current.clear();
+ for (const key of keys)
+ if ((generation.current[key] ?? 0) !== (sentGeneration[key] ?? 0)) {
+ Object.assign(merged, { [key]: sections(live.current)[key] });
+ edited.current.add(key);
+ }
+ base.current = saved;
+ createdId.current = null;
+ pendingCreation.current = null;
+ pendingUpdate.current = null;
+ const defaults = toDraft(
+ saved.values,
+ saved.clientKey ?? command.client_key,
+ saved.version,
+ );
+ form.setDefaults(defaults);
+ live.current = toDraft(merged, defaults.client_key, defaults.version);
+ form.setData(live.current);
+ form.clearErrors();
+ setChoices({});
+ setMustRefresh(false);
+ setAccessDenied(false);
+ setNeedsCompare(later);
+ setProblem(
+ later
+ ? 'A gravação foi reconhecida. Existem alterações posteriores; compare antes de voltar a guardar.'
+ : null,
+ );
+ }
+ function acknowledgeUpdate(
+ pageProps: unknown,
+ sent: NonNullable,
+ ): boolean {
+ if (
+ !alive.current ||
+ pendingUpdate.current !== sent ||
+ identity.current !== sent.id
+ )
+ return false;
+ const saved = readSnapshot(pageProps),
+ expectedVersion = (sent.base.version ?? 0) + 1;
+ if (
+ !saved ||
+ saved.id !== sent.id ||
+ saved.actorId !== sent.base.actorId ||
+ !saved.commands.some(
+ (command) =>
+ command.key === sent.command.operation_key &&
+ command.version === expectedVersion,
+ ) ||
+ saved.version === null ||
+ saved.version < expectedVersion
+ )
+ return false;
+ const expected = normalised(sections(sent.command));
+ if (saved.version === expectedVersion) {
+ if (saved.status !== 'draft' || !same(saved.values, expected))
+ return false;
+ applySaved(saved, sent.command, sent.generation);
+ return true;
+ }
+ applySaved(
+ {
+ ...sent.base,
+ version: expectedVersion,
+ status: 'draft',
+ values: expected,
+ commands: saved.commands,
+ },
+ sent.command,
+ sent.generation,
+ true,
+ );
+ return true;
+ }
+ function save(recover = false) {
+ if (
+ !alive.current ||
+ form.processing ||
+ refreshing ||
+ invalid ||
+ accessDenied ||
+ (!recover && blocked)
+ )
+ return;
+ const update = recover ? pendingUpdate.current : null;
+ if (recover && (!update?.ambiguous || current?.id !== update.id))
+ return;
+ const submittedId = update?.id ?? base.current?.id ?? null;
+ const pending = submittedId === null ? pendingCreation.current : null;
+ const command =
+ update?.command ??
+ pending?.command ??
+ structuredClone(live.current);
+ const sentGeneration = update?.generation ??
+ pending?.generation ?? { ...generation.current };
+ if (submittedId !== null && !update && base.current)
+ pendingUpdate.current = {
+ id: submittedId,
+ command: { ...command, operation_key: createOperationKey() },
+ generation: sentGeneration,
+ base: base.current,
+ ambiguous: false,
+ };
+ const submittedUpdate = pendingUpdate.current;
+ if (submittedId === null && !pending)
+ pendingCreation.current = {
+ command,
+ generation: sentGeneration,
+ ambiguous: false,
+ };
+ setProblem(null);
+ form.transform(() => submittedUpdate?.command ?? command);
+ const options = {
+ preserveScroll: true,
+ onSuccess: (page: { props: Record }) => {
+ if (!alive.current) return;
+ if (submittedUpdate) {
+ if (
+ !acknowledgeUpdate(page.props, submittedUpdate) &&
+ pendingUpdate.current === submittedUpdate
+ ) {
+ submittedUpdate.ambiguous = true;
+ setMustRefresh(true);
+ setNeedsCompare(true);
+ setProblem(
+ 'A resposta não confirmou esta gravação. A preparação foi conservada; recupere a mesma tentativa ou compare os dados actuais.',
+ );
+ }
+ return;
+ }
+ const saved = readSnapshot(page.props);
+ if (
+ !saved ||
+ saved.id === null ||
+ (submittedId !== null
+ ? saved.id !== submittedId ||
+ identity.current !== submittedId
+ : saved.clientKey !== command.client_key ||
+ (identity.current !== null &&
+ identity.current !== saved.id))
+ ) {
+ setProblem(
+ 'A gravação não foi reconciliada com este formulário. Compare os dados antes de continuar.',
+ );
+ setNeedsCompare(true);
+ return;
+ }
+ if (submittedId === null) createdId.current = saved.id;
+ pendingCreation.current = null;
+ if (
+ saved.status !== 'draft' ||
+ !same(saved.values, normalised(sections(command)))
+ ) {
+ setProblem(
+ 'A resposta contém uma versão com dados diferentes do que enviou. Compare antes de voltar a guardar; as suas edições foram conservadas.',
+ );
+ setNeedsCompare(true);
+ return;
+ }
+ applySaved(saved, command, sentGeneration);
+ },
+ onError: () => {
+ if (!alive.current) return;
+ if (
+ submittedUpdate &&
+ pendingUpdate.current === submittedUpdate
+ )
+ pendingUpdate.current = null;
+ if (!pendingCreation.current?.ambiguous)
+ pendingCreation.current = null;
+ },
+ onHttpException: (response: { status: number }) => {
+ if (!alive.current) return false;
+ if (submittedUpdate) {
+ if (pendingUpdate.current !== submittedUpdate) return false;
+ if (
+ response.status >= 500 ||
+ [401, 403, 404, 419].includes(response.status)
+ )
+ submittedUpdate.ambiguous = true;
+ else pendingUpdate.current = null;
+ setMustRefresh(true);
+ setNeedsCompare(true);
+ setAccessDenied(
+ [401, 403, 404, 419].includes(response.status),
+ );
+ setProblem(
+ 'A gravação não foi confirmada com os dados e acesso actuais. Compare antes de continuar; as edições foram conservadas.',
+ );
+ return false;
+ }
+ if (submittedId !== null && response.status === 409) {
+ setNeedsCompare(true);
+ setProblem(
+ 'A parceria foi alterada ou mudou de estado. Compare com os dados actuais antes de guardar; as suas edições foram conservadas.',
+ );
+ } else {
+ setProblem(
+ response.status === 403
+ ? 'Não foi possível confirmar a operação com o acesso actual. As suas edições foram conservadas.'
+ : 'A gravação não foi confirmada. As suas edições foram conservadas.',
+ );
+ if (submittedId !== null)
+ setNeedsCompare(response.status >= 500);
+ }
+ if (pendingCreation.current) {
+ if (
+ response.status >= 500 ||
+ response.status === 409 ||
+ pendingCreation.current.ambiguous
+ )
+ pendingCreation.current.ambiguous = true;
+ else pendingCreation.current = null;
+ }
+ return false;
+ },
+ onNetworkError: () => {
+ if (!alive.current) return false;
+ if (
+ submittedUpdate &&
+ pendingUpdate.current !== submittedUpdate
+ )
+ return false;
+ if (
+ submittedUpdate &&
+ pendingUpdate.current === submittedUpdate
+ ) {
+ submittedUpdate.ambiguous = true;
+ setMustRefresh(true);
+ }
+ setProblem(
+ 'A gravação não foi confirmada. As suas edições foram conservadas.',
+ );
+ if (pendingCreation.current)
+ pendingCreation.current.ambiguous = true;
+ else setNeedsCompare(true);
+ return false;
+ },
+ onCancel: () => {
+ if (!alive.current) return;
+ if (
+ submittedUpdate &&
+ pendingUpdate.current !== submittedUpdate
+ )
+ return;
+ if (
+ submittedUpdate &&
+ pendingUpdate.current === submittedUpdate
+ ) {
+ submittedUpdate.ambiguous = true;
+ setMustRefresh(true);
+ }
+ if (pendingCreation.current)
+ pendingCreation.current.ambiguous = true;
+ else setNeedsCompare(true);
+ setProblem(
+ 'A gravação foi interrompida; conserve a edição e recupere os dados antes de continuar.',
+ );
+ },
+ };
+ if (submittedId === null) form.post('/parcerias/rascunhos', options);
+ else form.put(`/parcerias/${submittedId}`, options);
+ }
+ return {
+ form,
+ setData,
+ save,
+ refresh,
+ adopt,
+ choose,
+ problem,
+ current,
+ values: own,
+ changed,
+ conflicts,
+ unresolved,
+ stale,
+ invalid,
+ refreshing,
+ editable,
+ blocked,
+ dirty,
+ retryingCreation: !!pendingCreation.current?.ambiguous,
+ retryingSave: !!pendingUpdate.current?.ambiguous,
+ canRecoverSave:
+ !!pendingUpdate.current?.ambiguous &&
+ !invalid &&
+ !accessDenied &&
+ !refreshing &&
+ !form.processing,
+ recoverSave: () => save(true),
+ mustRefresh,
+ baseVersion: base.current?.version ?? null,
+ };
+}
+export type PartnershipEditor = ReturnType;
diff --git a/resources/js/lib/partnership-history.ts b/resources/js/lib/partnership-history.ts
new file mode 100644
index 00000000..bc87272c
--- /dev/null
+++ b/resources/js/lib/partnership-history.ts
@@ -0,0 +1,26 @@
+export const publicationHistoryActions: Record = {
+ create: 'Criação do rascunho',
+ edit: 'Edição do rascunho',
+ submit: 'Submissão para moderação',
+ publish: 'Publicação',
+ return: 'Devolução para correcção',
+ reject: 'Rejeição',
+ suspend: 'Suspensão',
+ archive: 'Arquivo',
+ renew: 'Renovação em rascunho',
+};
+export type PublicationHistorySummary = {
+ limit: number;
+ has_more: boolean;
+ href: string;
+ entries: {
+ version: number | null;
+ restricted: boolean;
+ action: string | null;
+ actor_name: string | null;
+ occurred_at: string | null;
+ reason: string | null;
+ status_before: string | null;
+ status_after: string | null;
+ }[];
+};
diff --git a/resources/js/lib/partnership-publication.ts b/resources/js/lib/partnership-publication.ts
new file mode 100644
index 00000000..b4083732
--- /dev/null
+++ b/resources/js/lib/partnership-publication.ts
@@ -0,0 +1,465 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+import type { Partnership } from '@/pages/partnerships/shared';
+
+export type PublicationProps = {
+ record: Partnership;
+ owner: boolean;
+ canEdit: boolean;
+ moderator: boolean;
+ publicationActions: string[];
+ publicationCommands: { key: string; action: string; version: number }[];
+ origins: unknown[];
+ locations: unknown[];
+};
+type Snapshot = {
+ id: number;
+ version: number;
+ status: string;
+ context: string;
+ values: Record;
+ actions: string[];
+ canEdit: boolean;
+ moderator: boolean;
+ commands: PublicationProps['publicationCommands'];
+};
+const states: Record = {
+ submit: 'submitted',
+ publish: 'published',
+ return: 'returned',
+ reject: 'rejected',
+ suspend: 'suspended',
+ archive: 'archived',
+ renew: 'draft',
+};
+const object = (value: unknown): value is Record =>
+ !!value && typeof value === 'object' && !Array.isArray(value);
+const positive = (value: unknown): value is number =>
+ typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
+function scalar(value: unknown): string | null {
+ return value == null
+ ? ''
+ : typeof value === 'string' ||
+ typeof value === 'number' ||
+ typeof value === 'boolean'
+ ? String(value)
+ : null;
+}
+function canonical(value: unknown): unknown {
+ return Array.isArray(value)
+ ? value.map(canonical)
+ : object(value)
+ ? Object.fromEntries(
+ Object.keys(value)
+ .sort()
+ .map((key) => [key, canonical(value[key])]),
+ )
+ : value;
+}
+function read(props: unknown, id: number): Snapshot | null {
+ if (
+ !object(props) ||
+ !object(props.record) ||
+ props.record.id !== id ||
+ !positive(props.record.version) ||
+ typeof props.record.status !== 'string' ||
+ typeof props.canEdit !== 'boolean' ||
+ typeof props.moderator !== 'boolean' ||
+ !Array.isArray(props.publicationActions) ||
+ !props.publicationActions.every(
+ (value) =>
+ typeof value === 'string' && Object.hasOwn(states, value),
+ ) ||
+ !Array.isArray(props.publicationCommands) ||
+ !props.publicationCommands.every(
+ (value) =>
+ object(value) &&
+ typeof value.key === 'string' &&
+ typeof value.action === 'string' &&
+ Object.hasOwn(states, value.action) &&
+ positive(value.version),
+ ) ||
+ !Array.isArray(props.origins) ||
+ !Array.isArray(props.locations)
+ )
+ return null;
+ const payload = object(props.record.payload)
+ ? props.record.payload
+ : Array.isArray(props.record.payload) &&
+ props.record.payload.length === 0
+ ? {}
+ : null;
+ if (!payload) return null;
+ const { version, status, ...content } = props.record;
+ const values: Record = {};
+ for (const key of [
+ 'title',
+ 'offer',
+ 'seeking',
+ 'kind',
+ 'partnership_type',
+ 'sector_id',
+ 'organization_id',
+ 'deadline',
+ ]) {
+ const value = scalar(props.record[key]);
+ if (value === null) return null;
+ values[key] = value;
+ }
+ for (const key of [
+ 'summary',
+ 'requirements',
+ 'confidentiality',
+ 'availability',
+ 'consent',
+ 'mandatory',
+ ]) {
+ const item = payload[key];
+ const value =
+ key === 'mandatory' &&
+ Array.isArray(item) &&
+ item.every((entry) => typeof entry === 'string')
+ ? item.join(', ')
+ : scalar(item);
+ if (value === null) return null;
+ values[key] = value;
+ }
+ values.origins = props.origins
+ .map((value) =>
+ object(value)
+ ? (scalar(value.title ?? value.type) ??
+ 'Origem indisponível para comparação')
+ : '',
+ )
+ .join('\n');
+ values.locations = props.locations
+ .map((value) =>
+ object(value)
+ ? `${scalar(value.name ?? value.id) ?? 'Localização indisponível'} · ${scalar(value.role) ?? 'Papel indisponível'} · ${scalar(value.source_reference) ?? 'Fonte indisponível'}`
+ : '',
+ )
+ .join('\n');
+ return {
+ id,
+ version,
+ status,
+ context: JSON.stringify(
+ canonical([content, props.origins, props.locations]),
+ ),
+ values,
+ actions: props.publicationActions,
+ commands:
+ props.publicationCommands as PublicationProps['publicationCommands'],
+ canEdit: props.canEdit,
+ moderator: props.moderator,
+ };
+}
+type Pending = {
+ command: {
+ client_key: string;
+ version: number;
+ action: string;
+ reason: string;
+ };
+ generation: number;
+ base: Snapshot;
+ ambiguous: boolean;
+};
+export function usePublication(p: PublicationProps, actorId: number) {
+ const alive = useRef(true);
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ const id = p.record.id,
+ current = read(p, id),
+ identity = `${id}:${actorId}`;
+ const opened = useRef(identity),
+ observed = useRef(identity);
+ observed.current = identity;
+ const base = useRef(current),
+ pending = useRef(null),
+ generation = useRef(0);
+ const form = useForm({ reason: '' });
+ const live = useRef(form.data.reason);
+ live.current = form.data.reason;
+ const [problem, setProblem] = useState(null),
+ [needsCompare, setNeedsCompare] = useState(false),
+ [refreshing, setRefreshing] = useState(false),
+ [mustRefresh, setMustRefresh] = useState(false),
+ [, render] = useState(0);
+ const invalid =
+ !current || !base.current || opened.current !== observed.current;
+ const stale =
+ !!current &&
+ !!base.current &&
+ (current.version !== base.current.version ||
+ current.status !== base.current.status ||
+ current.context !== base.current.context);
+ const dirty = !!live.current || !!pending.current;
+ const can = (action: string) =>
+ !!current &&
+ (['publish', 'return', 'reject', 'suspend'].includes(action)
+ ? current.moderator && !current.canEdit
+ : current.canEdit);
+ useEffect(() => {
+ if (current && stale && !dirty && !needsCompare && !form.processing) {
+ base.current = current;
+ render((value) => value + 1);
+ }
+ }, [current, stale, dirty, needsCompare, form.processing]);
+ function change(value: string) {
+ generation.current++;
+ live.current = value;
+ form.setData('reason', value);
+ }
+ function acknowledge(props: unknown, sent: Pending): boolean {
+ if (
+ !alive.current ||
+ pending.current !== sent ||
+ observed.current !== opened.current
+ )
+ return false;
+ const fresh = read(props, id),
+ command = fresh?.commands.find(
+ (value) =>
+ value.key === sent.command.client_key &&
+ value.action === sent.command.action &&
+ value.version === sent.command.version + 1,
+ );
+ if (
+ !fresh ||
+ !command ||
+ fresh.version < command.version ||
+ (fresh.version === command.version &&
+ (fresh.status !== states[sent.command.action] ||
+ fresh.context !== sent.base.context))
+ )
+ return false;
+ const exact = fresh.version === command.version;
+ base.current = exact
+ ? fresh
+ : {
+ ...sent.base,
+ version: command.version,
+ status: states[sent.command.action],
+ };
+ pending.current = null;
+ if (generation.current === sent.generation) {
+ live.current = '';
+ form.setData('reason', '');
+ }
+ form.setDefaults({ reason: '' });
+ form.clearErrors();
+ setNeedsCompare(!exact);
+ setProblem(
+ exact
+ ? null
+ : 'A acção foi reconhecida. Há alterações posteriores; compare antes de preparar outra decisão.',
+ );
+ setMustRefresh(false);
+ render((value) => value + 1);
+ return true;
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: [
+ 'record',
+ 'owner',
+ 'canEdit',
+ 'moderator',
+ 'publicationActions',
+ 'publicationCommands',
+ 'historySummary',
+ 'origins',
+ 'locations',
+ ],
+ onSuccess: (page) => {
+ if (!alive.current || observed.current !== opened.current)
+ return;
+ if (pending.current && acknowledge(page.props, pending.current))
+ return;
+ const fresh = read(page.props, id);
+ if (!fresh) {
+ setProblem(
+ 'Resposta incompatível com esta proposta. O motivo preparado foi conservado.',
+ );
+ return;
+ }
+ setMustRefresh(false);
+ if (
+ base.current &&
+ fresh.version === base.current.version &&
+ fresh.status === base.current.status &&
+ fresh.context === base.current.context
+ ) {
+ setNeedsCompare(false);
+ setProblem(null);
+ }
+ },
+ onNetworkError: () => {
+ setProblem(
+ 'Não foi possível confirmar a actualização. O motivo foi conservado.',
+ );
+ return false;
+ },
+ onHttpException: () => {
+ setNeedsCompare(true);
+ setProblem(
+ 'Não foi possível consultar a proposta com o acesso actual. O motivo foi conservado.',
+ );
+ return false;
+ },
+ onFinish: () => {
+ if (alive.current) setRefreshing(false);
+ },
+ });
+ }
+ function adopt() {
+ if (invalid || !current || mustRefresh || refreshing || form.processing)
+ return;
+ base.current = current;
+ pending.current = null;
+ setNeedsCompare(false);
+ setProblem(null);
+ form.clearErrors();
+ render((value) => value + 1);
+ }
+ function send(action: string, recover = false) {
+ if (
+ invalid ||
+ !current ||
+ !base.current ||
+ refreshing ||
+ form.processing ||
+ !can(action)
+ )
+ return;
+ let sent = pending.current;
+ if (recover) {
+ if (!sent?.ambiguous || sent.command.action !== action) return;
+ } else {
+ if (
+ sent ||
+ stale ||
+ needsCompare ||
+ !current.actions.includes(action) ||
+ !live.current.trim()
+ )
+ return;
+ sent = {
+ command: {
+ client_key: createOperationKey(),
+ version: base.current.version,
+ action,
+ reason: live.current,
+ },
+ generation: generation.current,
+ base: base.current,
+ ambiguous: false,
+ };
+ pending.current = sent;
+ }
+ if (!sent) return;
+ const request = sent;
+ form.transform(() => ({ ...request.command }));
+ form.post(`/parcerias/${id}/estado`, {
+ preserveScroll: true,
+ onSuccess: (page) => {
+ if (!alive.current) return;
+ if (
+ !acknowledge(page.props, request) &&
+ pending.current === request
+ ) {
+ request.ambiguous = true;
+ setMustRefresh(true);
+ setNeedsCompare(true);
+ setProblem(
+ 'A resposta não confirmou esta tentativa. Conserve o motivo e recupere a mesma acção ou compare os dados actuais.',
+ );
+ }
+ },
+ onError: () => {
+ if (
+ !alive.current ||
+ pending.current !== request ||
+ observed.current !== opened.current
+ )
+ return;
+ pending.current = null;
+ setProblem(
+ 'A acção não foi gravada. Corrija os campos indicados; o motivo foi conservado.',
+ );
+ },
+ onNetworkError: () => {
+ if (
+ alive.current &&
+ pending.current === request &&
+ observed.current === opened.current
+ ) {
+ request.ambiguous = true;
+ setMustRefresh(true);
+ setProblem(
+ 'A resposta perdeu-se. Pode recuperar exactamente a mesma tentativa, sem repetir uma decisão já gravada.',
+ );
+ }
+ return false;
+ },
+ onHttpException: (response) => {
+ if (
+ !alive.current ||
+ pending.current !== request ||
+ observed.current !== opened.current
+ )
+ return false;
+ if (response.status >= 500) request.ambiguous = true;
+ else pending.current = null;
+ setMustRefresh(true);
+ setNeedsCompare(true);
+ setProblem(
+ 'A acção não foi confirmada com os dados e acesso actuais. Compare antes de continuar; o motivo foi conservado.',
+ );
+ return false;
+ },
+ });
+ }
+ return {
+ form,
+ current,
+ base: base.current,
+ stale,
+ invalid,
+ dirty,
+ problem,
+ refreshing,
+ needsCompare,
+ mustRefresh,
+ changes:
+ current && base.current
+ ? Object.keys(current.values).filter(
+ (key) =>
+ current.values[key] !== base.current?.values[key],
+ )
+ : [],
+ blocked:
+ invalid ||
+ stale ||
+ needsCompare ||
+ !!pending.current ||
+ refreshing ||
+ form.processing,
+ recovery: pending.current?.ambiguous
+ ? pending.current.command.action
+ : null,
+ can,
+ change,
+ refresh,
+ adopt,
+ send,
+ };
+}
diff --git a/resources/js/lib/partnership-room-delivery.ts b/resources/js/lib/partnership-room-delivery.ts
new file mode 100644
index 00000000..5a2829cf
--- /dev/null
+++ b/resources/js/lib/partnership-room-delivery.ts
@@ -0,0 +1,199 @@
+import { useForm } from '@inertiajs/react';
+import { useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+type Data = {
+ body: string;
+ file: File | null;
+ shared: boolean;
+ client_key: string;
+};
+function object(value: unknown): value is Record {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+/** Keeps the original command, including the immutable File object, until delivery is confirmed. */
+export function useRoomDelivery({
+ roomId,
+ actorId,
+ kind,
+ mutable,
+ canWrite,
+}: {
+ roomId: number;
+ actorId: number;
+ kind: 'message' | 'upload';
+ mutable: boolean;
+ canWrite: boolean;
+}) {
+ const form = useForm({
+ body: '',
+ file: null,
+ shared: false,
+ client_key: createOperationKey(),
+ });
+ const live = useRef(form.data);
+ live.current = form.data;
+ const generation = useRef({ body: 0, file: 0, shared: 0 });
+ const identity = useRef(JSON.stringify([roomId, actorId, kind]));
+ const observed = useRef(identity.current);
+ observed.current = JSON.stringify([roomId, actorId, kind]);
+ const pending = useRef<{
+ data: Data;
+ generation: typeof generation.current;
+ ambiguous: boolean;
+ } | null>(null);
+ const [problem, setProblem] = useState(null);
+ const recovering = !!pending.current?.ambiguous;
+ const invalid = observed.current !== identity.current;
+ const dirty =
+ !!pending.current ||
+ (kind === 'message' ? !!form.data.body : !!form.data.file);
+ const blocked =
+ form.processing || invalid || !canWrite || (!mutable && !recovering);
+ function change(
+ key: K,
+ value: Data[K],
+ ) {
+ generation.current[key]++;
+ live.current = { ...live.current, [key]: value };
+ form.setData(live.current);
+ }
+ function submit() {
+ if (
+ blocked ||
+ (kind === 'upload' &&
+ !pending.current?.data.file &&
+ !live.current.file)
+ )
+ return;
+ const command = pending.current ?? {
+ data: { ...live.current },
+ generation: { ...generation.current },
+ ambiguous: false,
+ };
+ pending.current = command;
+ setProblem(null);
+ form.transform(() =>
+ kind === 'message'
+ ? {
+ body: command.data.body,
+ client_key: command.data.client_key,
+ }
+ : {
+ file: command.data.file,
+ shared: command.data.shared,
+ client_key: command.data.client_key,
+ },
+ );
+ const unknown = () => {
+ if (pending.current) pending.current.ambiguous = true;
+ setProblem(
+ 'O envio não foi confirmado. A tentativa original e a sua preparação foram conservadas.',
+ );
+ return false;
+ };
+ form.post(
+ `/parcerias/salas/${roomId}/${kind === 'message' ? 'mensagens' : 'documentos'}`,
+ {
+ preserveScroll: true,
+ forceFormData: kind === 'upload',
+ onSuccess: (page) => {
+ if (observed.current !== identity.current) return;
+ const props = page.props;
+ const room = props.room;
+ const flash = props.flash;
+ const confirmed =
+ object(room) &&
+ room.id === roomId &&
+ (kind === 'message'
+ ? Array.isArray(props.messages) &&
+ props.messages.some(
+ (message) =>
+ object(message) &&
+ message.author_id === actorId &&
+ message.client_key ===
+ command.data.client_key &&
+ message.body === command.data.body.trim(),
+ )
+ : object(flash) &&
+ typeof flash.uploaded_document_id === 'string' &&
+ Array.isArray(props.documents) &&
+ props.documents.some(
+ (document) =>
+ object(document) &&
+ document.document_id ===
+ flash.uploaded_document_id &&
+ document.owner_id === actorId &&
+ document.file_name ===
+ command.data.file?.name,
+ ));
+ if (!confirmed) {
+ unknown();
+ return;
+ }
+ const next: Data = {
+ body: '',
+ file: null,
+ shared: false,
+ client_key: createOperationKey(),
+ };
+ if (
+ kind === 'message' &&
+ generation.current.body !== command.generation.body
+ )
+ next.body = live.current.body;
+ if (kind === 'upload') {
+ if (
+ generation.current.file !== command.generation.file
+ ) {
+ next.file = live.current.file;
+ next.shared = live.current.shared;
+ } else if (
+ generation.current.shared !==
+ command.generation.shared
+ )
+ next.shared = live.current.shared;
+ }
+ pending.current = null;
+ live.current = next;
+ form.setDefaults({
+ body: '',
+ file: null,
+ shared: false,
+ client_key: next.client_key,
+ });
+ form.setData(next);
+ form.clearErrors();
+ setProblem(null);
+ },
+ onError: () => {
+ if (!pending.current?.ambiguous) pending.current = null;
+ },
+ onHttpException: (response) => {
+ if (
+ response.status >= 500 ||
+ response.status === 409 ||
+ pending.current?.ambiguous
+ )
+ return unknown();
+ pending.current = null;
+ setProblem(
+ 'Não foi possível confirmar o envio com o acesso actual. A preparação foi conservada.',
+ );
+ return false;
+ },
+ onNetworkError: unknown,
+ onCancel: unknown,
+ },
+ );
+ }
+ return {
+ form,
+ data: form.data,
+ change,
+ submit,
+ problem,
+ recovering,
+ dirty,
+ blocked,
+ };
+}
diff --git a/resources/js/lib/partnership-room-edit.ts b/resources/js/lib/partnership-room-edit.ts
new file mode 100644
index 00000000..542b0ff0
--- /dev/null
+++ b/resources/js/lib/partnership-room-edit.ts
@@ -0,0 +1,845 @@
+import { router, useForm } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { createOperationKey } from './operation-key';
+
+type Values = Record;
+type Kind = 'agreement' | 'milestone';
+type Snapshot = {
+ actorId: number | null;
+ partnershipVersion: number | null;
+ interestVersion: number | null;
+ commands: {
+ key: string;
+ action: string;
+ version: number;
+ status: string;
+ party: string | null;
+ }[];
+ confirmations: Record;
+ id: number | null;
+ version: number | null;
+ context: string;
+ roomVersion: number;
+ status: string;
+ canWrite: boolean;
+ values: Values;
+};
+function object(value: unknown): value is Record {
+ return !!value && typeof value === 'object' && !Array.isArray(value);
+}
+function positive(value: unknown): value is number {
+ return (
+ typeof value === 'number' && Number.isSafeInteger(value) && value > 0
+ );
+}
+function text(value: unknown): string | null {
+ return value == null ? '' : typeof value === 'string' ? value : null;
+}
+const milestoneKeys = [
+ 'title',
+ 'responsible_id',
+ 'due_date',
+ 'status',
+ 'evidence',
+];
+function snapshot(
+ props: unknown,
+ roomId: number,
+ kind: Kind,
+ itemId: number | null,
+ creationKey?: string,
+): Snapshot | null {
+ if (
+ !object(props) ||
+ !object(props.room) ||
+ props.room.id !== roomId ||
+ !positive(props.room.version) ||
+ typeof props.room.status !== 'string' ||
+ typeof props.canWrite !== 'boolean'
+ )
+ return null;
+ const room = props.room;
+ const actorId = positive(props.agreementActorId)
+ ? props.agreementActorId
+ : null;
+ const partnershipVersion =
+ object(props.partnership) && positive(props.partnership.version)
+ ? props.partnership.version
+ : null;
+ const interestVersion =
+ object(props.interest) && positive(props.interest.version)
+ ? props.interest.version
+ : null;
+ if (
+ kind === 'agreement' &&
+ (!actorId ||
+ !partnershipVersion ||
+ !interestVersion ||
+ !Array.isArray(props.agreementCommands) ||
+ !props.agreementCommands.every(
+ (command) =>
+ object(command) &&
+ typeof command.key === 'string' &&
+ typeof command.action === 'string' &&
+ positive(command.version) &&
+ typeof command.status === 'string' &&
+ (command.party === null ||
+ command.party === 'proponent' ||
+ command.party === 'candidate'),
+ ))
+ )
+ return null;
+ let values: Record,
+ id: number | null = roomId,
+ version: number | null = room.version as number;
+ const confirmations: Snapshot['confirmations'] = {};
+ if (kind === 'agreement') {
+ if (room.agreement !== null && !object(room.agreement)) return null;
+ const agreement = object(room.agreement) ? room.agreement : {};
+ if (object(agreement.confirmations))
+ for (const party of ['proponent', 'candidate']) {
+ const confirmation = agreement.confirmations[party];
+ if (object(confirmation) && positive(confirmation.actor_id))
+ confirmations[party] = {
+ actorId: confirmation.actor_id,
+ reason:
+ typeof confirmation.reason === 'string'
+ ? confirmation.reason
+ : '',
+ };
+ }
+ values = {
+ title: text(agreement.title),
+ terms: text(agreement.terms),
+ reason: '',
+ };
+ } else if (itemId === null && !creationKey) {
+ id = null;
+ version = null;
+ values = {
+ title: '',
+ responsible_id: '',
+ due_date: '',
+ status: 'pending',
+ evidence: '',
+ };
+ } else {
+ if (!Array.isArray(props.milestones)) return null;
+ const item = props.milestones.find(
+ (candidate) =>
+ object(candidate) &&
+ (creationKey
+ ? candidate.client_key === creationKey
+ : candidate.id === itemId),
+ );
+ if (
+ !object(item) ||
+ !positive(item.id) ||
+ !positive(item.version) ||
+ !positive(item.responsible_id)
+ )
+ return null;
+ id = item.id;
+ version = item.version;
+ values = {
+ title: text(item.title),
+ responsible_id: String(item.responsible_id),
+ due_date: text(item.due_date),
+ status: text(item.status),
+ evidence: text(item.evidence),
+ };
+ }
+ if (!Object.values(values).every((value) => typeof value === 'string'))
+ return null;
+ return {
+ actorId,
+ partnershipVersion,
+ interestVersion,
+ confirmations,
+ commands:
+ kind === 'agreement' && Array.isArray(props.agreementCommands)
+ ? props.agreementCommands.map((command) => ({
+ key: command.key,
+ action: command.action,
+ version: command.version,
+ status: command.status,
+ party: command.party,
+ }))
+ : [],
+ id,
+ version,
+ context: JSON.stringify(
+ kind === 'agreement'
+ ? [
+ room.version,
+ room.status,
+ props.canWrite,
+ partnershipVersion,
+ interestVersion,
+ ]
+ : [room.version, room.status, props.canWrite],
+ ),
+ roomVersion: room.version as number,
+ status: room.status as string,
+ canWrite: props.canWrite,
+ values: values as Values,
+ };
+}
+const same = (a: Values, b: Values) =>
+ Object.keys(a).every((key) => a[key] === b[key]);
+const normal = (value: string) => value.trim();
+export function useRoomEdit({
+ props,
+ roomId,
+ kind,
+ itemId = null,
+}: {
+ props: unknown;
+ roomId: number;
+ kind: Kind;
+ itemId?: number | null;
+}) {
+ const alive = useRef(true);
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ const current = snapshot(props, roomId, kind, itemId);
+ const initial = useRef(current);
+ const initialIdentity = useRef(JSON.stringify([roomId, kind, itemId]));
+ const observedIdentity = useRef(initialIdentity.current);
+ observedIdentity.current = JSON.stringify([roomId, kind, itemId]);
+ const empty: Values =
+ kind === 'agreement'
+ ? { title: '', terms: '', reason: '' }
+ : {
+ title: '',
+ responsible_id: '',
+ due_date: '',
+ status: 'pending',
+ evidence: '',
+ };
+ const form = useForm<{
+ version: number | null;
+ client_key: string;
+ values: Values;
+ }>({
+ version: current?.version ?? null,
+ client_key: createOperationKey(),
+ values: current?.values ?? empty,
+ });
+ const live = useRef(form.data);
+ live.current = form.data;
+ const edited = useRef(new Set());
+ const generation = useRef>({});
+ const pending = useRef<{
+ command: Record;
+ generations: Record;
+ ambiguous: boolean;
+ base: Snapshot;
+ values: Values;
+ } | null>(null);
+ const [choices, setChoices] = useState>(
+ {},
+ );
+ const [refreshing, setRefreshing] = useState(false);
+ const [needsCompare, setNeedsCompare] = useState(false);
+ const [problem, setProblem] = useState(null);
+ const [mustRefresh, setMustRefresh] = useState(false),
+ [accessDenied, setAccessDenied] = useState(false);
+ const [created, setCreated] = useState(null);
+ const isNew = kind === 'milestone' && itemId === null;
+ const keys = Object.keys(current?.values ?? empty);
+ const invalid =
+ !current ||
+ !initial.current ||
+ (kind === 'agreement' && current.actorId !== initial.current.actorId) ||
+ initialIdentity.current !== JSON.stringify([roomId, kind, itemId]);
+ const stale =
+ !!current &&
+ !!initial.current &&
+ (current.version !== initial.current.version ||
+ current.context !== initial.current.context ||
+ !same(current.values, initial.current.values));
+ const changed =
+ current && initial.current
+ ? keys.filter(
+ (key) => current.values[key] !== initial.current?.values[key],
+ )
+ : [];
+ const conflicts = current
+ ? changed.filter(
+ (key) =>
+ edited.current.has(key) &&
+ live.current.values[key] !== current.values[key],
+ )
+ : [];
+ const choiceKey = (key: string) =>
+ JSON.stringify([
+ current?.version,
+ current?.context,
+ key,
+ current?.values[key],
+ ]);
+ const unresolved = conflicts.filter(
+ (key) => choices[choiceKey(key)] !== 'mine',
+ );
+ const editable =
+ !!current?.canWrite &&
+ (kind === 'agreement'
+ ? ['negotiation', 'agreement_recorded', 'agreed', 'execution']
+ : ['agreement_recorded', 'agreed', 'execution']
+ ).includes(current.status);
+ const recovering =
+ (isNew || kind === 'agreement') &&
+ !!pending.current?.ambiguous &&
+ !!current?.canWrite &&
+ !accessDenied;
+ const blocked =
+ invalid ||
+ stale ||
+ refreshing ||
+ needsCompare ||
+ (kind === 'agreement' && (accessDenied || !!pending.current)) ||
+ (!editable && !recovering);
+ const dirty =
+ !!pending.current ||
+ (!!initial.current &&
+ (!same(live.current.values, initial.current.values) ||
+ keys.some(
+ (key) =>
+ edited.current.has(key) &&
+ current &&
+ live.current.values[key] !== current.values[key],
+ )));
+ // Untouched controls follow current data. Deliberate edits and uncertain commands require comparison.
+ useEffect(() => {
+ if (
+ !current ||
+ invalid ||
+ (!stale && !(kind === 'agreement' && pending.current?.ambiguous)) ||
+ dirty ||
+ edited.current.size > 0 ||
+ pending.current ||
+ form.processing ||
+ needsCompare
+ )
+ return;
+ if (kind === 'agreement' && mustRefresh) return;
+ initial.current = current;
+ live.current = {
+ ...live.current,
+ version: current.version,
+ values: { ...current.values },
+ };
+ form.setDefaults(live.current);
+ form.setData(live.current);
+ }, [current, invalid, stale, dirty, form.processing, needsCompare]);
+ function change(key: string, value: string) {
+ if (!keys.includes(key)) return;
+ edited.current.add(key);
+ generation.current[key] = (generation.current[key] ?? 0) + 1;
+ live.current = {
+ ...live.current,
+ values: { ...live.current.values, [key]: value },
+ };
+ form.setData(live.current);
+ setChoices((previous) => {
+ const next = { ...previous };
+ delete next[choiceKey(key)];
+ return next;
+ });
+ }
+ function choose(key: string, value: 'mine' | 'current') {
+ if (!current || !keys.includes(key)) return;
+ if (value === 'current') change(key, current.values[key]);
+ setChoices((previous) => ({ ...previous, [choiceKey(key)]: value }));
+ }
+ function adopt() {
+ if (
+ !current ||
+ invalid ||
+ (!stale && !(kind === 'agreement' && pending.current?.ambiguous)) ||
+ (kind === 'agreement' && (mustRefresh || accessDenied)) ||
+ unresolved.length ||
+ refreshing ||
+ form.processing
+ )
+ return;
+ const values = { ...current.values };
+ for (const key of keys)
+ if (edited.current.has(key)) values[key] = live.current.values[key];
+ initial.current = current;
+ live.current = { ...live.current, version: current.version, values };
+ form.setData(live.current);
+ form.setDefaults({ ...live.current, values: current.values });
+ form.clearErrors();
+ setChoices({});
+ setNeedsCompare(false);
+ setProblem(null);
+ if (kind === 'agreement') pending.current = null;
+ }
+ function httpFailure(response: { status: number }) {
+ if (!alive.current) return false;
+ if (kind === 'agreement') {
+ setMustRefresh(true);
+ setAccessDenied([401, 403, 404, 419].includes(response.status));
+ }
+ setProblem(
+ response.status === 409
+ ? 'O registo ou o estado da sala mudou. Compare com os dados actuais; as suas edições foram conservadas.'
+ : 'Não foi possível confirmar a operação com o acesso actual. As suas edições foram conservadas.',
+ );
+ if (response.status === 409 || response.status >= 500)
+ setNeedsCompare(true);
+ if (pending.current) {
+ if (kind === 'agreement' && response.status === 409) {
+ pending.current = null;
+ return false;
+ }
+ if (
+ response.status >= 500 ||
+ response.status === 409 ||
+ pending.current.ambiguous
+ )
+ pending.current.ambiguous = true;
+ else pending.current = null;
+ }
+ return false;
+ }
+ function refresh() {
+ if (refreshing || form.processing) return;
+ setRefreshing(true);
+ router.reload({
+ only: [
+ 'room',
+ 'milestones',
+ 'participants',
+ 'canWrite',
+ 'messages',
+ 'documents',
+ 'partnership',
+ 'interest',
+ 'agreementActorId',
+ 'agreementCommands',
+ 'agreementParty',
+ ],
+ onSuccess: (page) => {
+ if (!alive.current) return;
+ if (
+ kind === 'agreement' &&
+ pending.current &&
+ acknowledgeAgreement(page.props, pending.current)
+ )
+ return;
+ const fresh = snapshot(page.props, roomId, kind, itemId);
+ if (
+ kind === 'agreement' &&
+ fresh &&
+ fresh.actorId === initial.current?.actorId
+ ) {
+ setMustRefresh(false);
+ setAccessDenied(false);
+ }
+ if (
+ fresh &&
+ initial.current &&
+ fresh.version === initial.current.version &&
+ fresh.context === initial.current.context &&
+ same(fresh.values, initial.current.values)
+ ) {
+ setNeedsCompare(false);
+ setProblem(null);
+ }
+ },
+ onHttpException: () => {
+ if (!alive.current) return false;
+ if (kind === 'agreement') {
+ setMustRefresh(true);
+ setAccessDenied(true);
+ }
+ setProblem(
+ 'Não foi possível recuperar esta sala com o acesso actual. As suas edições foram conservadas.',
+ );
+ return false;
+ },
+ onNetworkError: () => {
+ if (!alive.current) return false;
+ setProblem(
+ 'A recuperação não foi confirmada. As suas edições foram conservadas.',
+ );
+ return false;
+ },
+ onFinish: () => {
+ if (alive.current) setRefreshing(false);
+ },
+ });
+ }
+ function acknowledgeAgreement(
+ props: unknown,
+ sent: NonNullable,
+ ): boolean {
+ if (!alive.current || pending.current !== sent) return false;
+ const fresh = snapshot(props, roomId, 'agreement', null),
+ action = String(sent.command.action),
+ version = Number(sent.command.version) + 1;
+ const receipt = fresh?.commands.find(
+ (command) =>
+ command.key === sent.command.client_key &&
+ command.action === action &&
+ command.version === version,
+ );
+ if (
+ !fresh ||
+ !receipt ||
+ fresh.actorId !== sent.base.actorId ||
+ fresh.version === null ||
+ fresh.version < version
+ )
+ return false;
+ const expected: Values =
+ action === 'record'
+ ? {
+ title: normal(sent.values.title),
+ terms: normal(sent.values.terms),
+ reason: '',
+ }
+ : { ...sent.base.values, reason: '' };
+ if (
+ fresh.version === version &&
+ (fresh.status !== receipt.status ||
+ fresh.values.title !== expected.title ||
+ fresh.values.terms !== expected.terms)
+ )
+ return false;
+ if (
+ fresh.version === version &&
+ action === 'confirm' &&
+ (!receipt.party ||
+ fresh.confirmations[receipt.party]?.actorId !==
+ sent.base.actorId ||
+ fresh.confirmations[receipt.party]?.reason !==
+ normal(String(sent.command.reason)) ||
+ (receipt.status === 'agreed' &&
+ (!fresh.confirmations.proponent ||
+ !fresh.confirmations.candidate)))
+ )
+ return false;
+ const later =
+ fresh.version > version ||
+ fresh.partnershipVersion !== sent.base.partnershipVersion ||
+ fresh.interestVersion !== sent.base.interestVersion;
+ const saved: Snapshot = later
+ ? {
+ ...sent.base,
+ version,
+ roomVersion: version,
+ status: receipt.status,
+ values: expected,
+ context: JSON.stringify([
+ version,
+ receipt.status,
+ sent.base.canWrite,
+ sent.base.partnershipVersion,
+ sent.base.interestVersion,
+ ]),
+ }
+ : fresh;
+ const merged = { ...saved.values };
+ edited.current.clear();
+ for (const key of keys)
+ if (
+ (generation.current[key] ?? 0) !==
+ (sent.generations[key] ?? 0) ||
+ (action !== 'record' &&
+ key !== 'reason' &&
+ live.current.values[key] !== sent.base.values[key])
+ ) {
+ merged[key] = live.current.values[key];
+ edited.current.add(key);
+ }
+ initial.current = saved;
+ pending.current = null;
+ live.current = {
+ ...live.current,
+ version: saved.version,
+ values: merged,
+ };
+ form.setDefaults({ ...live.current, values: saved.values });
+ form.setData(live.current);
+ form.clearErrors();
+ setChoices({});
+ setNeedsCompare(later);
+ setMustRefresh(false);
+ setAccessDenied(false);
+ setProblem(
+ later
+ ? 'A acção foi reconhecida, mas existem decisões posteriores. Compare antes de preparar outra acção.'
+ : null,
+ );
+ return true;
+ }
+ function submit(action = 'record', recover = false) {
+ if (
+ !alive.current ||
+ form.processing ||
+ !initial.current ||
+ (kind === 'agreement' &&
+ (invalid || accessDenied || !current?.canWrite || refreshing))
+ )
+ return;
+ if (recover && kind === 'agreement') {
+ if (!pending.current?.ambiguous) return;
+ action = String(pending.current.command.action);
+ } else if (blocked) return;
+ const base = initial.current;
+ if (kind === 'agreement' && !recover) {
+ const allowed: Record = {
+ record: ['negotiation', 'agreement_recorded'],
+ confirm: ['agreement_recorded'],
+ start: ['agreed'],
+ complete: ['execution'],
+ renew: ['agreed', 'execution'],
+ cancel: [
+ 'negotiation',
+ 'agreement_recorded',
+ 'agreed',
+ 'execution',
+ ],
+ };
+ if (!allowed[action]?.includes(base.status)) return;
+ }
+ const command: Record =
+ pending.current?.command ??
+ (kind === 'agreement'
+ ? action === 'record'
+ ? {
+ ...live.current.values,
+ version: live.current.version,
+ action,
+ client_key: createOperationKey(),
+ partnership_version: base.partnershipVersion,
+ interest_version: base.interestVersion,
+ }
+ : {
+ version: live.current.version,
+ action,
+ reason: live.current.values.reason,
+ client_key: createOperationKey(),
+ partnership_version: base.partnershipVersion,
+ interest_version: base.interestVersion,
+ }
+ : {
+ ...live.current.values,
+ version: live.current.version,
+ ...(isNew ? { client_key: live.current.client_key } : {}),
+ });
+ const sentGenerations = pending.current?.generations ?? {
+ ...generation.current,
+ };
+ if ((isNew || kind === 'agreement') && !pending.current)
+ pending.current = {
+ command,
+ generations: sentGenerations,
+ ambiguous: false,
+ base,
+ values: { ...live.current.values },
+ };
+ const sentValues = { ...live.current.values };
+ const attempt = pending.current;
+ setProblem(null);
+ form.transform(() => command);
+ const unknown = () => {
+ if (!alive.current) return false;
+ if (kind === 'agreement' && pending.current !== attempt)
+ return false;
+ if (kind === 'agreement') setMustRefresh(true);
+ if (pending.current) pending.current.ambiguous = true;
+ else setNeedsCompare(true);
+ setProblem(
+ 'A gravação não foi confirmada. As suas edições foram conservadas.',
+ );
+ return false;
+ };
+ const options = {
+ preserveScroll: true,
+ onSuccess: (page: { props: Record }) => {
+ if (!alive.current) return;
+ if (kind === 'agreement') {
+ if (
+ attempt &&
+ pending.current === attempt &&
+ !acknowledgeAgreement(page.props, attempt)
+ ) {
+ attempt.ambiguous = true;
+ setMustRefresh(true);
+ setNeedsCompare(true);
+ setProblem(
+ 'A resposta não reconheceu esta tentativa. A preparação foi conservada.',
+ );
+ }
+ return;
+ }
+ if (
+ observedIdentity.current !==
+ JSON.stringify([roomId, kind, itemId])
+ )
+ return;
+ const saved = snapshot(
+ page.props,
+ roomId,
+ kind,
+ itemId,
+ isNew ? String(command.client_key) : undefined,
+ );
+ if (
+ !saved ||
+ (!isNew && saved.version !== Number(command.version) + 1)
+ ) {
+ setProblem(
+ 'A resposta não confirmou este registo. Recupere os dados antes de continuar; a edição foi conservada.',
+ );
+ setNeedsCompare(true);
+ if (pending.current) pending.current.ambiguous = true;
+ return;
+ }
+ if (!isNew) {
+ if (
+ milestoneKeys.some(
+ (key) =>
+ saved.values[key] !== normal(sentValues[key]),
+ ) ||
+ saved.context !== base.context
+ ) {
+ setProblem(
+ 'Os dados devolvidos diferem da operação enviada. Compare antes de continuar; a sua edição foi conservada.',
+ );
+ setNeedsCompare(true);
+ return;
+ }
+ }
+ const defaults = isNew
+ ? snapshot(page.props, roomId, kind, null)
+ : saved;
+ if (!defaults) return;
+ const merged = { ...defaults.values };
+ edited.current.clear();
+ for (const key of keys)
+ if (
+ (generation.current[key] ?? 0) !==
+ (sentGenerations[key] ?? 0)
+ ) {
+ merged[key] = live.current.values[key];
+ edited.current.add(key);
+ }
+ initial.current = defaults;
+ if (isNew) {
+ setCreated(saved.id);
+ pending.current = null;
+ }
+ live.current = {
+ version: defaults.version,
+ client_key: isNew
+ ? createOperationKey()
+ : live.current.client_key,
+ values: merged,
+ };
+ form.setDefaults({ ...live.current, values: defaults.values });
+ form.setData(live.current);
+ form.clearErrors();
+ setChoices({});
+ setNeedsCompare(false);
+ setProblem(null);
+ },
+ onError: () => {
+ if (
+ !alive.current ||
+ (kind === 'agreement' && pending.current !== attempt)
+ )
+ return;
+ if (pending.current && !pending.current.ambiguous)
+ pending.current = null;
+ },
+ onHttpException: (response: { status: number }) =>
+ kind === 'agreement' && pending.current !== attempt
+ ? false
+ : httpFailure(response),
+ onNetworkError: unknown,
+ onCancel: unknown,
+ };
+ if (kind === 'agreement')
+ form.post(`/parcerias/salas/${roomId}/acordo`, options);
+ else if (isNew) form.post(`/parcerias/salas/${roomId}/marcos`, options);
+ else form.put(`/parcerias/salas/${roomId}/marcos/${itemId}`, options);
+ }
+ return {
+ form,
+ values: form.data.values,
+ current: current?.values ?? empty,
+ baseVersion: initial.current?.version,
+ version: current?.version,
+ status: current?.status,
+ stale,
+ invalid,
+ editable,
+ dirty,
+ blocked,
+ refreshing,
+ changed,
+ conflicts,
+ unresolved,
+ problem,
+ recovering,
+ pendingAction:
+ kind === 'agreement' && pending.current?.ambiguous
+ ? String(pending.current.command.action)
+ : null,
+ canRecover:
+ kind === 'agreement' &&
+ recovering &&
+ !invalid &&
+ !refreshing &&
+ !form.processing,
+ recover: () => submit('record', true),
+ mustRefresh: kind === 'agreement' && mustRefresh,
+ created,
+ change,
+ choose,
+ adopt,
+ refresh,
+ submit,
+ };
+}
+export type RoomEditor = ReturnType;
+
+/** One room-level leave guard. No draft content is persisted in browser storage. */
+export function useRoomLeaveGuard(dirty: boolean) {
+ const live = useRef(dirty);
+ live.current = dirty;
+ useEffect(() => {
+ const leave = (event: BeforeUnloadEvent) => {
+ if (live.current) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ const stop = router.on('before', (event) => {
+ if (
+ live.current &&
+ event.detail.visit.method === 'get' &&
+ event.detail.visit.preserveState !== true &&
+ !window.confirm(
+ 'Há alterações por guardar nesta sala. Pretende sair sem as guardar?',
+ )
+ )
+ event.preventDefault();
+ });
+ window.addEventListener('beforeunload', leave);
+ return () => {
+ stop();
+ window.removeEventListener('beforeunload', leave);
+ };
+ }, []);
+}
diff --git a/resources/js/lib/product-experiments.ts b/resources/js/lib/product-experiments.ts
new file mode 100644
index 00000000..e4e4d4c3
--- /dev/null
+++ b/resources/js/lib/product-experiments.ts
@@ -0,0 +1,107 @@
+import type { UsageReport } from './product-usage';
+
+export type ExperimentValues = Record;
+export type ExperimentDocument = {
+ definition_version: string;
+ version: number;
+ at: string;
+ actor: { id: number; name: string };
+ reason: string;
+ values: ExperimentValues;
+ indicator: {
+ id: string;
+ title: string;
+ unit: string;
+ source: string;
+ limits: string;
+ definition_version: string;
+ } | null;
+ plan_sha256: string;
+ observation_plan_sha256: string | null;
+ registration: {
+ first_at: string | null;
+ original_plan_sha256: string | null;
+ amendments: number;
+ amended_after_observation: boolean;
+ };
+ operational_report: UsageReport | null;
+ report_matches_observation: boolean | null;
+ report_scope: string;
+};
+export type ExperimentView = {
+ installed: boolean;
+ id: string | null;
+ currentVersion: number;
+ historical: boolean;
+ document: ExperimentDocument | null;
+ values: ExperimentValues;
+ states: Record;
+ changeKinds: Record;
+ decisions: Record;
+ labels: Record;
+ catalogue: {
+ definition_version: string;
+ items: Omit<
+ NonNullable,
+ 'definition_version'
+ >[];
+ services: { code: string; title: string; version: number }[];
+ };
+ history: {
+ version: number;
+ at: string;
+ actor: string;
+ state: string;
+ reason: string;
+ }[];
+ historyNext: number | null;
+};
+
+export function experimentDifferences(
+ base: ExperimentValues,
+ mine: ExperimentValues,
+ current: ExperimentValues,
+ editedKeys?: readonly string[],
+): string[] {
+ return [
+ ...new Set([
+ ...Object.keys(base),
+ ...Object.keys(mine),
+ ...Object.keys(current),
+ ]),
+ ].filter(
+ (key) =>
+ (base[key] ?? '') !== (current[key] ?? '') &&
+ (editedKeys
+ ? editedKeys.includes(key)
+ : (mine[key] ?? '') !== (base[key] ?? '')) &&
+ (mine[key] ?? '') !== (current[key] ?? ''),
+ );
+}
+
+/** Merge only changes the user did not edit; conflicts remain explicit. */
+export function mergeExperimentValues(
+ base: ExperimentValues,
+ mine: ExperimentValues,
+ current: ExperimentValues,
+ editedKeys?: readonly string[],
+): ExperimentValues {
+ return Object.fromEntries(
+ [
+ ...new Set([
+ ...Object.keys(base),
+ ...Object.keys(mine),
+ ...Object.keys(current),
+ ]),
+ ].map((key) => [
+ key,
+ (
+ editedKeys
+ ? !editedKeys.includes(key)
+ : (mine[key] ?? '') === (base[key] ?? '')
+ )
+ ? (current[key] ?? '')
+ : (mine[key] ?? ''),
+ ]),
+ );
+}
diff --git a/resources/js/lib/product-usage.ts b/resources/js/lib/product-usage.ts
new file mode 100644
index 00000000..2671b7ab
--- /dev/null
+++ b/resources/js/lib/product-usage.ts
@@ -0,0 +1,69 @@
+export type SearchUsageReport = {
+ installed: boolean;
+ enabled_now: boolean;
+ applicable: boolean;
+ from: string;
+ to: string;
+ timezone: string;
+ read_at: string;
+ definition_version: string;
+ available_definitions: string[];
+ definition_conflict_now: boolean;
+ responses: number | null;
+ zero_responses: number | null;
+ zero_rate: number | null;
+ channels: {
+ id: string;
+ label: string;
+ responses: number | null;
+ zero_responses: number | null;
+ zero_rate: number | null;
+ first_recorded_at: string | null;
+ last_recorded_at: string | null;
+ definition_versions: string[];
+ }[];
+ exclusions: string[];
+ limits: string[];
+ completeness: string;
+ temporal_basis: string;
+};
+export type UsageReport = {
+ definition_version: string;
+ generated_at: string;
+ timezone: string;
+ observed_before: string;
+ filters: {
+ from: string;
+ to: string;
+ service_code: string | null;
+ search_definition?: string;
+ };
+ search?: SearchUsageReport;
+ services: { code: string; title: string; version: number }[];
+ coverage: Record;
+ metrics: {
+ id: string;
+ title: string;
+ value: number | null;
+ unit: string;
+ numerator: number | null;
+ denominator: number | null;
+ state: string;
+ source: string;
+ limits: string;
+ }[];
+ unmeasured: { id: string; title: string; reason: string; href?: string }[];
+ limits: string[];
+ fingerprint: string;
+ read_consistency: string;
+};
+
+export function usageValue(value: number | null, unit = ''): string {
+ if (value === null) return 'Sem medição';
+ return `${value.toLocaleString('pt-PT', { maximumFractionDigits: 2 })}${unit ? ` ${unit}` : ''}`;
+}
+
+/** Export the applied server snapshot, never the pending filter form. */
+export function usageExport(report: UsageReport): string {
+ return JSON.stringify(report, null, 2);
+}
diff --git a/resources/js/lib/profile-json.ts b/resources/js/lib/profile-json.ts
index 32a4e0b5..84708c3f 100644
--- a/resources/js/lib/profile-json.ts
+++ b/resources/js/lib/profile-json.ts
@@ -35,10 +35,20 @@ export async function profileJson(
credentials: 'same-origin',
headers: {
Accept: 'application/json',
- 'Content-Type': 'application/json',
+ ...(typeof FormData !== 'undefined' && data instanceof FormData
+ ? {}
+ : { 'Content-Type': 'application/json' }),
...(method === 'GET' ? {} : { 'X-XSRF-TOKEN': token }),
},
- ...(method === 'GET' ? {} : { body: JSON.stringify(data) }),
+ ...(method === 'GET'
+ ? {}
+ : {
+ body:
+ typeof FormData !== 'undefined' &&
+ data instanceof FormData
+ ? data
+ : JSON.stringify(data),
+ }),
});
const result = await response.json().catch(() => null);
const reauthenticate =
diff --git a/resources/js/lib/profile-support-installation.ts b/resources/js/lib/profile-support-installation.ts
new file mode 100644
index 00000000..dbc32297
--- /dev/null
+++ b/resources/js/lib/profile-support-installation.ts
@@ -0,0 +1,406 @@
+import { useEffect, useRef, useState } from 'react';
+import { portalRequest, PortalApiError } from './portal-api';
+import { createOperationKey } from './operation-key';
+import { usePagePreparationGuard } from './page-preparation-guard';
+export type SupportPlan = {
+ actorId: number;
+ target: { database: string; port: number };
+ hash: string;
+ code_hash: string;
+ installed: boolean;
+ consistent: boolean;
+ repairable: boolean;
+ ready: boolean;
+ action: 'none' | 'install' | 'repair_known_base' | 'blocked';
+ schema: { state: string; ledger: boolean };
+ dependencies: Record;
+ changes: string[];
+ backupDate: string | null;
+ rollback: string;
+ commands: { key: string; code_hash: string }[];
+ mfa_confirmed: boolean;
+};
+type Attempt = {
+ body: {
+ hash: string;
+ reason: string;
+ confirm: true;
+ idempotency_key: string;
+ };
+ code: string;
+ generation: number;
+};
+const endpoint = '/management/profile-install/technical-support';
+const object = (v: unknown): v is Record =>
+ !!v && typeof v === 'object' && !Array.isArray(v);
+const hex = (v: unknown): v is string =>
+ typeof v === 'string' && /^[a-f0-9]{64}$/.test(v);
+const target = (v: unknown): v is SupportPlan['target'] =>
+ object(v) &&
+ typeof v.database === 'string' &&
+ Number.isSafeInteger(v.port) &&
+ Number(v.port) > 0;
+const validPlan = (v: unknown): v is SupportPlan =>
+ object(v) &&
+ typeof v.actorId === 'number' &&
+ Number.isSafeInteger(v.actorId) &&
+ v.actorId > 0 &&
+ target(v.target) &&
+ hex(v.hash) &&
+ hex(v.code_hash) &&
+ typeof v.installed === 'boolean' &&
+ typeof v.consistent === 'boolean' &&
+ typeof v.repairable === 'boolean' &&
+ typeof v.ready === 'boolean' &&
+ ['none', 'install', 'repair_known_base', 'blocked'].includes(
+ String(v.action),
+ ) &&
+ object(v.schema) &&
+ typeof v.schema.state === 'string' &&
+ typeof v.schema.ledger === 'boolean' &&
+ object(v.dependencies) &&
+ Object.values(v.dependencies).every((x) => typeof x === 'boolean') &&
+ Array.isArray(v.changes) &&
+ v.changes.every((x) => typeof x === 'string') &&
+ (v.backupDate === null || typeof v.backupDate === 'string') &&
+ typeof v.rollback === 'string' &&
+ typeof v.mfa_confirmed === 'boolean' &&
+ Array.isArray(v.commands) &&
+ v.commands.every(
+ (x) => object(x) && typeof x.key === 'string' && hex(x.code_hash),
+ );
+const sameTarget = (a: SupportPlan['target'], b: SupportPlan['target']) =>
+ a.database === b.database && a.port === b.port;
+export function useProfileSupportInstallation(initial: SupportPlan) {
+ const [plan, setPlan] = useState(initial),
+ [base, setBase] = useState(initial),
+ [reason, setReason] = useState(''),
+ [confirmed, setConfirmed] = useState(false),
+ [busy, setBusy] = useState(false),
+ [refreshing, setRefreshing] = useState(false),
+ [uncertain, setUncertain] = useState(false),
+ [blocked, setBlocked] = useState(false),
+ [needsRefresh, setNeedsRefresh] = useState(false),
+ [message, setMessage] = useState(''),
+ [error, setError] = useState('');
+ const origin = useRef({ actor: initial.actorId, target: initial.target }),
+ epoch = useRef({ actor: initial.actorId, target: initial.target }),
+ alive = useRef(true),
+ pending = useRef(null),
+ active = useRef(null),
+ reading = useRef(null),
+ generation = useRef(0),
+ text = useRef(reason),
+ committed = useRef(null);
+ if (
+ epoch.current.actor !== initial.actorId ||
+ !sameTarget(epoch.current.target, initial.target)
+ )
+ epoch.current = { actor: initial.actorId, target: initial.target };
+ text.current = reason;
+ const valid =
+ validPlan(plan) &&
+ plan.actorId === origin.current.actor &&
+ sameTarget(plan.target, origin.current.target) &&
+ initial.actorId === origin.current.actor &&
+ sameTarget(initial.target, origin.current.target);
+ const stale = base.hash !== plan.hash;
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ function change(value: string) {
+ generation.current++;
+ text.current = value;
+ setReason(value);
+ setConfirmed(false);
+ setError('');
+ }
+ function acknowledge(attempt: Attempt) {
+ if (pending.current !== attempt) return;
+ pending.current = null;
+ active.current = null;
+ committed.current = attempt;
+ setBusy(false);
+ setUncertain(false);
+ setNeedsRefresh(true);
+ setConfirmed(false);
+ setError('');
+ setMessage(
+ 'Resultado da actualização confirmado. Confira a prévia actual.',
+ );
+ if (generation.current === attempt.generation) {
+ text.current = '';
+ setReason('');
+ }
+ }
+ function read(value: unknown) {
+ if (
+ !validPlan(value) ||
+ value.actorId !== origin.current.actor ||
+ !sameTarget(value.target, origin.current.target)
+ )
+ return false;
+ setPlan(value);
+ setBlocked(false);
+ setError('');
+ const attempt = pending.current;
+ if (
+ attempt &&
+ value.commands.some(
+ (c) =>
+ c.key === attempt.body.idempotency_key &&
+ c.code_hash === attempt.code,
+ )
+ )
+ acknowledge(attempt);
+ const known = committed.current;
+ if (known) {
+ if (
+ !value.commands.some(
+ (c) =>
+ c.key === known.body.idempotency_key &&
+ c.code_hash === known.code,
+ )
+ ) {
+ setError(
+ 'Esta consulta ainda não confirma o resultado já recebido. Actualize novamente antes de outra acção.',
+ );
+ return true;
+ }
+ if (
+ value.code_hash === known.code &&
+ value.installed &&
+ value.consistent
+ )
+ setBase(value);
+ committed.current = null;
+ setNeedsRefresh(false);
+ } else setNeedsRefresh(false);
+ return true;
+ }
+ useEffect(() => {
+ if (validPlan(initial)) read(initial);
+ }, [initial]);
+ async function refresh() {
+ if (reading.current) return;
+ const request = {},
+ scope = epoch.current;
+ reading.current = request;
+ setRefreshing(true);
+ try {
+ const value = await portalRequest(endpoint);
+ if (alive.current && epoch.current === scope && !read(value))
+ setError(
+ 'A consulta recebida não corresponde a esta conta e destino. A preparação foi conservada.',
+ );
+ } catch (e) {
+ if (alive.current && epoch.current === scope) {
+ if (
+ e instanceof PortalApiError &&
+ [401, 403, 419].includes(e.status)
+ )
+ setBlocked(true);
+ setError(
+ 'Não foi possível actualizar a prévia. O fundamento e a tentativa original foram conservados.',
+ );
+ }
+ } finally {
+ if (
+ alive.current &&
+ epoch.current === scope &&
+ reading.current === request
+ ) {
+ reading.current = null;
+ setRefreshing(false);
+ }
+ }
+ }
+ async function send(retry = false) {
+ if (
+ !valid ||
+ blocked ||
+ !plan.mfa_confirmed ||
+ active.current ||
+ reading.current
+ )
+ return;
+ if (
+ !retry &&
+ (pending.current ||
+ stale ||
+ needsRefresh ||
+ !confirmed ||
+ !plan.ready ||
+ plan.installed ||
+ !plan.mfa_confirmed ||
+ (!plan.consistent && !plan.repairable))
+ )
+ return;
+ let attempt = pending.current;
+ if (!attempt) {
+ if (text.current.trim().length < 20 || text.current.length > 1000) {
+ setError('Preencha o fundamento com 20 a 1000 caracteres.');
+ return;
+ }
+ try {
+ attempt = {
+ body: {
+ hash: base.hash,
+ reason: text.current,
+ confirm: true,
+ idempotency_key: createOperationKey().toLowerCase(),
+ },
+ code: base.code_hash,
+ generation: generation.current,
+ };
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível preparar a operação.',
+ );
+ return;
+ }
+ pending.current = attempt;
+ }
+ const scope = epoch.current;
+ active.current = attempt;
+ setBusy(true);
+ setUncertain(true);
+ setError('');
+ try {
+ const result = await portalRequest(endpoint, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(attempt.body),
+ });
+ if (
+ !alive.current ||
+ epoch.current !== scope ||
+ pending.current !== attempt
+ )
+ return;
+ if (
+ !object(result) ||
+ result.actor_id !== origin.current.actor ||
+ result.command_key !== attempt.body.idempotency_key ||
+ result.migration !==
+ '2026_11_03_080000_add_technical_support_profile' ||
+ result.code_hash !== attempt.code ||
+ result.installed !== true ||
+ !target(result.target) ||
+ !sameTarget(result.target, origin.current.target)
+ )
+ throw new Error(
+ 'A confirmação não corresponde à tentativa preparada. Consulte a prévia antes de continuar.',
+ );
+ acknowledge(attempt);
+ void refresh();
+ } catch (e) {
+ if (
+ !alive.current ||
+ epoch.current !== scope ||
+ pending.current !== attempt
+ )
+ return;
+ if (e instanceof PortalApiError && [409, 422].includes(e.status)) {
+ pending.current = null;
+ setUncertain(false);
+ setConfirmed(false);
+ setError(
+ e.status === 409
+ ? 'A tentativa foi recusada porque o plano mudou. Actualize e compare a prévia; o fundamento foi conservado.'
+ : e.errors.reason?.join(' ') ||
+ 'A operação foi recusada. Confira as dependências, as provas e o fundamento.',
+ );
+ if (e.status === 409) {
+ setNeedsRefresh(true);
+ void refresh();
+ }
+ } else if (
+ e instanceof PortalApiError &&
+ [401, 403, 419].includes(e.status)
+ ) {
+ setBlocked(true);
+ setError(
+ 'Confirme a conta e renove a autenticação MFA antes de repetir. A preparação foi conservada.',
+ );
+ } else
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Resultado sem confirmação. Conserve a tentativa original.',
+ );
+ } finally {
+ if (
+ alive.current &&
+ epoch.current === scope &&
+ active.current === attempt
+ ) {
+ active.current = null;
+ setBusy(false);
+ }
+ }
+ }
+ function adopt() {
+ if (!valid || busy || refreshing || pending.current || blocked) return;
+ setBase(plan);
+ setConfirmed(false);
+ setNeedsRefresh(false);
+ setMessage(
+ 'Prévia actual confirmada. Reveja o fundamento e confirme esta operação.',
+ );
+ setError('');
+ }
+ usePagePreparationGuard(
+ !!reason || uncertain,
+ 'Existe um fundamento preparado ou uma instalação sem confirmação. Sair desta página?',
+ );
+ return {
+ plan,
+ base,
+ reason,
+ change,
+ confirmed,
+ setConfirmed,
+ busy,
+ refreshing,
+ uncertain,
+ message,
+ error,
+ stale,
+ refresh,
+ send,
+ adopt,
+ canAdopt:
+ valid &&
+ !busy &&
+ !refreshing &&
+ !pending.current &&
+ !blocked &&
+ stale,
+ canRetry:
+ valid &&
+ plan.mfa_confirmed &&
+ !busy &&
+ !refreshing &&
+ !blocked &&
+ !!pending.current,
+ canSend:
+ valid &&
+ !blocked &&
+ !busy &&
+ !refreshing &&
+ !needsRefresh &&
+ !stale &&
+ !uncertain &&
+ confirmed &&
+ plan.ready &&
+ !plan.installed &&
+ plan.mfa_confirmed &&
+ (plan.consistent || plan.repairable),
+ };
+}
diff --git a/resources/js/lib/technical-incident-handling.ts b/resources/js/lib/technical-incident-handling.ts
new file mode 100644
index 00000000..99a9cfc9
--- /dev/null
+++ b/resources/js/lib/technical-incident-handling.ts
@@ -0,0 +1,368 @@
+import { router } from '@inertiajs/react';
+import { useEffect, useRef, useState } from 'react';
+import { portalRequest, PortalApiError } from './portal-api';
+import { createOperationKey } from './operation-key';
+export type HandlingState = {
+ version: number;
+ status: 'open' | 'in_progress' | 'resolved';
+ assignee_user_id: number | null;
+ assignee_name: string | null;
+ updated_at: string | null;
+ resolved_at: string | null;
+};
+export type Incident = {
+ reference: string;
+ operation: string;
+ observed_version: number;
+ occurred_at: string;
+ error_code: string;
+ handling: HandlingState;
+};
+export type Command = 'claim' | 'release' | 'note' | 'resolve' | 'reopen';
+export type HandlingProps = {
+ incident: Incident;
+ actorId: number;
+ commands: { key: string; version: number }[];
+};
+type Attempt = {
+ values: {
+ version: number;
+ action: Command;
+ note: string;
+ operation_key: string;
+ };
+ generation: number;
+};
+const object = (v: unknown): v is Record =>
+ !!v && typeof v === 'object' && !Array.isArray(v);
+const integer = (v: unknown, min = 0): v is number =>
+ typeof v === 'number' && Number.isSafeInteger(v) && v >= min;
+const validState = (v: unknown): v is HandlingState =>
+ object(v) &&
+ integer(v.version) &&
+ ['open', 'in_progress', 'resolved'].includes(String(v.status)) &&
+ (v.assignee_user_id === null || integer(v.assignee_user_id, 1)) &&
+ (v.assignee_name === null || typeof v.assignee_name === 'string') &&
+ (v.updated_at === null || typeof v.updated_at === 'string') &&
+ (v.resolved_at === null || typeof v.resolved_at === 'string');
+export function useTechnicalIncidentHandling(props: HandlingProps) {
+ const { incident, actorId, commands } = props;
+ const [note, setNote] = useState(''),
+ [base, setBase] = useState(() => ({ ...incident.handling })),
+ [busy, setBusy] = useState(false),
+ [uncertain, setUncertain] = useState(false),
+ [refreshing, setRefreshing] = useState(false),
+ [blocked, setBlocked] = useState(false),
+ [needsRefresh, setNeedsRefresh] = useState(false),
+ [notice, setNotice] = useState(''),
+ [error, setError] = useState('');
+ const pending = useRef(null),
+ activeRequest = useRef(null),
+ liveNote = useRef(note),
+ generation = useRef(0),
+ confirmed = useRef(null),
+ alive = useRef(true),
+ origin = useRef({ actorId, reference: incident.reference }),
+ scope = useRef({ actorId, reference: incident.reference });
+ if (
+ scope.current.actorId !== actorId ||
+ scope.current.reference !== incident.reference
+ )
+ scope.current = { actorId, reference: incident.reference };
+ liveNote.current = note;
+ const valid =
+ integer(actorId, 1) &&
+ actorId === origin.current.actorId &&
+ incident.reference === origin.current.reference &&
+ validState(incident.handling) &&
+ Array.isArray(commands) &&
+ commands.every(
+ (item) => typeof item.key === 'string' && integer(item.version, 1),
+ );
+ const stale = base.version !== incident.handling.version;
+ function change(value: string) {
+ generation.current++;
+ liveNote.current = value;
+ setNote(value);
+ setError('');
+ }
+ function acknowledge(attempt: Attempt, version: number) {
+ if (pending.current !== attempt) return;
+ pending.current = null;
+ activeRequest.current = null;
+ setBusy(false);
+ setUncertain(false);
+ setNeedsRefresh(true);
+ confirmed.current = version;
+ if (generation.current === attempt.generation) {
+ liveNote.current = '';
+ setNote('');
+ }
+ setNotice(
+ 'Tratamento registado. As alterações posteriores da nota foram conservadas.',
+ );
+ setError('');
+ }
+ function read(value: unknown) {
+ if (
+ !object(value) ||
+ value.actorId !== actorId ||
+ !object(value.incident) ||
+ value.incident.reference !== incident.reference ||
+ !validState(value.incident.handling) ||
+ !Array.isArray(value.commands)
+ )
+ return false;
+ const attempt = pending.current;
+ if (
+ attempt &&
+ value.commands.some(
+ (c) =>
+ object(c) &&
+ c.key === attempt.values.operation_key &&
+ c.version === attempt.values.version + 1,
+ ) &&
+ value.incident.handling.version >= attempt.values.version + 1
+ )
+ acknowledge(attempt, attempt.values.version + 1);
+ if (confirmed.current !== null) {
+ if (value.incident.handling.version === confirmed.current)
+ setBase({ ...value.incident.handling });
+ if (value.incident.handling.version >= confirmed.current) {
+ confirmed.current = null;
+ setNeedsRefresh(false);
+ }
+ }
+ setBlocked(false);
+ return true;
+ }
+ useEffect(() => {
+ alive.current = true;
+ return () => {
+ alive.current = false;
+ };
+ }, []);
+ useEffect(() => {
+ if (valid) read(props);
+ }, [incident, commands, actorId]);
+ function refresh() {
+ if (refreshing) return;
+ const epoch = scope.current;
+ setRefreshing(true);
+ router.reload({
+ only: ['incident', 'history', 'commands', 'actorId'],
+ onSuccess: (page) => {
+ if (
+ alive.current &&
+ scope.current === epoch &&
+ !read(page.props)
+ )
+ setError(
+ 'Não foi possível confirmar esta consulta. A nota preparada foi conservada.',
+ );
+ },
+ onError: () => {
+ if (alive.current && scope.current === epoch)
+ setError(
+ 'Não foi possível actualizar o incidente. A nota foi conservada.',
+ );
+ },
+ onFinish: () => {
+ if (alive.current && scope.current === epoch)
+ setRefreshing(false);
+ },
+ });
+ }
+ async function send(action: Command, retry = false) {
+ if (
+ !valid ||
+ blocked ||
+ refreshing ||
+ activeRequest.current ||
+ (!retry && (stale || needsRefresh || pending.current))
+ )
+ return;
+ let attempt = pending.current;
+ if (!attempt) {
+ if (
+ liveNote.current.trim().length < 10 ||
+ liveNote.current.length > 3000
+ ) {
+ setError('Preencha uma nota com 10 a 3000 caracteres.');
+ return;
+ }
+ try {
+ attempt = {
+ values: {
+ version: base.version,
+ action,
+ note: liveNote.current,
+ operation_key: createOperationKey().toLowerCase(),
+ },
+ generation: generation.current,
+ };
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível preparar o registo.',
+ );
+ return;
+ }
+ pending.current = attempt;
+ }
+ const epoch = scope.current;
+ activeRequest.current = attempt;
+ setBusy(true);
+ setUncertain(true);
+ setError('');
+ try {
+ const result = await portalRequest(
+ `/suporte-tecnico/incidentes/${incident.reference}`,
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(attempt.values),
+ },
+ );
+ if (
+ !alive.current ||
+ scope.current !== epoch ||
+ pending.current !== attempt
+ )
+ return;
+ if (
+ !object(result) ||
+ result.reference !== incident.reference ||
+ result.actor_id !== actorId ||
+ result.operation_key !== attempt.values.operation_key ||
+ result.result_version !== attempt.values.version + 1 ||
+ !validState(result.handling) ||
+ result.handling.version < result.result_version
+ )
+ throw new Error(
+ 'A confirmação recebida não corresponde a esta tentativa. Actualize o incidente.',
+ );
+ acknowledge(attempt, result.result_version);
+ refresh();
+ } catch (e) {
+ if (
+ !alive.current ||
+ scope.current !== epoch ||
+ pending.current !== attempt
+ )
+ return;
+ if (e instanceof PortalApiError && e.status === 422) {
+ pending.current = null;
+ setUncertain(false);
+ setError(
+ e.errors.note?.join(' ') ||
+ 'Este tratamento não pode ser aplicado ao estado actual. Actualize os dados e reveja a nota.',
+ );
+ } else if (
+ e instanceof PortalApiError &&
+ (e.status === 403 || e.status === 401 || e.status === 419)
+ ) {
+ setBlocked(true);
+ setError(
+ 'O acesso ou a sessão precisam de confirmação. A nota e a tentativa original foram conservadas.',
+ );
+ } else
+ setError(
+ e instanceof PortalApiError && e.status === 409
+ ? 'O incidente mudou. Actualize e compare o estado antes de preparar outra tentativa.'
+ : e instanceof Error
+ ? e.message
+ : 'Resultado sem confirmação. Conserve a tentativa original.',
+ );
+ } finally {
+ if (
+ alive.current &&
+ scope.current === epoch &&
+ activeRequest.current === attempt
+ ) {
+ activeRequest.current = null;
+ setBusy(false);
+ }
+ }
+ }
+ function adopt() {
+ if (!valid || !stale || busy || refreshing || needsRefresh || blocked)
+ return;
+ const attempt = pending.current;
+ if (attempt) {
+ if (
+ incident.handling.version <= attempt.values.version ||
+ commands.some((c) => c.key === attempt.values.operation_key)
+ )
+ return;
+ pending.current = null;
+ setUncertain(false);
+ }
+ setBase({ ...incident.handling });
+ setError('');
+ setNotice(
+ 'Estado actual confirmado. Reveja a nota conservada antes de a enviar.',
+ );
+ }
+ const guard = useRef(false);
+ guard.current = !!note || uncertain;
+ useEffect(() => {
+ const remove = router.on('before', (event) => {
+ if (
+ guard.current &&
+ event.detail.visit.method === 'get' &&
+ !event.detail.visit.preserveState &&
+ !window.confirm(
+ 'Existe uma nota preparada ou um envio sem confirmação. Sair desta página?',
+ )
+ )
+ event.preventDefault();
+ });
+ const unload = (event: BeforeUnloadEvent) => {
+ if (guard.current) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ window.addEventListener('beforeunload', unload);
+ return () => {
+ remove();
+ window.removeEventListener('beforeunload', unload);
+ };
+ }, []);
+ return {
+ note,
+ change,
+ base,
+ stale,
+ busy,
+ uncertain,
+ refreshing,
+ notice,
+ error,
+ refresh,
+ send,
+ adopt,
+ blocked:
+ !valid ||
+ blocked ||
+ busy ||
+ refreshing ||
+ needsRefresh ||
+ stale ||
+ uncertain,
+ canRetry:
+ valid && !blocked && !busy && !refreshing && !!pending.current,
+ canAdopt:
+ valid &&
+ !blocked &&
+ !busy &&
+ !refreshing &&
+ !needsRefresh &&
+ stale &&
+ (!pending.current ||
+ incident.handling.version > pending.current.values.version),
+ pendingAction: pending.current?.values.action,
+ };
+}
diff --git a/resources/js/lib/technical-incident-labels.ts b/resources/js/lib/technical-incident-labels.ts
new file mode 100644
index 00000000..4724099d
--- /dev/null
+++ b/resources/js/lib/technical-incident-labels.ts
@@ -0,0 +1,45 @@
+import type { Command } from './technical-incident-handling';
+export const incidentOperationLabels: Record = {
+ submit: 'Submissão para validação',
+ publish: 'Publicação',
+ upload_document: 'Carregamento de documento',
+ upload_image: 'Carregamento de imagem',
+ prepare_image: 'Preparação de imagens WebP',
+ scan_document: 'Análise de segurança de documento',
+};
+export function incidentOperationLabel(operation: string) {
+ return (
+ incidentOperationLabels[operation] ||
+ 'Operação técnica não identificada'
+ );
+}
+export function incidentErrorLabel(code: string) {
+ return (
+ (
+ {
+ database_failure:
+ 'Falha no serviço de dados durante a operação.',
+ workflow_unavailable: 'Falha técnica durante a operação.',
+ scan_dispatch_unconfirmed:
+ 'Encaminhamento da análise sem confirmação.',
+ scan_inconclusive: 'Análise de segurança inconclusiva.',
+ scan_worker_failed:
+ 'Falha na execução da análise de segurança.',
+ scan_cleanup_unconfirmed:
+ 'Limpeza do ficheiro temporário por confirmar.',
+ } as Record
+ )[code] || 'Falha técnica durante a operação.'
+ );
+}
+export const handlingLabels: Record = {
+ open: 'Na fila',
+ in_progress: 'Em tratamento',
+ resolved: 'Resolvido',
+};
+export const commandLabels: Record = {
+ claim: 'Assumir tratamento',
+ release: 'Devolver à fila',
+ note: 'Acrescentar nota',
+ resolve: 'Resolver incidente',
+ reopen: 'Reabrir incidente',
+};
diff --git a/resources/js/pages/crm/investor.tsx b/resources/js/pages/crm/investor.tsx
index 962f0201..63ffb714 100644
--- a/resources/js/pages/crm/investor.tsx
+++ b/resources/js/pages/crm/investor.tsx
@@ -1,9 +1,12 @@
-import { Link, useForm } from '@inertiajs/react';
+import { Link } from '@inertiajs/react';
+import { useCrmRecordEdit } from '@/lib/crm-record-edit';
+import CrmEditComparison from '@/components/crm-edit-comparison';
import { Management, Field, control, button } from '../management/shared';
import { leadStates } from './types';
type Contact = {
id: string;
+ version_no: number;
full_name: string;
email: string | null;
phone: string | null;
@@ -15,44 +18,61 @@ function ContactForm({
contact: Contact;
investorId: string;
}) {
- const form = useForm({
- full_name: contact.full_name,
- email: contact.email ?? '',
- phone: contact.phone ?? '',
+ const edit = useCrmRecordEdit({
+ id: contact.id,
+ kind: 'contact',
+ version: contact.version_no,
+ values: {
+ full_name: contact.full_name,
+ email: contact.email ?? '',
+ phone: contact.phone ?? '',
+ },
});
+ const form = edit.form;
return (
{
e.preventDefault();
- form.patch(
+ edit.submit(
`/management/crm/investors/${investorId}/contacts/${contact.id}`,
);
}}
>
-
+
form.setData('full_name', e.target.value)}
+ value={edit.values.full_name}
+ onChange={(e) => edit.change('full_name', e.target.value)}
/>
-
+
form.setData('email', e.target.value)}
+ value={edit.values.email}
+ onChange={(e) => edit.change('email', e.target.value)}
/>
-
+
form.setData('phone', e.target.value)}
+ value={edit.values.phone}
+ onChange={(e) => edit.change('phone', e.target.value)}
/>
-
+
+
Guardar contacto
@@ -65,6 +85,7 @@ export default function InvestorDetail({
}: {
investor: {
id: string;
+ version_no: number;
legal_name: string;
investor_type: string;
status: string;
@@ -72,38 +93,44 @@ export default function InvestorDetail({
contacts: Contact[];
leads: { id: string; title: string; status: string }[];
}) {
- const form = useForm({
- legal_name: investor.legal_name,
- investor_type: investor.investor_type,
- status: investor.status,
+ const edit = useCrmRecordEdit({
+ id: investor.id,
+ kind: 'investor',
+ version: investor.version_no,
+ values: {
+ legal_name: investor.legal_name,
+ investor_type: investor.investor_type,
+ status: investor.status,
+ },
});
+ const form = edit.form;
return (
{
e.preventDefault();
- form.patch(`/management/crm/investors/${investor.id}`);
+ edit.submit(`/management/crm/investors/${investor.id}`);
}}
>
-
+
- form.setData('legal_name', e.target.value)
+ edit.change('legal_name', e.target.value)
}
/>
- form.setData('investor_type', e.target.value)
+ edit.change('investor_type', e.target.value)
}
>
{Object.entries({
@@ -118,11 +145,11 @@ export default function InvestorDetail({
))}
-
+
form.setData('status', e.target.value)}
+ value={edit.values.status}
+ onChange={(e) => edit.change('status', e.target.value)}
>
{Object.entries({
prospect: 'Potencial investidor',
@@ -135,7 +162,34 @@ export default function InvestorDetail({
))}
-
+
+ key === 'investor_type'
+ ? ({
+ domestic: 'Nacional',
+ foreign: 'Estrangeiro',
+ institutional: 'Institucional',
+ individual: 'Individual',
+ }[value] ?? value)
+ : key === 'status'
+ ? ({
+ prospect: 'Potencial investidor',
+ active: 'Activo',
+ inactive: 'Inactivo',
+ }[value] ?? value)
+ : value
+ }
+ />
+
Guardar investidor
diff --git a/resources/js/pages/crm/lead.tsx b/resources/js/pages/crm/lead.tsx
index 1aff4ed1..cab3d894 100644
--- a/resources/js/pages/crm/lead.tsx
+++ b/resources/js/pages/crm/lead.tsx
@@ -1,16 +1,28 @@
-import { Link, useForm } from '@inertiajs/react';
+import CrmTaskCreation from '@/components/crm-task-creation';
+import type { TaskCreationContext } from '@/lib/crm-task-creation';
+import { Link } from '@inertiajs/react';
+import { useCrmRecordEdit } from '@/lib/crm-record-edit';
+import CrmEditComparison from '@/components/crm-edit-comparison';
import { Management, Field, button, control } from '../management/shared';
import { leadStates, taskStates } from './types';
import type { Lead, Owner, Task } from './types';
function TaskRow({ task, leadId }: { task: Task; leadId: string }) {
- const form = useForm({ status: task.status });
+ const edit = useCrmRecordEdit({
+ id: task.id,
+ kind: 'task',
+ version: task.version_no,
+ values: { status: task.status },
+ });
+ const form = edit.form;
return (
{
e.preventDefault();
- form.patch(`/management/crm/leads/${leadId}/tasks/${task.id}`);
+ if (task.can_update === false) return;
+ edit.submit(`/management/crm/leads/${leadId}/tasks/${task.id}`);
}}
>
{task.title}
@@ -26,12 +38,13 @@ function TaskRow({ task, leadId }: { task: Task; leadId: string }) {
form.setData('status', e.target.value)}
+ disabled={task.can_update === false}
+ value={edit.values.status}
+ onChange={(e) => edit.change('status', e.target.value)}
>
{Object.entries(taskStates).map(([key, label]) => (
@@ -40,9 +53,26 @@ function TaskRow({ task, leadId }: { task: Task; leadId: string }) {
))}
-
- Actualizar tarefa
-
+ {task.can_update !== false ? (
+ <>
+ taskStates[value] ?? value}
+ />
+
+ Actualizar tarefa
+
+ >
+ ) : (
+
+ Dossier associado encerrado; tarefa disponível para
+ consulta.
+
+ )}
);
}
@@ -50,6 +80,8 @@ export default function LeadDetail({
lead,
contacts,
owners,
+ nextAction,
+ taskCreation,
}: {
lead: Lead;
contacts: {
@@ -59,17 +91,21 @@ export default function LeadDetail({
phone: string | null;
}[];
owners: Owner[];
+ nextAction?: { future_tasks: number };
+ taskCreation: TaskCreationContext;
}) {
- const review = useForm({
- status: lead.status,
- owner_user_id: String(lead.owner_user_id ?? ''),
- qualification_reason: '',
- });
- const task = useForm({
- title: '',
- due_at: '',
- assignee_user_id: String(lead.owner_user_id ?? ''),
+ const edit = useCrmRecordEdit({
+ id: lead.id,
+ kind: 'lead',
+ version: lead.version_no,
+ blankAfterSave: ['qualification_reason'],
+ values: {
+ status: lead.status,
+ owner_user_id: String(lead.owner_user_id ?? ''),
+ qualification_reason: '',
+ },
});
+ const review = edit.form;
return (
@@ -108,23 +144,46 @@ export default function LeadDetail({
))}
+ {nextAction && (
+
+
+ {nextAction.future_tasks === 1
+ ? '1 tarefa disponível com prazo futuro.'
+ : `${nextAction.future_tasks} tarefas disponíveis com prazo futuro.`}
+
+ {nextAction.future_tasks === 0 &&
+ ['new', 'qualified'].includes(lead.status) && (
+
+ Registe uma próxima acção com prazo futuro antes
+ de qualificar o acompanhamento ou concluir a sua
+ última tarefa. Tarefas num dossier encerrado
+ ficam no histórico e não contam como próxima
+ acção.
+
+ )}
+
+ Registar próxima acção
+
+
+ )}
{
e.preventDefault();
- review.patch(`/management/crm/leads/${lead.id}`);
+ edit.submit(`/management/crm/leads/${lead.id}`);
}}
>
Qualificação e atribuição
-
+
- review.setData('status', e.target.value)
- }
+ value={edit.values.status}
+ onChange={(e) => edit.change('status', e.target.value)}
>
{Object.entries(leadStates)
.filter(([key]) => key !== 'converted')
@@ -135,12 +194,12 @@ export default function LeadDetail({
))}
-
+
- review.setData('owner_user_id', e.target.value)
+ edit.change('owner_user_id', e.target.value)
}
>
Seleccione
@@ -153,16 +212,13 @@ export default function LeadDetail({
- review.setData(
- 'qualification_reason',
- e.target.value,
- )
+ edit.change('qualification_reason', e.target.value)
}
/>
@@ -171,9 +227,30 @@ export default function LeadDetail({
Último fundamento: {lead.qualification_reason}
)}
+
+ key === 'status'
+ ? (leadStates[value] ?? value)
+ : key === 'owner_user_id'
+ ? (owners.find(
+ (owner) => String(owner.id) === value,
+ )?.name ?? 'Responsável por confirmar')
+ : value
+ }
+ />
Guardar lead
@@ -185,62 +262,12 @@ export default function LeadDetail({
))}
{!lead.tasks.length && Não existem tarefas.
}
- {
- e.preventDefault();
- task.transform((data) => ({
- ...data,
- due_at: data.due_at
- ? new Date(data.due_at).toISOString()
- : '',
- }));
- task.post(`/management/crm/leads/${lead.id}/tasks`, {
- onSuccess: () => task.reset('title', 'due_at'),
- });
- }}
- >
-
- Registar próxima acção
-
-
- task.setData('title', e.target.value)}
- />
-
-
- task.setData('due_at', e.target.value)}
- />
-
-
-
- task.setData('assignee_user_id', e.target.value)
- }
- >
- Seleccione
- {owners.map((owner) => (
-
- {owner.name}
-
- ))}
-
-
-
- Criar tarefa
-
-
+
);
}
diff --git a/resources/js/pages/crm/types.ts b/resources/js/pages/crm/types.ts
index 1593f6ac..3ff810dd 100644
--- a/resources/js/pages/crm/types.ts
+++ b/resources/js/pages/crm/types.ts
@@ -1,5 +1,7 @@
export type Owner = { id: number; name: string };
export type Task = {
+ version_no: number;
+ can_update?: boolean;
id: string;
title: string;
status: string;
@@ -7,6 +9,7 @@ export type Task = {
assignee_user_id: number | null;
};
export type Lead = {
+ version_no: number;
id: string;
title: string;
status: string;
diff --git a/resources/js/pages/dashboard.tsx b/resources/js/pages/dashboard.tsx
index e2677428..18f77122 100644
--- a/resources/js/pages/dashboard.tsx
+++ b/resources/js/pages/dashboard.tsx
@@ -1,5 +1,8 @@
import ProfileNavigation from '@/components/profile-navigation';
import ContentManagementEntry from '@/components/content-management-entry';
+import DashboardWorkQueue, {
+ type DashboardQueue,
+} from '@/components/dashboard-work-queue';
import { Head, Link } from '@inertiajs/react';
import { dashboard } from '@/routes';
import type { InvestmentContext } from '@/pages/investor-path/index';
@@ -32,9 +35,11 @@ export default function Dashboard({
summary,
investorPath,
opportunityManagement,
+ workQueue,
}: {
summary: Summary | null;
opportunityManagement?: OpportunityManagementAccess | null;
+ workQueue?: DashboardQueue | null;
investorPath?: {
contexts: InvestmentContext[];
current: {
@@ -53,8 +58,15 @@ export default function Dashboard({
Painel do portal
+
{summary ? (
<>
+
+ Indicadores de utilização e cobertura
+
{opportunityManagement && (
;
investor_id?: string;
project_id?: string;
journey_id?: string;
};
canWrite: boolean;
+ canChangeState?: boolean;
+ activity?: {
+ open_requests: number | null;
+ open_tasks: number | null;
+ pending_payments: number | null;
+ } | null;
manager: boolean;
requests: { id: string; status: string; protocol: string | null }[];
- services: { id: string; title: string; version: number }[];
+ services: {
+ id: string;
+ title: string;
+ version: number;
+ effective_from?: string | null;
+ }[];
documents: DeskDocument[];
links: {
id: string;
@@ -143,6 +162,9 @@ export default function Case({
events: Event[];
}) {
const actor = usePage<{ auth: { user: { id: number } } }>().props.auth.user;
+ const [documentOrigin, setDocumentOrigin] =
+ useState(null);
+ const uploadInput = useRef(null);
const requestForm = useForm({
service_version_id: services[0]?.id ?? '',
client_key: createOperationKey(),
@@ -156,7 +178,7 @@ export default function Case({
status: 'preparing',
reason: '',
evidence: '',
- document_id: '',
+ document_link_id: '',
valid_until: '',
exception: false,
});
@@ -177,6 +199,12 @@ export default function Case({
});
return (
+ {dossier.closed_at && (
+
+ Dossier encerrado. Os pedidos, documentos e o histórico
+ continuam disponíveis para consulta.
+
+ )}
{legacyRequest && (
@@ -206,6 +234,22 @@ export default function Case({
Voltar ao Balcão Virtual
+ {canChangeState && (
+ {
+ upload.reset('file', 'consent');
+ if (uploadInput.current) uploadInput.current.value = '';
+ setDocumentOrigin(null);
+ }}
+ />
+ )}
Um dossier, os mesmos pedidos, documentos, conversas e tarefas.
Projecto existente:{' '}
@@ -250,6 +294,14 @@ export default function Case({
className={card + ' space-y-3'}
onSubmit={(e) => {
e.preventDefault();
+ if (
+ !services.some(
+ (service) =>
+ service.id ===
+ requestForm.data.service_version_id,
+ )
+ )
+ return;
requestForm.post(
`/balcao-virtual/dossiers/${dossier.id}/pedidos`,
);
@@ -269,9 +321,29 @@ export default function Case({
}
>
Seleccione
+ {requestForm.data.service_version_id &&
+ !services.some(
+ (service) =>
+ service.id ===
+ requestForm.data.service_version_id,
+ ) && (
+
+ A versão seleccionada já não está na
+ lista. Escolha o formulário actual.
+
+ )}
{services.map((s) => (
{s.title} — v{s.version}
+ {s.effective_from
+ ? ` · desde ${s.effective_from}`
+ : ''}
))}
@@ -279,11 +351,28 @@ export default function Case({
+ service.id ===
+ requestForm.data.service_version_id,
+ )
}
>
Preparar rascunho de pedido
+
+ router.reload({
+ only: ['services'],
+ })
+ }
+ >
+ Actualizar versões disponíveis
+
{!services.length && (
Sem serviços publicados. A orientação e os
@@ -328,7 +417,7 @@ export default function Case({
),
)}
- {(canWrite || manager) && (
+ {!dossier.closed_at && (canWrite || manager) && (
{
@@ -412,17 +501,34 @@ export default function Case({
/>
- Identificador do documento de suporte
-
stageForm.setData(
- 'document_id',
+ 'document_link_id',
e.target.value,
)
}
- />
+ >
+
+ Sem suporte seleccionado
+
+ {documents.map((document) => (
+
+ {document.file_name} · versão{' '}
+ {document.version_no ?? 'por confirmar'}{' '}
+ · {document.source_reference}
+ {document.valid_until
+ ? ` · validade declarada ${document.valid_until}`
+ : ''}
+
+ ))}
+
Conclusão e não aplicabilidade exigem revisão por
@@ -473,53 +579,85 @@ export default function Case({
upload.transform((d) => ({
...d,
version: dossier.version,
+ file: documentOrigin ? null : d.file,
+ document_id: documentOrigin?.document_id || '',
+ reuse_link_id: documentOrigin?.id || '',
+ source_reference:
+ documentOrigin?.source_reference?.trim()
+ ? undefined
+ : d.source_reference,
}));
upload.post(
`/balcao-virtual/dossiers/${dossier.id}/documentos`,
+ {
+ onSuccess: () => {
+ upload.reset(
+ 'file',
+ 'consent',
+ 'source_reference',
+ );
+ if (uploadInput.current)
+ uploadInput.current.value = '';
+ setDocumentOrigin(null);
+ },
+ },
);
}}
>
-
- Ficheiro privado
-
- upload.setData(
- 'file',
- e.target.files?.[0] ?? null,
- )
+ {
+ setDocumentOrigin(document);
+ upload.setData('consent', false);
+ if (document) {
+ upload.setData('file', null);
+ if (uploadInput.current)
+ uploadInput.current.value = '';
}
- />
-
-
- Ou identificador de documento já autorizado
-
- upload.setData(
- 'document_id',
- e.target.value,
- )
- }
- />
-
-
- Proveniência e referência
-
- upload.setData(
- 'source_reference',
- e.target.value,
- )
- }
- />
-
+ }}
+ />
+ {!documentOrigin && (
+
+ Ficheiro privado
+
+ upload.setData(
+ 'file',
+ e.target.files?.[0] ?? null,
+ )
+ }
+ />
+
+ )}
+ {documentOrigin?.source_reference?.trim() ? (
+
+ Referência já registada:{' '}
+ {documentOrigin.source_reference}. Será
+ conservada com a validade declarada e a versão
+ do original.
+
+ ) : (
+
+ Proveniência e referência
+
+ upload.setData(
+ 'source_reference',
+ e.target.value,
+ )
+ }
+ />
+
+ )}
Assunto da evidência — não equivale a validação
)}
- {manager && !canWrite && (
+ {!dossier.closed_at && manager && !canWrite && (
;
@@ -34,8 +35,16 @@ export default function Catalogue({
)}
{(installed
- ? services.map((s) => ({ ...s.definition, version: s.version }))
- : Object.values(prepared).map((s) => ({ ...s, version: null }))
+ ? services.map((s) => ({
+ ...s.definition,
+ version: s.version,
+ effective_from: s.effective_from,
+ }))
+ : Object.values(prepared).map((s) => ({
+ ...s,
+ version: null,
+ effective_from: null,
+ }))
).map((s) => (
{s.title}
@@ -45,6 +54,13 @@ export default function Catalogue({
? `Versão ${s.version}`
: 'Preparado, ainda indisponível para novos pedidos'}
+ {s.effective_from && (
+
+ Esta versão aplica-se a novos pedidos desde{' '}
+ {s.effective_from}. Pedidos anteriores mantêm o
+ formulário com que foram criados.
+
+ )}
))}
diff --git a/resources/js/pages/desk/request.tsx b/resources/js/pages/desk/request.tsx
index 91555317..b1b7aaed 100644
--- a/resources/js/pages/desk/request.tsx
+++ b/resources/js/pages/desk/request.tsx
@@ -1,6 +1,20 @@
import { DossierPrefill } from '@/components/dossier-prefill';
import { createOperationKey } from '@/lib/operation-key';
import { deskFieldApplies } from '@/lib/desk-field-visibility';
+import {
+ deskEmpty,
+ deskChoices,
+ deskScalar,
+ mergeDeskPrefill,
+ type DeskAnswer,
+} from '@/lib/desk-field-values';
+import DeskTypedChoice from '@/components/desk-typed-choice';
+import DeskDraftRecovery from '@/components/desk-draft-recovery';
+import DeskAttachmentField, {
+ type AttachmentInventory,
+} from '@/components/desk-attachment-field';
+import { useState } from 'react';
+import type { Field } from '@/pages/desk/service-editor';
import { Link, useForm } from '@inertiajs/react';
import { Frame, card, input, button } from '@/pages/investment/shared';
import CountrySelect, { type Country } from '@/components/country-select';
@@ -15,21 +29,19 @@ import {
type DeskPayment,
} from '@/components/desk-internal-operations';
-type Field = {
- label: string;
- type: string;
- required: boolean;
- options?: Record;
- when?: { field: string; equals: string };
-};
+const emptyDocuments: DeskDocument[] = [];
+
export default function RequestPage({
- request,
+ request: initialRequest,
case: dossier,
definition,
owner,
manager,
analyst,
fieldsEditable,
+ operationsEditable = !['closed', 'cancelled'].includes(
+ initialRequest.status,
+ ),
states,
transitions,
findings,
@@ -38,18 +50,23 @@ export default function RequestPage({
territoryPaths,
events,
documents,
+ reusableDocuments = emptyDocuments,
payments,
caseVersion,
countries,
toolPrefill,
boundContextRevision = 0,
+ serviceEffectiveFrom,
+ returnReasons = {},
}: {
+ returnReasons?: Record;
+ serviceEffectiveFrom?: string | null;
boundContextRevision?: number;
request: {
id: string;
version: number;
status: string;
- payload: Record;
+ payload: Record;
protocol: string | null;
editable_fields: string[];
analyst_id: number | null;
@@ -65,6 +82,7 @@ export default function RequestPage({
manager: boolean;
analyst: boolean;
fieldsEditable: boolean;
+ operationsEditable?: boolean;
states: Record;
transitions: string[];
findings: {
@@ -83,6 +101,7 @@ export default function RequestPage({
analysts: { id: number; name: string }[];
territoryPaths: Record;
documents: DeskDocument[];
+ reusableDocuments?: DeskDocument[];
payments: DeskPayment[];
caseVersion: number;
countries: Country[];
@@ -100,6 +119,51 @@ export default function RequestPage({
payload: Record;
}[];
}) {
+ const [recoveredRequest, setRecoveredRequest] = useState<
+ typeof initialRequest | null
+ >(null);
+ const request =
+ recoveredRequest?.id === initialRequest.id &&
+ recoveredRequest.version > initialRequest.version
+ ? recoveredRequest
+ : initialRequest;
+ const [checkpointBusy, setCheckpointBusy] = useState(false);
+ const [checkpointBlocked, setCheckpointBlocked] = useState(false);
+ const [attachmentInventory, setAttachmentInventory] = useState<
+ | (AttachmentInventory & {
+ sourceDocuments: DeskDocument[];
+ sourceReusable: DeskDocument[];
+ })
+ | null
+ >(null);
+ const [attachmentBusy, setAttachmentBusy] = useState<
+ Record
+ >({});
+ const filesBusy = Object.values(attachmentBusy).some(Boolean);
+ const inventoryNewer =
+ attachmentInventory && attachmentInventory.case_version > caseVersion;
+ const inventorySame =
+ attachmentInventory && attachmentInventory.case_version === caseVersion;
+ const currentInventory = {
+ case_version: Math.max(
+ attachmentInventory?.case_version ?? 0,
+ caseVersion,
+ ),
+ documents:
+ attachmentInventory &&
+ (inventoryNewer ||
+ (inventorySame &&
+ attachmentInventory.sourceDocuments === documents))
+ ? attachmentInventory.documents
+ : documents,
+ reusable_documents:
+ attachmentInventory &&
+ (inventoryNewer ||
+ (inventorySame &&
+ attachmentInventory.sourceReusable === reusableDocuments))
+ ? (attachmentInventory.reusable_documents ?? emptyDocuments)
+ : reusableDocuments,
+ };
const form = useForm({
context_revision: 0,
context_reviewed: false,
@@ -114,6 +178,7 @@ export default function RequestPage({
status: transitions[0] ?? '',
reason: '',
editable_fields: [] as string[],
+ return_reason_code: 'unspecified',
});
const assignment = useForm({
version: request.version,
@@ -122,9 +187,19 @@ export default function RequestPage({
due_at: '',
});
const message = useForm({ body: '', client_key: createOperationKey() });
- const canEdit = owner && fieldsEditable;
+ const canEdit =
+ owner &&
+ fieldsEditable &&
+ ['draft', 'returned'].includes(request.status);
return (
+ {serviceEffectiveFrom && (
+
+ Entrada em vigor do formulário deste pedido:{' '}
+ {serviceEffectiveFrom}. O pedido conserva a versão com que
+ foi criado.
+
+ )}
{definition.result}
+ {canEdit && (
+ [
+ key,
+ field.type === 'attachment'
+ ? {
+ ...field,
+ options: Object.fromEntries(
+ currentInventory.documents.map(
+ (document) => [
+ document.id,
+ document.file_name,
+ ],
+ ),
+ ),
+ }
+ : field,
+ ],
+ ),
+ )}
+ paused={form.processing}
+ pendingWork={filesBusy}
+ onBusy={setCheckpointBusy}
+ onBlocked={setCheckpointBlocked}
+ onRecover={(payload, reason, current) => {
+ setRecoveredRequest({
+ ...request,
+ ...current,
+ payload: current.payload,
+ });
+ form.setData((d) => ({
+ ...d,
+ payload,
+ reason,
+ version: current.version,
+ consent: false,
+ context_reviewed: false,
+ context_revision: 0,
+ }));
+ }}
+ />
+ )}
{owner && (
- request.status !== 'returned' ||
- request.editable_fields.includes(k),
+ !['consent', 'attachment'].includes(
+ definition.fields[k]?.type,
+ ) &&
+ (request.status !== 'returned' ||
+ request.editable_fields.includes(k)),
)}
onReview={(revision, reviewed) =>
form.setData((d) => ({
@@ -158,21 +286,12 @@ export default function RequestPage({
onApply={(patch, replace) =>
form.setData((d) => ({
...d,
- payload: {
- ...d.payload,
- ...Object.fromEntries(
- Object.entries(patch)
- .filter(
- ([k]) =>
- replace ||
- !d.payload[k]?.trim(),
- )
- .map(([k, v]) => [
- k,
- typeof v === 'string' ? v : '',
- ]),
- ),
- },
+ payload: mergeDeskPrefill(
+ d.payload,
+ patch,
+ definition.fields,
+ replace,
+ ),
}))
}
/>
@@ -226,7 +345,10 @@ export default function RequestPage({
className={button}
disabled={
form.processing ||
- !!form.data.payload.description?.trim()
+ checkpointBusy ||
+ checkpointBlocked ||
+ filesBusy ||
+ !deskEmpty(form.data.payload.description)
}
onClick={() => {
form.transform((data) => ({
@@ -279,6 +401,13 @@ export default function RequestPage({
className={card + ' space-y-3'}
onSubmit={(e) => {
e.preventDefault();
+ if (
+ checkpointBusy ||
+ checkpointBlocked ||
+ filesBusy ||
+ !canEdit
+ )
+ return;
form.transform((d) => ({
...d,
version: request.version,
@@ -295,7 +424,7 @@ export default function RequestPage({
label="País do requerente (opcional)"
error={form.errors['payload.country']}
countries={countries}
- value={form.data.payload.country ?? ''}
+ value={deskScalar(form.data.payload.country)}
allowLegacyValue
onChange={(value) =>
form.setData('payload', {
@@ -317,7 +446,9 @@ export default function RequestPage({
label="País de origem do pedido (opcional)"
error={form.errors['payload.declared_origin_country_code']}
countries={countries}
- value={form.data.payload.declared_origin_country_code ?? ''}
+ value={deskScalar(
+ form.data.payload.declared_origin_country_code,
+ )}
disabled={
!canEdit ||
form.processing ||
@@ -378,6 +509,140 @@ export default function RequestPage({
)}
+ ) : f.type === 'attachment' ? (
+
+
+ setAttachmentBusy((state) => ({
+ ...state,
+ [key]: value,
+ }))
+ }
+ onChange={(value) =>
+ form.setData('payload', {
+ ...form.data.payload,
+ [key]: value,
+ })
+ }
+ onInventory={(result, select) => {
+ setAttachmentInventory({
+ ...result,
+ reusable_documents:
+ result.reusable_documents ??
+ currentInventory.reusable_documents,
+ sourceDocuments: documents,
+ sourceReusable: reusableDocuments,
+ });
+ const linkId = result.link_id;
+ if (select && linkId)
+ form.setData((d) => {
+ const ids = deskChoices(
+ d.payload[key],
+ );
+ const uploaded =
+ result.documents.find(
+ (document) =>
+ document.id ===
+ linkId,
+ );
+ const alreadySelected =
+ ids.includes(linkId) ||
+ (!!uploaded &&
+ ids.some(
+ (id) =>
+ result.documents.find(
+ (
+ document,
+ ) =>
+ document.id ===
+ id,
+ )
+ ?.document_id ===
+ uploaded.document_id,
+ ));
+ return {
+ ...d,
+ payload: {
+ ...d.payload,
+ [key]:
+ alreadySelected ||
+ ids.length >=
+ (f.max_files ??
+ 1)
+ ? ids
+ : [
+ ...ids,
+ linkId,
+ ],
+ },
+ };
+ });
+ }}
+ />
+ {Object.entries(form.errors)
+ .filter(
+ ([path]) =>
+ path === `payload.${key}` ||
+ path.startsWith(`payload.${key}.`),
+ )
+ .map(([path, error]) => (
+
+ {error}
+
+ ))}
+
+ ) : ['multiselect', 'consent'].includes(f.type) ? (
+
+
+ form.setData('payload', {
+ ...form.data.payload,
+ [key]: value,
+ })
+ }
+ />
+ {Object.entries(form.errors)
+ .filter(
+ ([path]) =>
+ path === `payload.${key}` ||
+ path.startsWith(`payload.${key}.`),
+ )
+ .map(([path, error]) => (
+
+ {error}
+
+ ))}
+
) : (
{f.label}
@@ -392,7 +657,9 @@ export default function RequestPage({
key,
))
}
- value={form.data.payload[key] ?? ''}
+ value={deskScalar(
+ form.data.payload[key],
+ )}
onChange={(e) =>
form.setData('payload', {
...form.data.payload,
@@ -419,7 +686,9 @@ export default function RequestPage({
key,
))
}
- value={form.data.payload[key] ?? ''}
+ value={deskScalar(
+ form.data.payload[key],
+ )}
onChange={(e) =>
form.setData('payload', {
...form.data.payload,
@@ -449,7 +718,9 @@ export default function RequestPage({
key,
))
}
- value={form.data.payload[key] ?? ''}
+ value={deskScalar(
+ form.data.payload[key],
+ )}
onChange={(e) =>
form.setData('payload', {
...form.data.payload,
@@ -463,17 +734,27 @@ export default function RequestPage({
)}
{canEdit && (
<>
-
- Justificação de correcção
-
- form.setData('reason', e.target.value)
- }
- />
-
-
+ {request.status === 'returned' && (
+
+ Justificação de correcção
+
+ form.setData('reason', e.target.value)
+ }
+ />
+
+ )}
+
Guardar rascunho
@@ -490,8 +771,21 @@ export default function RequestPage({
{
+ if (
+ checkpointBusy ||
+ checkpointBlocked ||
+ filesBusy ||
+ !canEdit
+ )
+ return;
form.transform((d) => ({
...d,
version: request.version,
@@ -512,108 +806,228 @@ export default function RequestPage({
))}
- {!owner && (manager || analyst) && transitions.length > 0 && (
- {
- e.preventDefault();
- decision.transform((d) => ({
- ...d,
- version: request.version,
- }));
- decision.post(
- `/balcao-virtual/pedidos/${request.id}/estado`,
- );
- }}
- >
-
- Resposta / análise do responsável
-
-
- Estado
-
- decision.setData('status', e.target.value)
+ {operationsEditable &&
+ owner &&
+ ['draft', 'returned'].includes(request.status) && (
+ {
+ event.preventDefault();
+ if (
+ decision.processing ||
+ form.processing ||
+ checkpointBusy ||
+ filesBusy
+ )
+ return;
+ decision.transform((data) => ({
+ ...data,
+ version: request.version,
+ status: 'cancelled',
+ }));
+ decision.post(
+ `/balcao-virtual/pedidos/${request.id}/estado`,
+ {
+ onSuccess: (page) => {
+ const saved = page.props.request as
+ | typeof initialRequest
+ | undefined;
+ if (
+ saved?.id === request.id &&
+ saved.status === 'cancelled'
+ ) {
+ form.setData(
+ 'payload',
+ saved.payload,
+ );
+ form.setData(
+ 'version',
+ saved.version,
+ );
+ form.setData('reason', '');
+ form.setData('consent', false);
+ setRecoveredRequest(null);
+ }
+ },
+ },
+ );
+ }}
+ >
+
+ Cancelar este pedido
+
+
+ O cancelamento conserva a última versão guardada, os
+ documentos e o histórico. O dossier continua
+ disponível; alterações por guardar não são
+ submetidas.
+
+
+ Motivo do cancelamento
+
+ decision.setData(
+ 'reason',
+ event.target.value,
+ )
+ }
+ />
+
+
- {transitions
- .filter(
- (s) =>
- manager ||
- ![
- 'accepted',
- 'rejected',
- 'closed',
- ].includes(s),
- )
- .map((s) => (
-
- {states[s]}
-
- ))}
-
-
-
- Fundamento da resposta
-
- decision.setData('reason', e.target.value)
- }
- />
-
- {decision.data.status === 'returned' && (
-
- Campos autorizados para correcção
- {Object.entries({
- ...definition.fields,
- country: { label: 'País do requerente' },
- declared_origin_country_code: {
- label: 'Origem declarada da solicitação',
- },
- }).map(([k, f]) => (
-
-
+ {Object.entries(decision.errors).map(([key, error]) => (
+
+ {error}
+
+ ))}
+
+ )}
+ {operationsEditable &&
+ !owner &&
+ (manager || analyst) &&
+ transitions.length > 0 && (
+ {
+ e.preventDefault();
+ decision.transform((d) => ({
+ ...d,
+ version: request.version,
+ }));
+ decision.post(
+ `/balcao-virtual/pedidos/${request.id}/estado`,
+ );
+ }}
+ >
+
+ Resposta / análise do responsável
+
+
+ Estado
+
+ decision.setData('status', e.target.value)
+ }
+ >
+ {transitions
+ .filter(
+ (s) =>
+ manager ||
+ ![
+ 'accepted',
+ 'rejected',
+ 'closed',
+ ].includes(s),
+ )
+ .map((s) => (
+
+ {states[s]}
+
+ ))}
+
+
+
+ Fundamento da resposta
+
+ decision.setData('reason', e.target.value)
+ }
+ />
+
+ {decision.data.status === 'returned' && (
+
+ Devolução para correcção
+
+ Categoria do motivo (opcional, para
+ indicadores)
+
decision.setData(
- 'editable_fields',
- e.target.checked
- ? [
- ...decision.data
- .editable_fields,
- k,
- ]
- : decision.data.editable_fields.filter(
- (v) => v !== k,
- ),
+ 'return_reason_code',
+ e.target.value,
)
}
- />{' '}
- {f.label}
+ >
+ {Object.entries(returnReasons).map(
+ ([code, label]) => (
+
+ {label}
+
+ ),
+ )}
+
- ))}
-
- )}
-
- Registar resposta fundamentada
-
- {Object.entries(decision.errors).map(([k, v]) => (
-
- {v}
-
- ))}
-
- )}
- {manager &&
+ Campos autorizados para correcção
+ {Object.entries({
+ ...definition.fields,
+ country: { label: 'País do requerente' },
+ declared_origin_country_code: {
+ label: 'Origem declarada da solicitação',
+ },
+ }).map(([k, f]) => (
+
+
+ decision.setData(
+ 'editable_fields',
+ e.target.checked
+ ? [
+ ...decision.data
+ .editable_fields,
+ k,
+ ]
+ : decision.data.editable_fields.filter(
+ (v) => v !== k,
+ ),
+ )
+ }
+ />{' '}
+ {f.label}
+
+ ))}
+
+ )}
+
+ Registar resposta fundamentada
+
+ {Object.entries(decision.errors).map(([k, v]) => (
+
+ {v}
+
+ ))}
+
+ )}
+ {operationsEditable &&
+ manager &&
!['draft', 'closed', 'cancelled'].includes(request.status) && (
))}
- {!['closed', 'cancelled'].includes(request.status) && (
+ {operationsEditable && (
{
e.preventDefault();
@@ -750,7 +1164,7 @@ export default function RequestPage({
)}
- {!owner && (manager || analyst) && (
+ {operationsEditable && !owner && (manager || analyst) && (
)}
- {!['closed', 'cancelled'].includes(request.status) && (
-
- )}
+
Respostas e histórico
{events.map((e) => (
@@ -777,6 +1189,15 @@ export default function RequestPage({
{typeof e.payload.reason === 'string' && (
{e.payload.reason}
)}
+ {e.action === 'request_returned' && (
+
+ Categoria:{' '}
+ {typeof e.payload.return_reason_label ===
+ 'string'
+ ? e.payload.return_reason_label
+ : 'Sem classificação registada'}
+
+ )}
{[
'document_reviewed',
'payment_reviewed',
diff --git a/resources/js/pages/desk/service-editor.tsx b/resources/js/pages/desk/service-editor.tsx
index 2ece45b2..91818fba 100644
--- a/resources/js/pages/desk/service-editor.tsx
+++ b/resources/js/pages/desk/service-editor.tsx
@@ -9,7 +9,11 @@ export type Field = {
required: boolean;
min?: number;
options?: Record;
- when?: { field: string; equals: string };
+ statement?: string;
+ mime_types?: string[];
+ max_size_kb?: number;
+ max_files?: number;
+ when?: { field: string; equals: string; operator?: 'equals' | 'contains' };
};
export type Definition = {
title: string;
@@ -26,6 +30,9 @@ type Service = {
definition: Definition;
fixedTypes?: Record;
editable?: boolean;
+ effective_from?: string | null;
+ activeVersion?: number;
+ upcoming?: { version: number; effective_from: string }[];
};
const types: Record = {
text: 'Texto curto',
@@ -33,6 +40,9 @@ const types: Record = {
number: 'Número',
date: 'Data',
select: 'Lista de opções',
+ multiselect: 'Selecção múltipla',
+ consent: 'Declaração de consentimento',
+ attachment: 'Anexos de documentos autorizados',
territory: 'Localização do cadastro',
email: 'Email',
tel: 'Telefone',
@@ -51,6 +61,14 @@ function describeField(field: Field | undefined): string {
field.label,
types[field.type] ?? field.type,
field.required ? 'Obrigatório' : 'Opcional',
+ ...(field.statement ? [`Declaração: ${field.statement}`] : []),
+ ...(field.type === 'attachment'
+ ? [
+ `Formatos: ${field.mime_types?.join(', ')}`,
+ `Tamanho por ficheiro: ${field.max_size_kb} KiB`,
+ `Máximo de ficheiros: ${field.max_files}`,
+ ]
+ : []),
...(field.min !== undefined ? [`Mínimo: ${field.min}`] : []),
...(field.options
? [
@@ -60,12 +78,22 @@ function describeField(field: Field | undefined): string {
]
: []),
field.when
- ? `Aplica-se quando ${field.when.field} = ${field.when.equals}`
+ ? `Aplica-se quando ${field.when.field} ${field.when.operator === 'contains' ? 'inclui' : '='} ${field.when.equals}`
: 'Sempre aplicável',
].join(' · ');
}
-export default function ServiceEditor({ services }: { services: Service[] }) {
+export default function ServiceEditor({
+ services,
+ schedulingAvailable = false,
+ today = '',
+ calendarTimezone = '',
+}: {
+ services: Service[];
+ schedulingAvailable?: boolean;
+ today?: string;
+ calendarTimezone?: string;
+}) {
const [code, setCode] = useState(services[0]?.code ?? '');
const service = services.find((row) => row.code === code);
return (
@@ -103,6 +131,9 @@ export default function ServiceEditor({ services }: { services: Service[] }) {
) : !service ? (
Não existem serviços disponíveis para edição.
@@ -118,7 +149,17 @@ export default function ServiceEditor({ services }: { services: Service[] }) {
);
}
-function Editor({ service }: { service: Service }) {
+function Editor({
+ service,
+ schedulingAvailable = false,
+ today = '',
+ calendarTimezone = '',
+}: {
+ service: Service;
+ schedulingAvailable?: boolean;
+ today?: string;
+ calendarTimezone?: string;
+}) {
const form = useForm(
`desk-service-editor:${service.code}:${service.version}`,
{
@@ -126,11 +167,24 @@ function Editor({ service }: { service: Service }) {
definition: structuredClone(service.definition),
reason: '',
confirm: false,
+ effective_from:
+ schedulingAvailable &&
+ service.effective_from &&
+ service.effective_from > today
+ ? service.effective_from
+ : '',
},
);
const [newKey, setNewKey] = useState('');
const [localError, setLocalError] = useState('');
const fields = form.data.definition.fields;
+ const dateChanged =
+ schedulingAvailable &&
+ (form.data.effective_from
+ ? form.data.effective_from !== (service.effective_from ?? '')
+ : Boolean(
+ service.effective_from && service.effective_from > today,
+ ));
const setFields = (value: Record) =>
form.setData((data) => ({
...data,
@@ -202,6 +256,67 @@ function Editor({ service }: { service: Service }) {
Etapa do percurso existente: {service.definition.stage}.
Este editor não altera a sequência de tramitação.
+
+ Base de edição: última versão publicada, {service.version}.
+ Versão actualmente disponível para novos pedidos:{' '}
+ {(service.activeVersion ?? service.version) || 'nenhuma'}.
+ Entrada em vigor da base:{' '}
+ {service.effective_from ||
+ 'sem data explícita (versão histórica)'}
+ .
+
+ {Boolean(service.upcoming?.length) && (
+
+
+ Edições já agendadas que se aplicarão nas
+ respectivas datas:
+
+
+ {service.upcoming!.map((edition) => (
+
+ Versão {edition.version}:{' '}
+ {edition.effective_from}.
+
+ ))}
+
+
+ Uma correcção imediata não cancela estas datas. Para
+ substituir uma edição futura, publique a correcção
+ com a mesma data de início.
+
+
+ )}
+ {schedulingAvailable ? (
+
+ Data de entrada em vigor da nova versão
+
+ form.setData((data) => ({
+ ...data,
+ confirm: false,
+ effective_from: event.target.value,
+ }))
+ }
+ />
+
+ Vazio significa a data da publicação. Calendário do
+ portal
+ {calendarTimezone ? `: ${calendarTimezone}` : ''}.
+ Versões futuras não substituem a versão actual antes
+ dessa data.
+
+
+ ) : (
+
+ O agendamento requer a actualização das datas de entrada
+ em vigor neste destino. A publicação imediata existente
+ continua disponível.
+
+ )}
@@ -240,14 +355,54 @@ function Editor({ service }: { service: Service }) {
...field,
type: event.target.value,
};
- if (next.type !== 'select')
+ if (
+ !['select', 'multiselect'].includes(
+ next.type,
+ )
+ )
delete next.options;
else
next.options ??= {
opcao_1: 'Primeira opção',
};
if (next.type !== 'number') delete next.min;
- setFields({ ...fields, [key]: next });
+ if (next.type !== 'consent')
+ delete next.statement;
+ else next.statement ??= '';
+ if (next.type === 'attachment') {
+ next.mime_types ??= [
+ 'application/pdf',
+ 'image/png',
+ 'image/jpeg',
+ 'text/plain',
+ ];
+ next.max_size_kb ??= 10240;
+ next.max_files ??= 1;
+ } else {
+ delete next.mime_types;
+ delete next.max_size_kb;
+ delete next.max_files;
+ }
+ const changedFields = {
+ ...fields,
+ [key]: next,
+ };
+ for (const [
+ dependentKey,
+ dependent,
+ ] of Object.entries(changedFields)) {
+ if (dependent.when?.field !== key)
+ continue;
+ const when = { ...dependent.when };
+ if (next.type === 'multiselect')
+ when.operator = 'contains';
+ else delete when.operator;
+ changedFields[dependentKey] = {
+ ...dependent,
+ when,
+ };
+ }
+ setFields(changedFields);
}}
>
{Object.entries(types).map(([value, label]) => (
@@ -293,7 +448,118 @@ function Editor({ service }: { service: Service }) {
/>
)}
- {field.type === 'select' && (
+ {field.type === 'attachment' && (
+
+
+ Limites dos documentos desta pergunta
+
+
+ Aplicam-se à versão publicada e aos novos
+ pedidos que a utilizarem. Pedidos anteriores
+ conservam os seus limites.
+
+ {Object.entries({
+ 'application/pdf': 'PDF',
+ 'image/png': 'Imagem PNG',
+ 'image/jpeg': 'Imagem JPEG',
+ 'text/plain': 'Texto simples',
+ }).map(([mime, label]) => (
+
+
+ update(key, {
+ mime_types: event.target
+ .checked
+ ? [
+ ...(field.mime_types ??
+ []),
+ mime,
+ ]
+ : (
+ field.mime_types ??
+ []
+ ).filter(
+ (value) =>
+ value !==
+ mime,
+ ),
+ })
+ }
+ />{' '}
+ {label}
+
+ ))}
+
+ Máximo por ficheiro (KB)
+
+ update(key, {
+ max_size_kb: Number(
+ event.target.value,
+ ),
+ })
+ }
+ />
+
+
+ Máximo de ficheiros seleccionados
+
+ update(key, {
+ max_files: Number(
+ event.target.value,
+ ),
+ })
+ }
+ />
+
+
+ )}
+ {field.type === 'consent' && (
+
+ Texto exacto da declaração
+
+ update(key, {
+ statement: event.target.value,
+ })
+ }
+ />
+
+ A pessoa escolhe aceitar ou recusar;
+ obrigatório exige uma resposta explícita.
+ Esta escolha não substitui o consentimento
+ da submissão nem concede permissões ou
+ validação oficial.
+
+
+ )}
+ {['select', 'multiselect'].includes(field.type) && (
Opções de resposta
{Object.entries(field.options ?? {}).map(
@@ -370,17 +636,40 @@ function Editor({ service }: { service: Service }) {
next.when = {
field: event.target.value,
equals: '',
+ ...(fields[event.target.value]
+ ?.type === 'multiselect'
+ ? {
+ operator:
+ 'contains' as const,
+ }
+ : {}),
};
else delete next.when;
setFields({ ...fields, [key]: next });
}}
>
Sempre
+ {field.when &&
+ (!fields[field.when.field] ||
+ ['number', 'attachment'].includes(
+ fields[field.when.field].type,
+ )) && (
+
+ Origem indisponível para esta
+ condição; escolha outra resposta ou
+ «Sempre»
+
+ )}
{Object.entries(fields)
.filter(
([other, source]) =>
other !== key &&
- source.type !== 'number',
+ !['number', 'attachment'].includes(
+ source.type,
+ ),
)
.map(([other, value]) => (
@@ -393,7 +682,9 @@ function Editor({ service }: { service: Service }) {
{field.when && (
Resposta que torna o campo aplicável
- {fields[field.when.field]?.type === 'select' ? (
+ {['select', 'multiselect', 'consent'].includes(
+ fields[field.when.field]?.type,
+ ) ? (
update(key, {
when: {
+ ...field.when!,
field: field.when!.field,
equals: event.target.value,
},
@@ -411,8 +703,14 @@ function Editor({ service }: { service: Service }) {
Seleccionar resposta
{Object.entries(
- fields[field.when.field].options ??
- {},
+ fields[field.when.field].type ===
+ 'consent'
+ ? {
+ accepted: 'Aceite',
+ declined: 'Recusado',
+ }
+ : (fields[field.when.field]
+ .options ?? {}),
).map(([value, label]) => (
{label}
@@ -552,6 +850,20 @@ function Editor({ service }: { service: Service }) {
e submissões anteriores continuam vinculados à sua definição
original; as respectivas respostas não são reescritas.
+ {schedulingAvailable && (
+
+ Entrada em vigor proposta:{' '}
+ {form.data.effective_from ||
+ today ||
+ 'na data da publicação'}
+ {dateChanged ? ' (alterada)' : ''}. Para cada serviço,
+ aplica-se a data de início já atingida mais recente; na
+ mesma data, prevalece a versão mais elevada. As versões
+ históricas sem data são usadas enquanto não existir uma
+ edição com início aplicável. Uma correcção para hoje não
+ cancela uma edição já agendada para uma data posterior.
+
+ )}
Motivo da alteração
0 &&
changed.length === 0 &&
- metaChanges.length === 0)
+ metaChanges.length === 0 &&
+ !dateChanged)
}
>
{form.processing ? 'A publicar…' : 'Publicar nova versão'}
diff --git a/resources/js/pages/education/declaration.tsx b/resources/js/pages/education/declaration.tsx
new file mode 100644
index 00000000..9ce5687f
--- /dev/null
+++ b/resources/js/pages/education/declaration.tsx
@@ -0,0 +1,154 @@
+import { Link } from '@inertiajs/react';
+import EducationReview from '@/components/education-review';
+import type { EducationReviewProps } from '@/lib/education-review';
+import { Management, Pagination } from '../management/shared';
+import type { Paginated } from '../management/shared';
+
+type ReviewEntry = {
+ id: string;
+ version: number | null;
+ actor: string | null;
+ occurred_at: string;
+ available: boolean;
+ status: 'reviewed' | 'rejected' | null;
+ reason: string | null;
+ previous_reason: string | null;
+};
+export default function Declaration(
+ props: EducationReviewProps & {
+ backUrl: string;
+ references: Record;
+ history?: Paginated;
+ },
+) {
+ const row = props.declaration;
+ const labels: Record = {
+ occupation: 'Ocupação',
+ skill: 'Competência',
+ location: 'Localização',
+ project: 'Projecto',
+ course: 'Curso',
+ };
+ return (
+
+
+ Voltar às declarações
+
+
+
+ {row.qualification}
+
+
+ {row.quantity}{' '}
+ {props.kind === 'demands'
+ ? 'trabalhadores'
+ : 'vagas formativas'}{' '}
+ · {row.period_start} a {row.period_end}
+
+
+ Fonte válida até {row.valid_until}
+ {row.valid_until < props.today ? ' · Expirada' : ''}
+
+ {row.reference_date && (
+ Data de referência: {row.reference_date}
+ )}
+ {props.kind === 'demands' && row.employer && (
+ Empregador declarado: {row.employer}
+ )}
+
+ Fonte: {row.source}
+
+ {!!Object.keys(props.references).length && (
+
+ Referências no cadastro actual
+
+ )}
+ {Object.entries(props.references).map(([field, value]) => (
+
+ {labels[field] ?? field}:{' '}
+ {value || 'Não identificado no cadastro actual'}
+
+ ))}
+ {row.submitted_by_name && (
+ Submetida por {row.submitted_by_name}
+ )}
+ {row.reviewed_by_name && (
+ Revisão actual por {row.reviewed_by_name}
+ )}
+ {row.review_reason && (
+
+ Último fundamento registado: {row.review_reason}
+
+ )}
+ {props.kind === 'demands' && (
+
+ Analisar procura e oferta
+
+ )}
+
+
+ {props.history && (
+
+
+ Registos de revisão disponíveis
+
+
+ Os registos anteriores à preservação dos fundamentos
+ podem não estar disponíveis.
+
+ {!props.history.data.length && (
+ Sem registos de revisão preservados.
+ )}
+ {props.history.data.map((entry) => (
+
+
+ Versão {entry.version ?? 'não identificada'} ·{' '}
+ {entry.actor ?? 'Autor não identificado'}
+
+ {entry.occurred_at}
+ {entry.available ? (
+ <>
+
+ {entry.status === 'reviewed'
+ ? 'Revista'
+ : 'Rejeitada'}
+
+
+ Fundamento: {entry.reason}
+
+ {entry.previous_reason && (
+
+ Fundamento anterior capturado:{' '}
+ {entry.previous_reason}
+
+ )}
+ >
+ ) : (
+
+ Fundamento indisponível para leitura. O
+ registo original foi preservado.
+
+ )}
+
+ ))}
+
+
+ )}
+
+ );
+}
diff --git a/resources/js/pages/education/index.tsx b/resources/js/pages/education/index.tsx
index 3b370063..c956b611 100644
--- a/resources/js/pages/education/index.tsx
+++ b/resources/js/pages/education/index.tsx
@@ -1,5 +1,14 @@
-import { Link, useForm } from '@inertiajs/react';
-import { useState } from 'react';
+import { Link, router, useForm } from '@inertiajs/react';
+import { useCallback, useEffect, useState } from 'react';
+import {
+ portalRequest,
+ PortalApiError,
+ newSubmissionKey,
+} from '@/lib/portal-api';
+import EducationSubmittedSnapshot, {
+ type EducationDraft,
+ type EducationDraftSummary,
+} from '@/components/education-submitted-snapshot';
import {
Management,
Field,
@@ -23,8 +32,28 @@ type RecordRow = {
period_start: string;
period_end: string;
source: string;
+ can_review?: boolean;
+ review_unavailable?: 'self' | 'expired' | null;
+ details_url?: string;
+};
+type WorkCounts = {
+ total: number;
+ submitted: number;
+ reviewed: number;
+ rejected: number;
+ expired: number;
+ to_review: number;
};
type Props = {
+ workQueue?: {
+ actor_id: number;
+ drafts: number | null;
+ demands: WorkCounts;
+ capacities: WorkCounts;
+ };
+ draftsAvailable?: boolean;
+ selectedDraft?: EducationDraft | null;
+ ownDrafts?: Paginated | null;
demands: Paginated;
capacities: Paginated;
skills: Option[];
@@ -34,7 +63,12 @@ type Props = {
projects: Option[];
territories: TerritoryOption[];
today: string;
- filters: { q?: string; status?: string; geo_location_id?: string };
+ filters: {
+ q?: string;
+ status?: string;
+ geo_location_id?: string;
+ scope?: 'all' | 'mine' | 'review';
+ };
indicators: {
demand_records: number;
capacity_records: number;
@@ -92,6 +126,11 @@ function Select({
required
>
Seleccione
+ {value && !options.some((option) => option.id === value) && (
+
+ Selecção guardada não incluída nesta lista
+
+ )}
{options.map((o) => (
{o.code ? `${o.code} — ` : ''}
@@ -169,32 +208,111 @@ function Catalog({
);
}
-function Intake({
+export function Intake({
kind,
props,
+ onSaved,
+ onDirty,
}: {
kind: 'demands' | 'capacities';
props: Props;
+ onSaved?: (draft: EducationDraft) => void;
+ onDirty?: (kind: 'demands' | 'capacities', dirty: boolean) => void;
}) {
const demand = kind === 'demands';
+ const initial =
+ props.selectedDraft?.kind === kind ? props.selectedDraft : null;
+ const [active, setActive] = useState(initial);
+ const [clientKey] = useState(newSubmissionKey);
+ const [draftBusy, setDraftBusy] = useState(false);
+ const [draftMessage, setDraftMessage] = useState('');
+ const [draftError, setDraftError] = useState('');
+ const [initialPath] = useState(() =>
+ territoryPath(
+ String(initial?.payload.geo_location_id ?? ''),
+ props.territories,
+ ),
+ );
const [territoryResetKey, setTerritoryResetKey] = useState(0);
const form = useForm({
- project_id: '',
- course_id: '',
- occupation_id: '',
- skill_id: '',
- geo_location_id: '',
- employer: '',
- qualification: '',
- quantity: '',
- period_start: '',
- period_end: '',
- source: '',
- reference_date: props.today,
- valid_until: '',
+ project_id: String(initial?.payload.project_id ?? ''),
+ course_id: String(initial?.payload.course_id ?? ''),
+ occupation_id: String(initial?.payload.occupation_id ?? ''),
+ skill_id: String(initial?.payload.skill_id ?? ''),
+ geo_location_id: String(initial?.payload.geo_location_id ?? ''),
+ employer: String(initial?.payload.employer ?? ''),
+ qualification: String(initial?.payload.qualification ?? ''),
+ quantity: String(initial?.payload.quantity ?? ''),
+ period_start: String(initial?.payload.period_start ?? ''),
+ period_end: String(initial?.payload.period_end ?? ''),
+ source: String(initial?.payload.source ?? ''),
+ reference_date: initial
+ ? String(initial.payload.reference_date ?? '')
+ : props.today,
+ valid_until: String(initial?.payload.valid_until ?? ''),
});
+ useEffect(
+ () => onDirty?.(kind, form.isDirty),
+ [onDirty, kind, form.isDirty],
+ );
+ async function persist(submit = false) {
+ if (draftBusy) return;
+ setDraftBusy(true);
+ setDraftMessage('');
+ setDraftError('');
+ form.clearErrors();
+ const payload = { ...form.data };
+ try {
+ const url =
+ `/management/education/drafts/${kind}` +
+ (active ? `/${active.id}` : '') +
+ (submit ? '/submit' : '');
+ const saved = await portalRequest(url, {
+ method: submit || !active ? 'POST' : 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ version_no: active?.version_no ?? 0,
+ client_key: clientKey,
+ payload,
+ }),
+ });
+ setActive(saved);
+ form.setDefaults(payload);
+ onSaved?.(saved);
+ setDraftMessage(
+ submit
+ ? 'Declaração submetida para revisão independente.'
+ : 'Rascunho privado guardado. Pode recuperá-lo na sua lista.',
+ );
+ } catch (failure) {
+ if (failure instanceof PortalApiError) {
+ form.setError(
+ Object.fromEntries(
+ Object.entries(failure.errors).map(
+ ([key, messages]) => [
+ key,
+ messages[0] ?? failure.message,
+ ],
+ ),
+ ),
+ );
+ setDraftError(
+ failure.status === 409
+ ? 'O rascunho foi alterado noutra sessão. As suas edições continuam neste formulário; abra a versão guardada antes de tentar novamente.'
+ : failure.message,
+ );
+ } else
+ setDraftError(
+ 'Não foi possível guardar. As suas edições continuam neste formulário.',
+ );
+ } finally {
+ setDraftBusy(false);
+ }
+ }
+ if (active?.state === 'submitted')
+ return ;
return (
-
+
{demand
? 'Declarar procura de trabalhadores'
@@ -204,6 +322,10 @@ function Intake({
className="mt-4 grid gap-4 md:grid-cols-2"
onSubmit={(e) => {
e.preventDefault();
+ if (active) {
+ void persist(true);
+ return;
+ }
form.post(`/management/education/${kind}`, {
onSuccess: () => {
form.reset();
@@ -212,125 +334,176 @@ function Intake({
});
}}
>
-
- form.setData(demand ? 'project_id' : 'course_id', v)
- }
- />
- form.setData('occupation_id', v)}
- />
- form.setData('skill_id', v)}
- />
-
-
- form.setData(
- 'geo_location_id',
- path[path.length - 1]?.id ?? '',
- )
+
+
+ form.setData(demand ? 'project_id' : 'course_id', v)
}
/>
-
- {demand && (
-
+ form.setData('occupation_id', v)}
+ />
+ form.setData('skill_id', v)}
+ />
+
+ {initial?.payload.geo_location_id &&
+ form.data.geo_location_id ===
+ initial.payload.geo_location_id &&
+ initialPath.length === 0 && (
+
+ O local guardado já não consta do cadastro
+ disponível. A referência foi conservada;
+ escolha uma localização actual antes de
+ submeter.
+
+ )}
+
+ form.setData(
+ 'geo_location_id',
+ path[path.length - 1]?.id ?? '',
+ )
+ }
+ />
+
+ {demand && (
+
+
+ form.setData('employer', e.target.value)
+ }
+ />
+
+ )}
+
- form.setData('employer', e.target.value)
+ form.setData('qualification', e.target.value)
}
/>
- )}
-
-
- form.setData('qualification', e.target.value)
- }
- />
-
-
-
- form.setData('quantity', e.target.value)
- }
- />
-
- {(
- [
- 'period_start',
- 'period_end',
- 'reference_date',
- 'valid_until',
- ] as const
- ).map((key) => (
form.setData(key, e.target.value)}
+ value={form.data.quantity}
+ onChange={(e) =>
+ form.setData('quantity', e.target.value)
+ }
/>
- ))}
-
- form.setData('source', e.target.value)}
- />
-
-
-
-
- Submeter para revisão
-
-
+ {(
+ [
+ 'period_start',
+ 'period_end',
+ 'reference_date',
+ 'valid_until',
+ ] as const
+ ).map((key) => (
+
+
+ form.setData(key, e.target.value)
+ }
+ />
+
+ ))}
+
+
+ form.setData('source', e.target.value)
+ }
+ />
+
+
+
+ {draftError &&
{draftError}
}
+ {draftMessage &&
{draftMessage}
}
+ {props.draftsAvailable && (
+ <>
+
+ Guardar rascunho conserva informação
+ incompleta apenas na sua conta; ainda não
+ declara trabalhadores ou vagas para análise.
+
+
void persist()}
+ >
+ Guardar rascunho
+
+ {active && (
+
+ Rascunho guardado na versão{' '}
+ {active.version_no}. A submissão usa os
+ campos actuais deste formulário.
+
+ )}
+ >
+ )}
+
+ Submeter para revisão
+
+
+
);
@@ -344,11 +517,6 @@ function Review({
kind: string;
today: string;
}) {
- const form = useForm({
- version_no: row.version_no,
- status: 'reviewed',
- review_reason: '',
- });
return (
@@ -361,72 +529,98 @@ function Review({
? 'Fonte expirada'
: (
{
- submitted: 'Submetido',
- reviewed: 'Revisto internamente',
- rejected: 'Rejeitado',
+ submitted: 'Submetida',
+ reviewed: 'Revista internamente',
+ rejected: 'Rejeitada',
} as Record
)[row.status]}
Fonte: {row.source}
- {kind === 'demands' && (
-
- Analisar procura e oferta
+ {row.review_unavailable === 'self' && (
+ Submetida por si; a revisão cabe a outro gestor.
+ )}
+ {row.details_url && (
+
+ {row.can_review
+ ? 'Consultar e rever'
+ : 'Consultar declaração'}
)}
-
- Revisão independente
- {
- e.preventDefault();
- form.transform((data) => ({
- ...data,
- version_no: row.version_no,
- }));
- form.post(
- `/management/education/${kind}/${row.id}/review`,
- );
- }}
- >
-
-
- form.setData('status', e.target.value)
- }
- >
- Registar revisão
-
- Rejeitar declaração
-
-
-
-
-
- form.setData('review_reason', e.target.value)
- }
- />
-
-
-
- Guardar decisão
-
-
-
);
}
export default function Index(props: Props) {
+ const [savedHere, setSavedHere] = useState([]);
+ const [dirtyForms, setDirtyForms] = useState({
+ demands: false,
+ capacities: false,
+ });
+ const markDirty = useCallback(
+ (kind: 'demands' | 'capacities', dirty: boolean) => {
+ setDirtyForms((current) =>
+ current[kind] === dirty
+ ? current
+ : { ...current, [kind]: dirty },
+ );
+ },
+ [],
+ );
+ const saved = useCallback((draft: EducationDraft) => {
+ setSavedHere((current) => [
+ {
+ id: draft.id,
+ kind: draft.kind,
+ version_no: draft.version_no,
+ state: draft.state,
+ updated_at: draft.updated_at,
+ label: String(draft.payload.qualification ?? ''),
+ },
+ ...current.filter((item) => item.id !== draft.id),
+ ]);
+ if (draft.state === 'submitted')
+ router.reload({
+ only: [
+ 'demands',
+ 'capacities',
+ 'indicators',
+ 'ownDrafts',
+ 'workQueue',
+ ],
+ });
+ }, []);
+ const unsaved = dirtyForms.demands || dirtyForms.capacities;
+ useEffect(() => {
+ const warn = (event: BeforeUnloadEvent) => {
+ if (unsaved) {
+ event.preventDefault();
+ event.returnValue = '';
+ }
+ };
+ window.addEventListener('beforeunload', warn);
+ const unsubscribe = router.on('before', (event) => {
+ if (
+ unsaved &&
+ event.detail.visit.method === 'get' &&
+ event.detail.visit.preserveState !== true &&
+ !window.confirm(
+ 'Há alterações por guardar nos formulários de Educação. Pretende sair sem as guardar?',
+ )
+ )
+ event.preventDefault();
+ });
+ return () => {
+ window.removeEventListener('beforeunload', warn);
+ unsubscribe();
+ };
+ }, [unsaved]);
+ const ownDrafts = [
+ ...savedHere,
+ ...(props.ownDrafts?.data ?? []).filter(
+ (item) => !savedHere.some((saved) => saved.id === item.id),
+ ),
+ ];
const search = useForm({
+ scope: props.filters.scope ?? 'all',
q: props.filters.q ?? '',
status: props.filters.status ?? '',
geo_location_id: props.filters.geo_location_id ?? '',
@@ -464,6 +658,54 @@ export default function Index(props: Props) {
filtros. Não representam totais de trabalhadores, lacunas
validadas ou resultados educativos.
+ {props.workQueue && (
+
+
+ O meu acompanhamento
+
+
+ Contagens das minhas declarações, em todos os filtros.
+
+ {props.workQueue.drafts !== null && (
+
+ Rascunhos privados por concluir:{' '}
+ {props.workQueue.drafts}
+
+ )}
+
+ {(['demands', 'capacities'] as const).map((kind) => {
+ const counts = props.workQueue?.[kind];
+ if (!counts) return null;
+ return (
+
+
+ {kind === 'demands'
+ ? 'Declarações de procura'
+ : 'Declarações de capacidade formativa'}
+
+ Submetidas por mim: {counts.total}
+
+ Por rever, com fonte vigente:{' '}
+ {counts.submitted}
+
+
+ Revistas: {counts.reviewed} ·
+ Rejeitadas: {counts.rejected} · Fonte
+ expirada: {counts.expired}
+
+
+ Disponíveis para a minha revisão
+ independente: {counts.to_review}
+
+
+ );
+ })}
+
+
+ )}
{
@@ -473,6 +715,31 @@ export default function Index(props: Props) {
});
}}
>
+
+
+ search.setData({
+ ...search.data,
+ scope: event.target.value as
+ | 'all'
+ | 'mine'
+ | 'review',
+ status:
+ event.target.value === 'review'
+ ? ''
+ : search.data.status,
+ })
+ }
+ >
+ Todas as declarações
+ Submetidas por mim
+
+ Disponíveis para revisão independente
+
+
+
search.setData('q', e.target.value)}
/>
-
-
- search.setData('status', e.target.value)
- }
- >
- Todos
-
- Por rever, fonte vigente
-
- Revisto, fonte vigente
-
- Rejeitado, fonte vigente
-
- Fonte expirada
-
-
+ {search.data.scope !== 'review' && (
+
+
+ search.setData('status', e.target.value)
+ }
+ >
+ Todos
+
+ Por rever, fonte vigente
+
+
+ Revisto, fonte vigente
+
+
+ Rejeitado, fonte vigente
+
+ Fonte expirada
+
+
+ )}
))}
-
-
+ {props.draftsAvailable && (
+
+
+ Os meus rascunhos e submissões
+
+
+ Estes registos pertencem apenas à sua conta. Rascunhos
+ incompletos não entram nos indicadores de trabalhadores
+ ou vagas.
+
+
+ Iniciar outra declaração
+
+ {ownDrafts.length === 0 && (
+ Ainda não guardou rascunhos.
+ )}
+
+ {ownDrafts.map((item) => (
+
+
+ {item.kind === 'demands'
+ ? 'Procura de trabalhadores'
+ : 'Capacidade formativa'}{' '}
+ —{' '}
+ {item.state === 'submitted'
+ ? 'submetida'
+ : 'rascunho'}
+ , versão {item.version_no}
+ {item.label
+ ? ` — ${item.label}`
+ : ''} —{' '}
+ {new Date(item.updated_at).toLocaleString(
+ 'pt-MZ',
+ )}
+
+
+ ))}
+
+ {props.ownDrafts && }
+
+ )}
+
+
{(['demands', 'capacities'] as const).map((kind) => (
diff --git a/resources/js/pages/funding/show.tsx b/resources/js/pages/funding/show.tsx
index 44bb878e..740747d6 100644
--- a/resources/js/pages/funding/show.tsx
+++ b/resources/js/pages/funding/show.tsx
@@ -1,19 +1,8 @@
import { Link, router } from '@inertiajs/react';
-import { useState } from 'react';
-import { portalRequest } from '@/lib/portal-api';
+import FundingCriteriaAssessment from '@/components/funding-criteria-assessment';
import { Frame, card, button } from '@/pages/investment/shared';
import { type Programme, windowLabels } from './shared';
-type Assessment = {
- notice: string;
- criteria: { code: string; status: string }[];
-};
-const statusLabels: Record = {
- matches: 'Corresponde à resposta esperada',
- does_not_match: 'Não corresponde à resposta esperada',
- unknown: 'Informação por confirmar',
- not_applicable: 'Não aplicável ao tipo de candidato indicado',
-};
export default function Show({
record,
saved,
@@ -23,50 +12,7 @@ export default function Show({
saved: { version: number; saved_at: string } | null;
authenticated: boolean;
}) {
- const [kind, setKind] = useState('unknown');
- const [windowCode, setWindowCode] = useState('');
- const [answers, setAnswers] = useState>({});
- const [assessment, setAssessment] = useState(null);
- const [error, setError] = useState('');
- const [busy, setBusy] = useState(false);
const payload = record.payload;
- const window = payload.windows.find((item) => item.code === windowCode);
- const criteria = [...payload.criteria, ...(window?.criteria ?? [])];
- async function assess() {
- setBusy(true);
- setError('');
- setAssessment(null);
- try {
- setAssessment(
- await portalRequest(
- `/fundos/${record.id}/criterios`,
- {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- version_id: record.version_id,
- applicant_kind: kind,
- window_code: windowCode || null,
- answers: Object.fromEntries(
- criteria.map((c) => [
- c.code,
- answers[c.code] ?? 'unknown',
- ]),
- ),
- }),
- },
- ),
- );
- } catch (failure) {
- setError(
- failure instanceof Error
- ? failure.message
- : 'Não foi possível conferir os critérios.',
- );
- } finally {
- setBusy(false);
- }
- }
return (
@@ -167,103 +113,10 @@ export default function Show({
))}
-
-
- Conferir critérios documentados
-
-
- Esta consulta não envia candidatura nem concede
- financiamento. As respostas não ficam guardadas.
-
-
- Tipo de candidato
- {
- setKind(e.target.value);
- setAssessment(null);
- }}
- >
- Por definir
- Pessoa singular
- Entidade
-
-
-
- Janela
- {
- setWindowCode(e.target.value);
- setAssessment(null);
- }}
- >
- Apenas critérios gerais
- {payload.windows.map((item) => (
-
- {item.title}
-
- ))}
-
-
- {criteria.length === 0 && (
-
- Esta ficha não contém critérios suficientes para
- conferir a correspondência.
-
- )}
- {criteria.map((criterion) => (
-
-
- {criterion.question}
- {
- setAnswers({
- ...answers,
- [criterion.code]: e.target.value,
- });
- setAssessment(null);
- }}
- >
-
- Não sei / por confirmar
-
- Sim
- Não
-
-
-
{criterion.explanation}
-
Fonte: {criterion.source_reference}
- {assessment && (
-
- {
- statusLabels[
- assessment.criteria.find(
- (c) => c.code === criterion.code,
- )?.status ?? 'unknown'
- ]
- }
-
- )}
-
- ))}
- void assess()}
- >
- {busy ? 'A conferir…' : 'Conferir respostas'}
-
- {error && {error}
}
- {assessment && {assessment.notice}
}
-
+
{payload.documents.length > 0 && (
Documentos associados
diff --git a/resources/js/pages/investment/business-marketplace.tsx b/resources/js/pages/investment/business-marketplace.tsx
index f1cc2459..65985975 100644
--- a/resources/js/pages/investment/business-marketplace.tsx
+++ b/resources/js/pages/investment/business-marketplace.tsx
@@ -6,6 +6,11 @@ import {
type TerritoryOption,
} from '@/components/investment-territory';
import { businessModalities } from './business-types';
+import {
+ BusinessDistance,
+ GeographicCoverage,
+ type BusinessGeographicCoverage,
+} from '@/components/similar-businesses';
import {
ClassificationSummary,
type PublicClassification,
@@ -25,6 +30,10 @@ type PublicBusiness = {
currency?: string | null;
sector?: { name: string; slug: string } | null;
province?: string | null;
+ distance_km?: number | null;
+ location_recorded_at?: string | null;
+ location_source_reference?: string | null;
+ location_source_date?: string | null;
};
type PaginationLink = { url: string | null; label: string; active: boolean };
type Props = {
@@ -52,6 +61,7 @@ type Props = {
locality_id?: string;
};
territorySelection?: TerritoryOption[];
+ geographicCoverage?: BusinessGeographicCoverage | null;
};
export default function BusinessMarketplace({
@@ -60,7 +70,20 @@ export default function BusinessMarketplace({
territorySelection = [],
classificationOptions,
authorities = [],
+ geographicCoverage,
}: Props) {
+ const [radiusSelection, setRadiusSelection] = useState({
+ origin: filters.near_business,
+ value: filters.radius_km ?? '',
+ });
+ const radius =
+ radiusSelection.origin === filters.near_business
+ ? radiusSelection.value
+ : (filters.radius_km ?? '');
+ const proximity =
+ filters.near_business && radius
+ ? { near_business: filters.near_business, radius_km: radius }
+ : {};
const [classification, setClassification] = useState<
Record
>(() =>
@@ -85,12 +108,15 @@ export default function BusinessMarketplace({
admin_post_id: filters.admin_post_id ?? '',
locality_id: filters.locality_id ?? '',
});
- const returnQuery = new URLSearchParams({
- ...(query ? { q: query } : {}),
- ...(modality ? { modality } : {}),
- ...territory,
- ...classification,
- }).toString();
+ // Detail links describe the results actually retrieved, even while the next search is being edited.
+ const returnQuery = new URLSearchParams(
+ Object.fromEntries(
+ Object.entries(filters).filter(
+ (entry): entry is [string, string] =>
+ entry[1] !== undefined && entry[1] !== '',
+ ),
+ ),
+ ).toString();
const paginationLinks =
results.meta?.links ??
(Array.isArray(results.links) ? results.links : []);
@@ -111,11 +137,44 @@ export default function BusinessMarketplace({
modality: modality || undefined,
...territory,
...classification,
+ ...proximity,
},
{ preserveState: true, preserveScroll: true },
);
}}
>
+ {filters.near_business && (
+
+
+ Distância a partir da ficha de referência
+
+
+ Raio em km (0,1 a 2000)
+
+ setRadiusSelection({
+ origin: filters.near_business,
+ value: event.target.value,
+ })
+ }
+ />
+
+
+ Referência:{' '}
+ {geographicCoverage?.origin_title ??
+ 'ficha pública seleccionada'}
+ . Limpar o raio retira o filtro de distância na
+ próxima pesquisa. Um filtro territorial adicional
+ restringe também os resultados.
+
+
+ )}
Pesquisar negócios
@@ -290,6 +349,16 @@ export default function BusinessMarketplace({
)}
Pesquisar
+ {geographicCoverage && (
+
+ )}
+ {results.data.length === 0 && (
+
+ Não foram encontradas fichas públicas com estes critérios. A
+ cobertura do catálogo não demonstra ausência de negócios no
+ mercado.
+
+ )}
{results.data.map((record) => (
@@ -297,6 +366,7 @@ export default function BusinessMarketplace({
{businessModalities[record.modality] ??
'Modalidade por indicar'}
+
)}
+
{(record.amount_min || record.amount_max) && (
Montante indicativo: {record.amount_min ?? '—'} –{' '}
@@ -128,16 +136,19 @@ export default function BusinessOpportunity({
currentId={record.id}
classifications={record.multidimensional}
catalogueUrl={similarCatalogueUrl}
- criteria={[
- businessModalities[record.modality] ?? record.modality,
- ...(record.sector ? [record.sector.name] : []),
- ...(record.province &&
+ radiusAvailable={similarRadiusAvailable}
+ areaLabel={
+ record.province &&
new URL(
similarCatalogueUrl,
'https://portal.invalid',
).searchParams.has('province_id')
- ? [record.province]
- : []),
+ ? record.province
+ : undefined
+ }
+ criteria={[
+ businessModalities[record.modality] ?? record.modality,
+ ...(record.sector ? [record.sector.name] : []),
]}
/>
)}
diff --git a/resources/js/pages/investment/business-wizard.tsx b/resources/js/pages/investment/business-wizard.tsx
index 7e5b2319..aaff8fa3 100644
--- a/resources/js/pages/investment/business-wizard.tsx
+++ b/resources/js/pages/investment/business-wizard.tsx
@@ -6,6 +6,9 @@ import type { Business } from './business-types';
import { businessModalities } from './business-types';
import BusinessObjects from './business-objects';
import type { BusinessObject } from './business-objects';
+import BusinessPointSummary, {
+ type RegisteredBusinessLocation,
+} from '@/components/business-point-summary';
import {
decodeBusinessLocations,
emptyBusinessLocation,
@@ -13,6 +16,8 @@ import {
hasDuplicateBusinessLocationPath,
locationPathFromPayload,
updateBusinessLocation,
+ businessPointTerritoryKey,
+ businessPointRequiredFields,
} from '../../lib/business-locations';
export type FormSchema = Record<
@@ -36,6 +41,8 @@ type Props = {
objects: BusinessObject[];
objectKinds: string[];
sectors: { id: number; name: string }[];
+ registeredLocation?: RegisteredBusinessLocation | null;
+ pointPublicationAvailable?: boolean;
};
const steps = [
['Proponente', 'Applicant'],
@@ -185,6 +192,8 @@ export default function BusinessWizard({
objects,
objectKinds,
sectors,
+ registeredLocation,
+ pointPublicationAvailable,
}: Props) {
const [english, setEnglish] = useState(false);
const t = (pt: string, en: string) => (english ? en : pt);
@@ -206,6 +215,7 @@ export default function BusinessWizard({
return initial;
});
const modality = record.modality;
+ const pointRequired = businessPointRequiredFields(payload);
const [sectorId, setSectorId] = useState(record.sector_id ?? null);
const [sectorSearch, setSectorSearch] = useState('');
const [publicTitle, setPublicTitle] = useState(record.public_title ?? '');
@@ -530,6 +540,13 @@ export default function BusinessWizard({
{record.code} · {t('Versão', 'Version')} {version}
+ {[5, 7, 8].includes(step) && (
+
+ )}
{t(
'Área privada. Guardar ou submeter não publica a oportunidade nem confirma a titularidade ou a transmissibilidade.',
@@ -720,7 +737,7 @@ export default function BusinessWizard({
label={
field.type === 'checkbox'
? ''
- : `${english ? field.en : field.pt}${requiredFields.has(key) || ((key === 'mandate_reference' || key === 'mandate_document_reference' || key === 'disclosure_scope') && payload.acting_capacity === 'representative') || (key === 'project_stage_other' && payload.project_stage === 'other') || (key === 'available_from' && payload.availability === 'from_date') || (key === 'province_id' && payload.geography_scope === 'specific') || (key === 'locations_json' && payload.geography_scope === 'multiple') || (['value_meaning', 'currency', 'asking_value'].includes(key) && ['defined', 'indicative'].includes(payload.value_status ?? '')) || (key === 'investment_total' && payload.opportunity_type === 'investment_project') || (key === 'asset_deal_kind' && ['company_sale', 'asset_sale'].includes(payload.opportunity_type ?? '')) || (key === 'partnership_contribution' && payload.opportunity_type === 'business_partnership') || (key === 'amount_sought' && payload.opportunity_type === 'financing_request') || (key === 'asset_modality' && payload.opportunity_type === 'asset_sale') || (['concession_entity', 'concession_reference'].includes(key) && payload.opportunity_type === 'concession_opportunity') || (key === 'supply_description' && payload.opportunity_type === 'supply_opportunity') ? ' *' : ''}`
+ : `${english ? field.en : field.pt}${pointRequired.has(key) || requiredFields.has(key) || ((key === 'mandate_reference' || key === 'mandate_document_reference' || key === 'disclosure_scope') && payload.acting_capacity === 'representative') || (key === 'project_stage_other' && payload.project_stage === 'other') || (key === 'available_from' && payload.availability === 'from_date') || (key === 'province_id' && payload.geography_scope === 'specific') || (key === 'locations_json' && payload.geography_scope === 'multiple') || (['value_meaning', 'currency', 'asking_value'].includes(key) && ['defined', 'indicative'].includes(payload.value_status ?? '')) || (key === 'investment_total' && payload.opportunity_type === 'investment_project') || (key === 'asset_deal_kind' && ['company_sale', 'asset_sale'].includes(payload.opportunity_type ?? '')) || (key === 'partnership_contribution' && payload.opportunity_type === 'business_partnership') || (key === 'amount_sought' && payload.opportunity_type === 'financing_request') || (key === 'asset_modality' && payload.opportunity_type === 'asset_sale') || (['concession_entity', 'concession_reference'].includes(key) && payload.opportunity_type === 'concession_opportunity') || (key === 'supply_description' && payload.opportunity_type === 'supply_opportunity') ? ' *' : ''}`
}
>
{field.type === 'checkbox' ? (
@@ -775,6 +792,71 @@ export default function BusinessWizard({
update(key, value)
}
/>
+ ) : field.type === 'point_territory' ? (
+
+ update(key, event.target.value)
+ }
+ >
+
+ {t(
+ 'Seleccionar uma localização declarada',
+ 'Select a declared location',
+ )}
+
+ {payload[key] &&
+ !locationRows.some(
+ (row) =>
+ businessPointTerritoryKey(
+ row,
+ ) === payload[key],
+ ) && (
+
+ {t(
+ 'Selecção guardada fora das localizações actuais; reconcilie antes de submeter',
+ 'Saved selection is outside the current locations; reconcile before submitting',
+ )}
+
+ )}
+ {locationRows
+ .map((row, index) => ({
+ row,
+ index,
+ }))
+ .filter(
+ ({ row }) =>
+ row.province_id,
+ )
+ .map(({ row, index }) => (
+
+ {t(
+ 'Localização',
+ 'Location',
+ )}{' '}
+ {index + 1}
+ {payload.locations_json ===
+ resolvedLocationJson &&
+ territoryPaths[index]
+ ?.length
+ ? ` — ${territoryPaths[index].join(' / ')}`
+ : t(
+ ' (declarada nesta etapa)',
+ ' (declared in this step)',
+ )}
+
+ ))}
+
) : field.type === 'select' ? (
{t(
- 'Indique pelo menos duas localizações distintas. Não são recolhidas coordenadas neste formulário.',
- 'Enter at least two distinct locations. This form does not collect coordinates.',
+ 'Indique pelo menos duas localizações distintas. Se preparar um ponto exacto, escolha acima a localização a que pertence. Não é escolhido automaticamente o primeiro território.',
+ 'Enter at least two distinct locations. If preparing an exact point, select its location above. The first territory is not selected automatically.',
)}
{locationRows.map((row, index) => (
diff --git a/resources/js/pages/investment/business.tsx b/resources/js/pages/investment/business.tsx
index 7492e9a9..fe63af8e 100644
--- a/resources/js/pages/investment/business.tsx
+++ b/resources/js/pages/investment/business.tsx
@@ -10,6 +10,10 @@ import type { BusinessVerification } from './business-verifications';
import BusinessWizard from './business-wizard';
import type { FormSchema } from './business-wizard';
import type { Country } from '@/components/country-select';
+import BusinessPointSummary, {
+ type RegisteredBusinessLocation,
+} from '@/components/business-point-summary';
+import { businessPointTerritoryLabel } from '@/lib/business-locations';
type Props = {
countries: Country[];
@@ -18,6 +22,8 @@ type Props = {
sectors: { id: number; name: string }[];
record: Business;
canEdit: boolean;
+ registeredLocation?: RegisteredBusinessLocation | null;
+ pointPublicationAvailable?: boolean;
owner: boolean;
canReview: boolean;
canTriage: boolean;
@@ -68,6 +74,8 @@ function Editor({
verifications,
formSchema,
sectors,
+ registeredLocation,
+ pointPublicationAvailable,
}: Props) {
const [payload, setPayload] = useState(record.payload);
const [modality, setModality] = useState(record.modality);
@@ -131,6 +139,16 @@ function Editor({
{businessStates[record.status]} · versão {record.version_no} ·
informação reservada
+
Informação declarada, pendente de validação. Não constitui
anúncio público, certificação, avaliação ou autorização de
@@ -148,7 +166,18 @@ function Editor({
{Object.entries(formSchema)
.filter(
- ([key]) =>
+ ([key, field]) =>
+ !key.startsWith('location_point_') &&
+ ![
+ 'location_latitude',
+ 'location_longitude',
+ ].includes(key) &&
+ Object.entries(field.when ?? {}).every(
+ ([dependency, values]) =>
+ values.includes(
+ record.payload[dependency] ?? '',
+ ),
+ ) &&
![
'title',
'description',
diff --git a/resources/js/pages/investment/company-comparison.tsx b/resources/js/pages/investment/company-comparison.tsx
new file mode 100644
index 00000000..c9431a30
--- /dev/null
+++ b/resources/js/pages/investment/company-comparison.tsx
@@ -0,0 +1,386 @@
+import { useRef, useState } from 'react';
+import { Link, router } from '@inertiajs/react';
+import { Frame, card, input, button } from './shared';
+import { profileJson } from '@/lib/profile-json';
+import { createOperationKey } from '@/lib/operation-key';
+import {
+ companyComparisonUrl,
+ type CompanyAnswers,
+} from '@/lib/company-comparison';
+
+type Question = { label: string; options: Record };
+type Result = {
+ engine_version: string;
+ source: {
+ title: string;
+ edition: string;
+ issued_on: string;
+ consulted_on: string;
+ url: string;
+ };
+ questions: Record;
+ active: string[];
+ pending: string[];
+ route: string;
+ scope: string;
+ preparation: string[];
+ forms: {
+ code: string;
+ title: string;
+ description: string;
+ articles: string;
+ source_href: string;
+ constraints: string[];
+ notes: string[];
+ selected: boolean;
+ }[];
+};
+type Props = {
+ definition: { version: string; questions: Record };
+ case: { id: string; title: string; version: number } | null;
+ canWrite: boolean;
+ answers: CompanyAnswers;
+ result: Result;
+ saved: { revision: number; at: string; result: Result } | null;
+ history: {
+ id: string;
+ revision: number;
+ at: string;
+ engine_version: string;
+ }[];
+ historyNext: number | null;
+ historical: boolean;
+ workingCopy: boolean;
+};
+export default function CompanyComparison(props: Props) {
+ return (
+
+ );
+}
+function Comparator(props: Props) {
+ const { definition, result, saved, history, historical, workingCopy } =
+ props;
+ const dossier = props.case;
+ const [answers, setAnswers] = useState(props.answers);
+ const [dirty, setDirty] = useState(false);
+ const [busy, setBusy] = useState(false);
+ const [error, setError] = useState('');
+ const formRef = useRef(null);
+ const operation = useRef(createOperationKey());
+ const base = dossier
+ ? `/investimentos/${dossier.id}/forma-juridica`
+ : '/formas-juridicas';
+ const oldDefinition =
+ !workingCopy && saved && result.engine_version !== definition.version;
+ const readOnly = historical || !!oldDefinition;
+ const active = ['representation', 'cooperation'].includes(answers.purpose)
+ ? ['purpose', 'regulated']
+ : Object.keys(definition.questions);
+ const currentValues = (): CompanyAnswers => {
+ const data = new FormData(formRef.current!);
+ return Object.fromEntries(
+ Object.keys(definition.questions).map((key) => {
+ const value = data.get(`answers[${key}]`);
+ return [
+ key,
+ typeof value === 'string'
+ ? value
+ : (answers[key] ?? 'unknown'),
+ ];
+ }),
+ );
+ };
+ async function save() {
+ if (!dossier || busy) return;
+ setBusy(true);
+ setError('');
+ try {
+ await profileJson(base, {
+ version: dossier.version,
+ operation_key: operation.current,
+ answers: currentValues(),
+ });
+ router.visit(base, { preserveState: false });
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível guardar. As respostas continuam no formulário.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ return (
+
+ {dossier && (
+
+ Dossier:{' '}
+
+ {dossier.title}
+
+
+ )}
+
+ Compare a estrutura pretendida e os pontos a esclarecer antes de
+ preparar o acto constitutivo.
+
+ {saved && (
+
+ {historical
+ ? 'Revisão histórica'
+ : 'Última comparação guardada'}
+ : {saved.revision} · {saved.at}.{' '}
+ {workingCopy &&
+ 'As respostas desta consulta ainda não substituem a edição guardada.'}
+
+ )}
+ {readOnly ? (
+
+
+ Respostas conservadas
+
+
+ {result.active.map((key) => (
+
+
{result.questions[key]?.label ?? key}
+
+ {result.questions[key]?.options[
+ answers[key]
+ ] ?? answers[key]}
+
+
+ ))}
+
+
+ Preparar nova comparação com estas respostas
+
+
+ ) : (
+
+
+ {Object.entries(definition.questions).map(
+ ([key, question]) =>
+ active.includes(key) ? (
+
+ {question.label}
+ {
+ setAnswers({
+ ...answers,
+ [key]: e.target.value,
+ });
+ setDirty(true);
+ operation.current =
+ createOperationKey();
+ }}
+ >
+ {Object.entries(
+ question.options,
+ ).map(([code, label]) => (
+
+ {label}
+
+ ))}
+
+
+ ) : (
+
+ ),
+ )}
+
+
+
+ Actualizar comparação
+
+ {dossier ? (
+ props.canWrite && (
+
+ {busy ? 'A guardar…' : 'Guardar no dossier'}
+
+ )
+ ) : (
+
+ router.visit(
+ companyComparisonUrl(
+ '/investimentos',
+ currentValues(),
+ 'company_comparison',
+ ),
+ )
+ }
+ >
+ Escolher dossier para guardar
+
+ )}
+
+ {dirty && (
+
+ Actualize a comparação para reflectir as alterações.
+ Guardar utiliza as respostas actuais.
+
+ )}
+ {dossier && !props.canWrite && (
+
+ Consulta do dossier. A edição depende do acesso
+ actual e de o dossier estar aberto.
+
+ )}
+ {error && (
+
+
{error}
+
+ As respostas continuam no formulário. Reabra a
+ comparação com estes valores para recuperar a
+ sessão ou a versão actual do dossier.
+
+
+ Reabrir com estas respostas
+
+
+ )}
+
+ )}
+
+
+ Alternativas e pontos a conferir
+
+ {result.route}
+ {result.pending.length > 0 && (
+
+ Por esclarecer:{' '}
+ {result.pending
+ .map((key) => result.questions[key]?.label ?? key)
+ .join(' · ')}
+
+ )}
+
+ {result.forms.map((item) => (
+
+
+ {item.title}
+ {item.selected
+ ? ' · Preferência para aprofundar'
+ : ''}
+
+ {item.description}
+ {item.constraints.map((text) => (
+
+ Incompatibilidade a resolver: {text}
+
+ ))}
+ {item.notes.map((text) => (
+ {text}
+ ))}
+
+ {item.articles} · consultar fonte
+
+
+ ))}
+
+
+ Preparar a próxima conversa
+
+
+ {result.preparation.map((item) => (
+ {item}
+ ))}
+
+ {result.scope}
+
+
+
+ Fonte e edição consultadas
+
+
+ {result.source.title}
+
+
+ {result.source.edition}. Publicação:{' '}
+ {result.source.issued_on}. Consulta desta edição:{' '}
+ {result.source.consulted_on}.
+
+
+ {dossier && (
+
+
+ Comparações guardadas
+
+
+ {history.map((item) => (
+
+
+ Revisão {item.revision} · {item.at}
+
+
+ ))}
+
+ {props.historyNext && (
+
+ Comparações anteriores
+
+ )}
+ {historical && (
+
+ Voltar à comparação actual
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/resources/js/pages/investment/company-preparation.tsx b/resources/js/pages/investment/company-preparation.tsx
new file mode 100644
index 00000000..b25f405d
--- /dev/null
+++ b/resources/js/pages/investment/company-preparation.tsx
@@ -0,0 +1,790 @@
+import { useRef, useState } from 'react';
+import { Link, router } from '@inertiajs/react';
+import { Frame, card, input, button } from './shared';
+import { profileJson, ProfileValidationError } from '@/lib/profile-json';
+import { createOperationKey } from '@/lib/operation-key';
+import {
+ preparationValues,
+ type CompanyFacts,
+ type Party,
+} from '@/lib/company-preparation';
+
+type Review = {
+ issues: string[];
+ totals: Record | null;
+ note: string;
+};
+type Props = {
+ case: { id: string; title: string; version: number };
+ canWrite: boolean;
+ historical: boolean;
+ definition: {
+ version: string;
+ forms: Record;
+ roles: Record;
+ template_notice: string;
+ source: { title: string; edition: string; url: string };
+ };
+ facts: CompanyFacts;
+ review: Review;
+ saved: { revision: number; at: string } | null;
+ sources: Record<
+ string,
+ { name: string; kind: 'person' | 'entity'; origin: string }
+ >;
+ history: { id: string; revision: number; at: string }[];
+ historyNext: number | null;
+};
+
+export default function CompanyPreparation(props: Props) {
+ return (
+
+ );
+}
+
+function Preparation(props: Props) {
+ const [facts, setFacts] = useState(props.facts);
+ const [busy, setBusy] = useState(false);
+ const [error, setError] = useState('');
+ const [fields, setFields] = useState>({});
+ const [recovery, setRecovery] = useState(null);
+ const [version, setVersion] = useState(props.case.version);
+ const [dirty, setDirty] = useState(false);
+ const form = useRef(null);
+ const operation = useRef(createOperationKey());
+ const base = `/investimentos/${props.case.id}/preparar-empresa`;
+ const readOnly = !props.canWrite || props.historical;
+ const corporate = !!facts.form && facts.form !== 'individual';
+ const shares = ['anonymous', 'simplified'].includes(facts.form ?? '');
+ function update(key: keyof CompanyFacts, value: string) {
+ setFacts((old) => ({ ...old, [key]: value || null }));
+ }
+ function party(id: string, changes: Partial) {
+ setFacts((old) => ({
+ ...old,
+ parties: old.parties.map((p) =>
+ p.id === id ? { ...p, ...changes } : p,
+ ),
+ }));
+ }
+ function text(
+ key: Exclude,
+ label: string,
+ multiline = false,
+ ) {
+ return (
+
+ {label}
+ {multiline ? (
+ update(key, e.target.value)}
+ maxLength={2000}
+ />
+ ) : (
+ update(key, e.target.value)}
+ maxLength={
+ key === 'proposed_name'
+ ? 250
+ : key === 'currency'
+ ? 3
+ : 25
+ }
+ />
+ )}
+
+ );
+ }
+ function partyText(
+ p: Party,
+ key:
+ | 'name'
+ | 'cash'
+ | 'in_kind'
+ | 'paid'
+ | 'share_count'
+ | 'work'
+ | 'commitment',
+ label: string,
+ ) {
+ return (
+
+ {label}
+
+ party(p.id, { [key]: e.target.value || null })
+ }
+ maxLength={
+ ['work', 'commitment'].includes(key)
+ ? 2000
+ : key === 'name'
+ ? 250
+ : 25
+ }
+ />
+
+ );
+ }
+ async function save() {
+ if (busy || readOnly) return;
+ setBusy(true);
+ setError('');
+ setFields({});
+ const values = preparationValues(form.current!, facts);
+ setFacts(values);
+ try {
+ await profileJson(base, {
+ version,
+ operation_key: operation.current,
+ facts: values,
+ });
+ router.visit(base, { preserveState: false });
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível guardar. Os dados continuam no formulário.',
+ );
+ if (e instanceof ProfileValidationError) setFields(e.fields);
+ } finally {
+ setBusy(false);
+ }
+ }
+ async function recover() {
+ setBusy(true);
+ try {
+ setRecovery(await profileJson(base, {}, 'GET'));
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível consultar o dossier.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ return (
+
+
+
+ {props.case.title}
+ {' '}
+ ·{' '}
+
+ Comparar formas jurídicas
+
+
+ {props.definition.template_notice}
+
+ Guarde mesmo que faltem dados. Só se pedem informações desta
+ preparação; valores indicados como realizados são declarações,
+ não comprovativos de pagamento.
+
+ {props.saved && (
+
+ {props.historical
+ ? 'Revisão histórica'
+ : 'Última ficha guardada'}
+ : {props.saved.revision} · {props.saved.at}.{' '}
+
+ Abrir a preparação actual
+
+
+ )}
+ {dirty && (
+
+ Alterações por guardar. Os totais e as questões serão
+ conferidos quando guardar esta ficha.
+
+ )}
+ {error && (
+
+
{error}
+
+ {Object.entries(fields).map(([key, message]) => (
+ {message}
+ ))}
+
+
+ Conferir edição actual sem perder estes dados
+
+
+ )}
+ {recovery && (
+
+
+ Edição actualmente guardada no dossier
+
+
+ Versão {recovery.case.version}. Compare os dados antes
+ de voltar a guardar; a nova gravação conserva esta
+ edição no histórico.
+
+
+ {recovery.canWrite && (
+ {
+ setVersion(recovery.case.version);
+ operation.current = createOperationKey();
+ setRecovery(null);
+ setError('');
+ }}
+ >
+ Conferi: manter os meus dados para uma nova revisão
+
+ )}
+
+ )}
+ setDirty(true)}
+ onSubmit={(e) => {
+ e.preventDefault();
+ void save();
+ }}
+ className="space-y-5"
+ >
+
+
+
+ 1. Forma jurídica
+
+
+ Alternativa a preparar
+ update('form', e.target.value)}
+ >
+ Ainda por definir
+ {Object.entries(props.definition.forms).map(
+ ([code, f]) => (
+
+ {f.title}
+
+ ),
+ )}
+
+
+
+
+
+ 2. Intervenientes e papéis
+
+
+ A mesma pessoa pode acumular papéis. Ter uma
+ participação não atribui automaticamente
+ administração, representação ou qualidade de
+ beneficiário efectivo.
+
+ {facts.parties.map((p, index) => (
+
+ Interveniente {index + 1}
+
+ Origem do nome
+ {
+ const s =
+ props.sources[e.target.value];
+ party(p.id, {
+ source: e.target.value || null,
+ source_snapshot: undefined,
+ ...(s
+ ? {
+ name: s.name,
+ kind: s.kind,
+ }
+ : {}),
+ });
+ }}
+ >
+
+ Informação nova desta preparação
+
+ {Object.entries(props.sources).map(
+ ([key, source]) => (
+
+ {source.origin} ·{' '}
+ {source.name}
+
+ ),
+ )}
+
+
+ {p.source_snapshot && (
+
+ Versão utilizada:{' '}
+ {p.source_snapshot.version ??
+ 'não indicada'}{' '}
+ · {p.source_snapshot.origin}. Conservada
+ nesta ficha; mudanças no cadastro não a
+ substituem.
+
+ )}
+ {partyText(
+ p,
+ 'name',
+ 'Nome da pessoa ou entidade',
+ )}
+
+ Natureza
+
+ party(p.id, {
+ kind: e.target
+ .value as Party['kind'],
+ })
+ }
+ >
+
+ Pessoa singular
+
+ Entidade
+
+
+ {Object.entries(props.definition.roles).map(
+ ([code, label]) => (
+
+
+ party(p.id, {
+ roles: e.target.checked
+ ? [...p.roles, code]
+ : p.roles.filter(
+ (r) =>
+ r !==
+ code,
+ ),
+ })
+ }
+ />{' '}
+ {label}
+
+ ),
+ )}
+ {p.roles.includes('representative') && (
+
+ Quem representa?
+
+ party(p.id, {
+ represented_id:
+ e.target.value || null,
+ })
+ }
+ >
+
+ Ainda por identificar
+
+ {facts.parties
+ .filter(
+ (other) =>
+ other.id !== p.id,
+ )
+ .map((other, i) => (
+
+ {other.name ||
+ `Interveniente ${i + 1}`}
+
+ ))}
+
+
+ )}
+ {
+ setDirty(true);
+ setFacts((old) => ({
+ ...old,
+ parties: old.parties.filter(
+ (other) => other.id !== p.id,
+ ),
+ }));
+ }}
+ >
+ Retirar da preparação actual
+
+
+ ))}
+ {
+ setDirty(true);
+ setFacts((old) => ({
+ ...old,
+ parties: [
+ ...old.parties,
+ {
+ id: createOperationKey(),
+ name: null,
+ kind: 'person',
+ source: null,
+ roles: [],
+ represented_id: null,
+ cash: null,
+ in_kind: null,
+ paid: null,
+ share_count: null,
+ work: null,
+ commitment: null,
+ },
+ ],
+ }));
+ }}
+ >
+ Adicionar interveniente
+
+
+
+
+ 3. Nome e sede propostos
+
+ {text('proposed_name', 'Denominação proposta')}
+ {text(
+ 'seat',
+ 'Sede proposta (distinta da morada pessoal)',
+ true,
+ )}
+
+
+
+ 4. Actividades
+
+ {text(
+ 'activities',
+ 'Actividades a incluir no objecto',
+ true,
+ )}
+
+ Existem regras sectoriais ou profissionais próprias?
+
+ update('regulated', e.target.value)
+ }
+ >
+
+ Ainda não confirmei
+
+ Sim
+ Não identifiquei
+
+
+
+ Descrever o objecto não concede licença para exercer
+ a actividade.
+
+
+ {corporate && (
+
+
+ 5. Capital e participações
+
+
+ Indique zero apenas quando confirmado; deixe em
+ branco o que desconhece. Todos os valores
+ monetários desta ficha usam a mesma moeda, sem
+ conversão.
+
+ {text(
+ 'currency',
+ 'Código da moeda (três letras, por exemplo MZN)',
+ )}
+ {text('capital', 'Capital declarado')}
+ {shares &&
+ text(
+ 'nominal_value',
+ 'Valor nominal de cada acção',
+ )}
+ {facts.parties
+ .filter((p) => p.roles.includes('subscriber'))
+ .map((p) => (
+
+
+ {p.name ||
+ 'Participante ainda sem nome'}
+
+ {partyText(
+ p,
+ 'cash',
+ 'Entrada subscrita em dinheiro',
+ )}
+ {partyText(
+ p,
+ 'in_kind',
+ 'Entrada subscrita em espécie (valor declarado)',
+ )}
+ {partyText(
+ p,
+ 'paid',
+ 'Total já realizado (declaração)',
+ )}
+ {shares &&
+ partyText(
+ p,
+ 'share_count',
+ 'Número de acções',
+ )}
+ {partyText(
+ p,
+ 'work',
+ 'Contribuição em trabalho, se pretendida; não somada ao capital',
+ )}
+ {partyText(
+ p,
+ 'commitment',
+ 'Condições e prazos ainda por cumprir, se definidos',
+ )}
+
+ ))}
+
+ )}
+
+
+ 6. Administração e forma de obrigar
+
+ {text(
+ 'management',
+ 'Estrutura, nomeações e poderes pretendidos',
+ true,
+ )}
+ {text(
+ 'binding',
+ 'Quem poderá vincular a entidade e em que condições?',
+ true,
+ )}
+
+
+
+ 7. Conferência e preparação para revisão
+
+ {text(
+ 'notes',
+ 'Questões a esclarecer nesta preparação',
+ true,
+ )}
+
+ Guardar ficha no dossier
+
+
+
+
+
+
+ {props.saved
+ ? 'Conferência da ficha guardada'
+ : 'Pontos a preparar'}
+
+ {props.review.note}
+ {props.review.totals && (
+
+ {Object.entries(props.review.totals).map(
+ ([key, value]) => (
+
+
+ {{
+ currency: 'Moeda',
+ subscribed: 'Total subscrito',
+ paid: 'Realizado declarado',
+ unpaid: 'Por realizar declarado',
+ shares_nominal:
+ 'Valor nominal total das acções',
+ }[key] ?? key}
+
+ {value ?? 'Por determinar'}
+
+ ),
+ )}
+
+ )}
+
+ {props.review.issues.map((issue) => (
+ {issue}
+ ))}
+
+
+
+ {props.definition.source.title}
+ {' '}
+ · {props.definition.source.edition}
+
+
+
+ Histórico
+
+ {props.history.map((h) => (
+
+
+ Revisão {h.revision} · {h.at}
+
+
+ ))}
+
+ {props.historyNext && (
+
+ Edições anteriores
+
+ )}
+
+
+ );
+}
+
+function SavedFacts({
+ facts,
+ definition,
+}: Pick) {
+ const labels: {
+ key: Exclude;
+ label: string;
+ }[] = [
+ { key: 'form', label: 'Forma jurídica' },
+ { key: 'proposed_name', label: 'Denominação proposta' },
+ { key: 'seat', label: 'Sede proposta' },
+ { key: 'activities', label: 'Actividades' },
+ {
+ key: 'regulated',
+ label: 'Regras sectoriais ou profissionais identificadas',
+ },
+ { key: 'currency', label: 'Moeda' },
+ { key: 'capital', label: 'Capital declarado' },
+ { key: 'nominal_value', label: 'Valor nominal por acção' },
+ { key: 'management', label: 'Administração pretendida' },
+ { key: 'binding', label: 'Forma de obrigar pretendida' },
+ { key: 'notes', label: 'Questões a esclarecer' },
+ ];
+ return (
+
+
+ {labels.map(({ key, label }) => (
+
+
{label}
+
+ {key === 'form'
+ ? (definition.forms[facts.form ?? '']?.title ??
+ 'Por definir')
+ : key === 'regulated'
+ ? ({
+ yes: 'Sim',
+ no: 'Não identificadas',
+ unknown: 'Por confirmar',
+ }[facts.regulated] ?? 'Por confirmar')
+ : (facts[key] ?? 'Por definir')}
+
+
+ ))}
+
+ {facts.parties.map((p, index) => (
+
+
+ Interveniente {index + 1}:{' '}
+ {p.name ?? 'Nome por definir'}
+
+
+ {p.kind === 'entity' ? 'Entidade' : 'Pessoa singular'} ·{' '}
+ {p.roles
+ .map((role) => definition.roles[role] ?? role)
+ .join(', ') || 'Papéis por definir'}
+
+ {p.source_snapshot && (
+
+ {p.source_snapshot.origin} · versão{' '}
+ {p.source_snapshot.version ?? 'não indicada'}
+
+ )}
+ {p.roles.includes('representative') && (
+
+ Representa:{' '}
+ {facts.parties.find(
+ (other) => other.id === p.represented_id,
+ )?.name ?? 'Por identificar'}
+
+ )}
+
+ {(
+ [
+ ['cash', 'Entrada em dinheiro'],
+ ['in_kind', 'Entrada em espécie'],
+ ['paid', 'Realização declarada'],
+ ['share_count', 'Número de acções'],
+ ['work', 'Contribuição em trabalho'],
+ ['commitment', 'Condições e prazos'],
+ ] as const
+ ).map(([key, label]) => (
+
+
{label}
+
+ {p[key] ?? 'Por definir'}
+
+
+ ))}
+
+
+ ))}
+
+ );
+}
diff --git a/resources/js/pages/investment/guide.tsx b/resources/js/pages/investment/guide.tsx
new file mode 100644
index 00000000..c44c7be6
--- /dev/null
+++ b/resources/js/pages/investment/guide.tsx
@@ -0,0 +1,676 @@
+import { useRef, useState } from 'react';
+import { Link, router } from '@inertiajs/react';
+import { Frame, card, input, button } from './shared';
+import { profileJson, ProfileValidationError } from '@/lib/profile-json';
+import { createOperationKey } from '@/lib/operation-key';
+import { guideChoices, guideUrl } from '@/lib/investment-guides';
+
+type Guide = {
+ slug: string;
+ version: string;
+ sha256: string;
+ title: string;
+ reviewed_on: string;
+ scope: string;
+ selection_label?: string;
+ selection_hint?: string;
+ cards_title?: string;
+ eligibility_title?: string;
+ preparation_title?: string;
+ requirements?: GuideRequirement[];
+ documents?: {
+ id: string;
+ title: string;
+ text: string;
+ paths: string[];
+ citations: GuideCitation[];
+ }[];
+ handoffs?: { title: string; url: string; note: string }[];
+ instruments: Record<
+ string,
+ {
+ title: string;
+ description: string;
+ risks: string[];
+ prepare: string[];
+ sources: string[];
+ requirements?: GuideRequirement[];
+ }
+ >;
+ sources: Record<
+ string,
+ {
+ title: string;
+ url: string;
+ edition: string;
+ locator: string;
+ consulted_on: string;
+ sha256: string | null;
+ valid_until?: string;
+ }
+ >;
+ eligibility: {
+ text: string;
+ sources: string[];
+ citations?: GuideCitation[];
+ }[];
+ preparation: {
+ title: string;
+ text: string;
+ sources: string[];
+ responsible?: string;
+ citations?: GuideCitation[];
+ }[];
+ next: string[];
+ limits: string[];
+};
+type GuideCitation = { source: string; reference: string; page: number };
+type GuideRequirement = {
+ id: string;
+ text: string;
+ kind: 'requirement' | 'exception' | 'gap';
+ citations: GuideCitation[];
+};
+type Props = {
+ guide: Guide;
+ instruments: string[];
+ note: string;
+ case: { id: string; title: string; version: number } | null;
+ saved: {
+ revision: number;
+ at: string;
+ note: string;
+ instruments: string[];
+ guide: Guide;
+ context: { revision: number };
+ } | null;
+ canWrite: boolean;
+ historical: boolean;
+ olderEdition: boolean;
+ currentAvailable: boolean;
+ workingCopy: boolean;
+ contextChanged: boolean;
+ unavailableInstruments: string[];
+ history: { id: string; revision: number; at: string; edition: string }[];
+ historyNext: number | null;
+};
+
+export default function InvestmentGuide(props: Props) {
+ return (
+
+ );
+}
+
+function GuideView(props: Props) {
+ const { guide, saved, historical, olderEdition } = props;
+ const dossier = props.case;
+ const [selected, setSelected] = useState(props.instruments);
+ const [note, setNote] = useState(props.note);
+ const [busy, setBusy] = useState(false);
+ const [error, setError] = useState('');
+ const [recovery, setRecovery] = useState(null);
+ const [version, setVersion] = useState(dossier?.version ?? 0);
+ const form = useRef(null);
+ const operation = useRef(createOperationKey());
+ const base = dossier
+ ? `/investimentos/${dossier.id}/guias/${guide.slug}`
+ : `/guias-investimento/${guide.slug}`;
+ const readOnly =
+ historical || olderEdition || (!!dossier && !props.canWrite);
+ const visible = selected.length ? selected : Object.keys(guide.instruments);
+ function sourceLinks(keys: string[]) {
+ return (
+
+ Fontes:{' '}
+ {keys.map((key) => (
+
+
+ {guide.sources[key]?.title ?? key}
+
+
+ ))}
+
+ );
+ }
+ function citations(items: GuideCitation[] = []) {
+ return (
+
+ );
+ }
+ function requirements(items: GuideRequirement[] = []) {
+ return (
+
+ {items.map((item) => (
+
+
+
+ {
+ {
+ gap: 'Por esclarecer',
+ exception:
+ 'Regra com dispensa ou condição específica',
+ requirement: 'Conferir requisito',
+ }[item.kind]
+ }
+ :
+ {' '}
+ {item.text}
+
+ {citations(item.citations)}
+
+ ))}
+
+ );
+ }
+ function choose() {
+ router.visit(
+ guideUrl(
+ '/investimentos',
+ {
+ slug: guide.slug,
+ sha256: guide.sha256,
+ instruments: guideChoices(form.current!),
+ },
+ true,
+ ),
+ );
+ }
+ async function save() {
+ if (!dossier || busy || readOnly) return;
+ setBusy(true);
+ setError('');
+ const values = new FormData(form.current!);
+ const currentNote = values.get('note');
+ const chosen = guideChoices(form.current!);
+ const text = typeof currentNote === 'string' ? currentNote : note;
+ setNote(text);
+ setSelected(chosen);
+ try {
+ await profileJson(base, {
+ version,
+ operation_key: operation.current,
+ sha256: guide.sha256,
+ instruments: chosen,
+ note: text,
+ });
+ router.visit(base, { preserveState: false });
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível guardar. A nota continua nesta página.',
+ );
+ if (
+ e instanceof ProfileValidationError &&
+ Object.values(e.fields).length
+ )
+ setError(Object.values(e.fields).join(' '));
+ } finally {
+ setBusy(false);
+ }
+ }
+ async function recover() {
+ setBusy(true);
+ try {
+ setRecovery(await profileJson(base, {}, 'GET'));
+ } catch (e) {
+ setError(
+ e instanceof Error
+ ? e.message
+ : 'Não foi possível consultar o dossier.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ return (
+
+ {dossier && (
+
+ Dossier:{' '}
+
+ {dossier.title}
+
+
+ )}
+ {guide.scope}
+
+ Edição {guide.version} · Conteúdo conferido em{' '}
+ {guide.reviewed_on}.
+
+ {saved && (
+
+ {historical
+ ? 'Referência histórica'
+ : 'Última referência guardada'}
+ : revisão {saved.revision} · {saved.at} · contexto{' '}
+ {saved.context.revision}.
+ {props.workingCopy &&
+ ' Esta preparação ainda não substitui a referência guardada.'}
+
+ )}
+ {props.contextChanged && (
+
+ Os dados de contexto disponíveis nesta consulta diferem dos
+ utilizados na referência. Confira a sua pertinência; a
+ edição guardada conserva o contexto anterior.
+
+ )}
+ {props.unavailableInstruments.length > 0 && (
+
+ Esta edição deixou de incluir:{' '}
+ {props.unavailableInstruments.join(', ')}. A selecção e o
+ conteúdo anteriores continuam na referência guardada e no
+ histórico.
+
+ )}
+ {(historical || olderEdition) && (
+
+ Consulta preservada da edição utilizada.{' '}
+ {props.currentAvailable ? (
+
+ Preparar uma nova referência com o guia actual
+
+ ) : (
+ 'O guia foi retirado da consulta actual; esta referência continua disponível.'
+ )}
+
+ )}
+ {
+ e.preventDefault();
+ if (dossier) void save();
+ else choose();
+ }}
+ className={card}
+ >
+
+
+ {guide.selection_label ??
+ 'Que instrumentos pretende aprofundar?'}
+
+
+ {guide.selection_hint ??
+ 'Sem selecção, consulte o conjunto. Pode combinar instrumentos; a selecção organiza a consulta e não é uma recomendação.'}
+
+ {Object.entries(guide.instruments).map(([code, item]) => (
+
+
+ setSelected((old) =>
+ e.target.checked
+ ? [...old, code]
+ : old.filter((v) => v !== code),
+ )
+ }
+ />{' '}
+ {item.title}
+
+ ))}
+ {dossier && (
+
+ Questões a discutir nesta preparação (opcional)
+ setNote(e.target.value)}
+ />
+
+ A nota fica privada no dossier; reutilize os
+ dados e documentos já registados.
+
+
+ )}
+
+ {dossier
+ ? 'Guardar referência no dossier'
+ : 'Escolher dossier para preparar'}
+
+
+
+ {error && (
+
+
{error}
+
+ Conferir a referência actual sem perder a nota
+
+
+ )}
+ {recovery && (
+
+
+ Referência actualmente guardada
+
+
+ Dossier: {recovery.case?.title} · Edição{' '}
+ {recovery.guide.version} · revisão{' '}
+ {recovery.saved?.revision ?? 'ainda não guardada'}
+
+
+ {recovery.instruments
+ .map(
+ (code) =>
+ recovery.guide.instruments[code]?.title ??
+ code,
+ )
+ .join(', ') || 'Consulta do conjunto'}
+
+
+ {recovery.note || 'Sem nota'}
+
+ {recovery.canWrite &&
+ recovery.case &&
+ recovery.currentAvailable &&
+ !recovery.olderEdition &&
+ recovery.guide.sha256 === guide.sha256 && (
+ {
+ setVersion(recovery.case!.version);
+ operation.current = createOperationKey();
+ setRecovery(null);
+ setError('');
+ }}
+ >
+ Conferi: manter a minha preparação numa nova
+ revisão
+
+ )}
+ {(recovery.guide.sha256 !== guide.sha256 ||
+ recovery.olderEdition ||
+ !recovery.currentAvailable) && (
+
+ O guia utilizado foi alterado. Conserve a nota e
+ abra o guia actual numa nova página para comparar as
+ edições.
+
+ )}
+
+ )}
+
+
+ {guide.cards_title ?? 'Instrumentos, riscos e preparação'}
+
+ {guide.requirements && (
+
+
+ Conferência comum aos percursos deste guião
+
+ {requirements(guide.requirements)}
+
+ )}
+
+ {visible.map((code) => {
+ const item = guide.instruments[code];
+ return (
+ item && (
+
+
+ {item.title}
+
+ {item.description}
+
+ Riscos e pontos a conferir
+
+
+ {item.risks.map((text) => (
+ {text}
+ ))}
+
+ {item.prepare.length > 0 && (
+ <>
+
+ Preparar para discussão
+
+
+ {item.prepare.map((text) => (
+ {text}
+ ))}
+
+ >
+ )}
+ {sourceLinks(item.sources)}
+ {requirements(item.requirements)}
+
+ )
+ );
+ })}
+
+
+ {guide.documents && (
+
+
+ Documentos dos percursos seleccionados
+
+
+ Os documentos comuns aparecem uma vez; as condições
+ específicas de cada segmento devem ser conservadas.
+ Reutilize os documentos do dossier e confira a sua
+ actualidade com o operador.
+
+ {guide.documents
+ .filter((doc) =>
+ doc.paths.some((code) => visible.includes(code)),
+ )
+ .map((doc) => (
+
+ {doc.title}
+ {doc.text}
+
+ Percursos:{' '}
+ {doc.paths
+ .filter((code) =>
+ visible.includes(code),
+ )
+ .map(
+ (code) =>
+ guide.instruments[code].title,
+ )
+ .join(' · ')}
+
+ {citations(doc.citations)}
+
+ ))}
+
+ )}
+
+
+ {guide.eligibility_title ??
+ 'Elegibilidade: confirmar com a entidade'}
+
+ {guide.eligibility.map((item) => (
+
+
{item.text}
+ {sourceLinks(item.sources)}
+ {citations(item.citations)}
+
+ ))}
+
+
+
+ {guide.preparation_title ?? 'Dados e documentos a preparar'}
+
+
+ Referência de preparação; a lista exigida em cada operação é
+ definida pela entidade destinatária.
+
+ {guide.preparation.map((item) => (
+
+ {item.title}
+ {item.text}
+ {item.responsible && (
+ Intervenientes: {item.responsible}
+ )}
+ {sourceLinks(item.sources)}
+ {citations(item.citations)}
+
+ ))}
+ {dossier && (
+
+ Reutilizar ou anexar documentos neste dossier
+
+ )}
+
+
+ Próximos passos
+
+ {guide.next.map((text) => (
+ {text}
+ ))}
+
+
+ {guide.limits.map((text) => (
+ {text}
+ ))}
+
+ {guide.handoffs?.map((handoff) => (
+
+
+ {handoff.title}
+ {' '}
+ · {handoff.note}
+
+ ))}
+
+
+ {guide.slug === 'bolsa'
+ ? 'Consultar a preparação de capitalização'
+ : 'Consultar o guião de admissão à Bolsa'}
+
+
+
+ Continuar a preparação no percurso existente
+
+
+
+
+ Fontes e edição consultada
+
+ {Object.entries(guide.sources).map(([key, source]) => (
+
+
+
+ {source.edition} · {source.locator} · consulta{' '}
+ {source.consulted_on}
+
+ {source.valid_until && (
+
+ Período indicado até {source.valid_until}; fonte
+ histórica, sem aplicação como mínimo actual.
+
+ )}
+ {source.sha256 && (
+
+
+ Identificação do exemplar consultado
+
+
+ SHA256: {source.sha256}
+
+
+ A fonte externa pode ser actualizada; a
+ referência guardada conserva os dados da
+ edição utilizada.
+
+
+ )}
+
+ ))}
+
+ {dossier && (
+
+
+ Histórico de referências
+
+
+ {props.history.map((h) => (
+
+
+ Revisão {h.revision} · {h.edition} · {h.at}
+
+
+ ))}
+
+ {props.historyNext && (
+
+ Referências anteriores
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/resources/js/pages/investment/profile.tsx b/resources/js/pages/investment/profile.tsx
index 02a5e6b4..1d1ee9f2 100644
--- a/resources/js/pages/investment/profile.tsx
+++ b/resources/js/pages/investment/profile.tsx
@@ -1,8 +1,11 @@
-import { Link, router, useForm } from '@inertiajs/react';
-import { Frame, Field, input, button, card } from './shared';
+import { Link, router } from '@inertiajs/react';
+import { Frame, button, card } from './shared';
import PartnershipSourceLinks from '@/components/partnership-source-links';
-import CountrySelect, { type Country } from '@/components/country-select';
-import { useEffect, useId } from 'react';
+import { type Country } from '@/components/country-select';
+import { useCallback, useState } from 'react';
+import Editor from '@/components/investment-profile-editor';
+import OrganizationEditor from '@/components/organization-country-editor';
+import { usePagePreparationGuard } from '@/lib/page-preparation-guard';
type RecordData = { version: number; payload: Record };
type Company = RecordData & {
@@ -37,19 +40,38 @@ const labels: Record = {
export default function Profile({
account,
+ actorId,
companies,
countries,
organizations = [],
organizationCountryAvailable = false,
}: {
account: RecordData;
+ actorId: number;
companies: Company[];
countries: Country[];
organizations?: Organization[];
organizationCountryAvailable?: boolean;
}) {
+ const [preparations, setPreparations] = useState>(
+ {},
+ );
+ const reportDirty = useCallback(
+ (id: string, dirty: boolean) =>
+ setPreparations((prior) =>
+ prior[id] === dirty ? prior : { ...prior, [id]: dirty },
+ ),
+ [],
+ );
+ usePagePreparationGuard(
+ Object.values(preparations).some(Boolean),
+ 'Existem dados por guardar nesta página. Sair e perder a preparação?',
+ );
return (
+
+ Comparar formas jurídicas antes de constituir uma entidade
+
Voltar à área do investidor
@@ -62,7 +84,11 @@ export default function Profile({
.
)}
- {organizations
- .filter((o) => o.country)
- .map((org) => (
-
-
- País mestre de {org.name}: {org.country}. A
- reutilização altera somente esta declaração;
- manifestações anteriores conservam o seu
- valor.
-
-
- router.post(
- `/investidor/companies/${company.id}/organization-country`,
- {
- version: company.version,
- organization_id: org.id,
- organization_version:
- org.version,
- },
- { preserveScroll: true },
- )
- }
- >
- Reutilizar país de {org.name}
-
-
- ))}
+ onClick={() => {
+ if (
+ Object.values(preparations).some(Boolean) &&
+ !window.confirm(
+ 'Existem dados por guardar nesta página. Sair e perder a preparação?',
+ )
+ )
+ return;
router.post('/investidor/manifestacoes', {
company_id: company.id,
- })
- }
+ });
+ }}
>
Preparar manifestação desta empresa
@@ -159,7 +168,11 @@ export default function Profile({
Acrescentar empresa
(
@@ -203,201 +218,3 @@ export default function Profile({
);
}
-function OrganizationEditor({
- organization,
- countries,
-}: {
- organization: Organization;
- countries: Country[];
-}) {
- const form = useForm({
- version: organization.version,
- country: organization.country ?? '',
- source_reference: organization.provenance?.reference ?? '',
- });
- const id = useId();
- useEffect(() => {
- if (Object.keys(form.errors).length)
- document
- .getElementById(id)
- ?.querySelector('[aria-invalid="true"]')
- ?.focus();
- }, [form.errors, id]);
- return (
-
- {organization.name}
-
- Versão {organization.version}; origem do país:{' '}
- {organization.provenance?.kind === 'representative_declaration'
- ? 'declaração do representante'
- : 'não informada'}
- .
-
- {
- event.preventDefault();
- form.put(
- `/investidor/organizations/${organization.id}/country`,
- { preserveScroll: true },
- );
- }}
- >
-
- form.setData('country', country)}
- />
-
-
- Fonte ou referência deste país
-
-
- form.setData('source_reference', event.target.value)
- }
- />
- {form.errors.source_reference && (
-
- {form.errors.source_reference}
-
- )}
- {form.errors.version && (
- {form.errors.version}
- )}
-
- Guardar país da organização
-
-
-
- );
-}
-function Editor({
- record,
- fields,
- company = false,
- countries,
-}: {
- record: RecordData & { id?: string };
- fields: string[];
- company?: boolean;
- countries: Country[];
-}) {
- const isCompany = company || !!record.id;
- const form = useForm({
- version: record.version,
- payload: Object.fromEntries(
- [...fields, 'country'].map((key) => [
- key,
- record.payload[key] ?? '',
- ]),
- ),
- });
- return (
- {
- e.preventDefault();
- const options = { preserveScroll: true };
- if (isCompany)
- form.post(
- '/investidor/companies' +
- (record.id ? '/' + record.id : ''),
- options,
- );
- else form.put('/investidor/profile', options);
- }}
- >
-
- {record.payload.country && (
-
- País anteriormente registado: {record.payload.country}.
- Conservado sem atribuir automaticamente residência,
- constituição ou origem da solicitação.
-
- )}
- {fields.map((key) => (
-
- {key.endsWith('_country_code') ? (
-
- form.setData('payload', {
- ...form.data.payload,
- [key]: value,
- })
- }
- />
- ) : (
-
- form.setData('payload', {
- ...form.data.payload,
- [key]: e.target.value,
- })
- }
- />
- )}
- {!key.endsWith('_country_code') &&
- form.errors[`payload.${key}`] && (
-
- {form.errors[`payload.${key}`]}
-
- )}
-
- ))}
-
- {Object.entries(form.errors).map(([key, value]) => (
-
- {value}
-
- ))}
-
- {isCompany
- ? 'Guardar declaração da empresa'
- : 'Guardar perfil de investimento'}
-
-
- );
-}
diff --git a/resources/js/pages/investment/zone-attachments.tsx b/resources/js/pages/investment/zone-attachments.tsx
index e7d9e08b..ef455615 100644
--- a/resources/js/pages/investment/zone-attachments.tsx
+++ b/resources/js/pages/investment/zone-attachments.tsx
@@ -287,12 +287,22 @@ export default function ZoneAttachments({
type="button"
className={button}
disabled={busy}
- onClick={() =>
- void send(
+ onClick={() => {
+ setBusy(true);
+ setError('');
+ router.post(
`/management/documents/${item.document_id}/malware/retry`,
{},
- )
- }
+ {
+ preserveScroll: true,
+ onError: () =>
+ setError(
+ 'Não foi possível pedir a análise. Actualize o estado antes de repetir.',
+ ),
+ onFinish: () => setBusy(false),
+ },
+ );
+ }}
>
Tentar análise novamente
diff --git a/resources/js/pages/investor-path/index.tsx b/resources/js/pages/investor-path/index.tsx
index 52110900..eaf26d44 100644
--- a/resources/js/pages/investor-path/index.tsx
+++ b/resources/js/pages/investor-path/index.tsx
@@ -1,7 +1,12 @@
import { createOperationKey } from '@/lib/operation-key';
import { Head, Link, router, useForm } from '@inertiajs/react';
import { useState } from 'react';
+import {
+ companyComparisonUrl,
+ type CompanyAnswers,
+} from '@/lib/company-comparison';
import type { LegacyArticle } from '@/pages/portal/legacy';
+import { guideUrl, type GuideSelection } from '@/lib/investment-guides';
export type InvestmentContext = {
id: string;
@@ -15,8 +20,12 @@ export default function InvestmentContexts({
contentSource,
sectorSource,
zoneSource,
+ companyComparisonAnswers,
+ guideSelection,
}: {
contexts: InvestmentContext[];
+ companyComparisonAnswers?: CompanyAnswers | null;
+ guideSelection?: GuideSelection | null;
contentSource?: LegacyArticle;
zoneSource?: {
zone_id: string;
@@ -37,11 +46,29 @@ export default function InvestmentContexts({
reuse_consent: false,
content_resource_id: contentSource?.id,
sector_slug: sectorSource?.slug,
+ ...(companyComparisonAnswers
+ ? { company_comparison: companyComparisonAnswers }
+ : {}),
+ ...(guideSelection ? { investment_guide: guideSelection } : {}),
});
return (
Os meus investimentos
+ {guideSelection && (
+
+ Escolha ou crie o dossier onde pretende preparar esta
+ referência. O guia e a nota só serão guardados quando
+ confirmar nesse dossier.
+
+ )}
+ {companyComparisonAnswers && (
+
+ Escolha o dossier para continuar a comparação de formas
+ jurídicas. As respostas só serão guardadas quando confirmar
+ nesse dossier.
+
+ )}
{zoneSource && (
Parque escolhido: {zoneSource.title}
@@ -78,7 +105,19 @@ export default function InvestmentContexts({
{item.title}
diff --git a/resources/js/pages/investor-path/show.tsx b/resources/js/pages/investor-path/show.tsx
index ced5faae..8bac92e1 100644
--- a/resources/js/pages/investor-path/show.tsx
+++ b/resources/js/pages/investor-path/show.tsx
@@ -930,6 +930,29 @@ export default function InvestmentPath(path: Path) {
Documentos
+
+ Preparar capitalização e financiamento
+
+
+ Preparar a admissão à Bolsa de Valores de Moçambique
+
+
+ Preparar os dados para a constituição da empresa
+
+ {path.tools.company && (
+
+ Comparar formas jurídicas para este investimento
+
+ )}
{path.documents.map((doc) => (
diff --git a/resources/js/pages/management/experiments/edit.tsx b/resources/js/pages/management/experiments/edit.tsx
new file mode 100644
index 00000000..e8f3ffda
--- /dev/null
+++ b/resources/js/pages/management/experiments/edit.tsx
@@ -0,0 +1,722 @@
+import { Link, router } from '@inertiajs/react';
+import { useState } from 'react';
+import { Frame, card, input, button } from '@/pages/investment/shared';
+import { profileJson, ProfileValidationError } from '@/lib/profile-json';
+import { createOperationKey } from '@/lib/operation-key';
+import {
+ experimentDifferences,
+ mergeExperimentValues,
+ type ExperimentView,
+} from '@/lib/product-experiments';
+import { usageValue } from '@/lib/product-usage';
+
+export default function ExperimentPage(props: ExperimentView) {
+ return (
+
+ );
+}
+function Editor(props: ExperimentView) {
+ const [values, setValues] = useState(props.values);
+ const [base, setBase] = useState(props.values);
+ const [editedKeys, setEditedKeys] = useState([]);
+ const [referenceDocument, setReferenceDocument] = useState(props.document);
+ const [catalogue, setCatalogue] = useState(props.catalogue);
+ const [version, setVersion] = useState(
+ props.document?.version ?? props.currentVersion,
+ );
+ const [operation, setOperation] = useState(createOperationKey);
+ const [reason, setReason] = useState('');
+ const [busy, setBusy] = useState(false);
+ const [message, setMessage] = useState('');
+ const [errors, setErrors] = useState>({});
+ const [current, setCurrent] = useState(null);
+ const [resolved, setResolved] = useState([]);
+ const [confirmPlan, setConfirmPlan] = useState(false);
+ const [confirmObservation, setConfirmObservation] = useState(false);
+ const [refreshIndicator, setRefreshIndicator] = useState(false);
+ const [attachReport, setAttachReport] = useState(false);
+ const [removeReport, setRemoveReport] = useState(false);
+ const readonly = props.historical || !props.installed;
+ const document = referenceDocument;
+ const differences = current
+ ? experimentDifferences(
+ base,
+ values,
+ current.values,
+ editedKeys,
+ ).filter((k) => !resolved.includes(k))
+ : [];
+ const planComplete = !['draft', 'cancelled'].includes(values.state);
+ const showObservation =
+ ['observing', 'reviewed'].includes(values.state) ||
+ [
+ 'observed_from',
+ 'observed_to',
+ 'control_result',
+ 'variant_result',
+ 'result',
+ 'decision',
+ ].some((k) => values[k]);
+ const frozenIndicator =
+ document?.indicator?.id === values.indicator_id && !refreshIndicator
+ ? document.indicator
+ : null;
+ const selectedIndicator =
+ frozenIndicator ??
+ catalogue.items.find((m) => m.id === values.indicator_id);
+ function change(key: string, value: string) {
+ setEditedKeys((keys) => (keys.includes(key) ? keys : [...keys, key]));
+ setValues((v) => ({ ...v, [key]: value }));
+ }
+ function field(key: string, required = false, type = 'textarea') {
+ const error = errors['values.' + key];
+ return (
+
+ {props.labels[key]}
+ {type === 'textarea' ? (
+ change(key, e.target.value)}
+ />
+ ) : (
+ change(key, e.target.value)}
+ />
+ )}
+ {error && (
+
+ {error}
+
+ )}
+
+ );
+ }
+ async function save() {
+ if (readonly || current !== null) return;
+ setBusy(true);
+ setMessage('');
+ setErrors({});
+ try {
+ const result = await profileJson(
+ props.id
+ ? `/management/product-experiments/${props.id}/revisions`
+ : '/management/product-experiments',
+ {
+ version,
+ operation_key: operation,
+ reason,
+ values,
+ confirm_plan_change: confirmPlan,
+ confirm_observation_plan: confirmObservation,
+ refresh_indicator: refreshIndicator,
+ attach_report: attachReport,
+ remove_report: removeReport,
+ indicator_definition_version: catalogue.definition_version,
+ },
+ );
+ router.visit('/management/product-experiments/' + result.id, {
+ preserveState: false,
+ });
+ } catch (error) {
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'Não foi possível guardar. As suas alterações continuam neste formulário.',
+ );
+ if (error instanceof ProfileValidationError)
+ setErrors(error.fields);
+ } finally {
+ setBusy(false);
+ }
+ }
+ async function compare() {
+ if (!props.id) return;
+ setBusy(true);
+ try {
+ setCurrent(
+ await profileJson(
+ '/management/product-experiments/' + props.id,
+ {},
+ 'GET',
+ ),
+ );
+ setResolved([]);
+ } catch (error) {
+ setMessage(
+ error instanceof Error
+ ? error.message
+ : 'Não foi possível consultar a versão actual.',
+ );
+ } finally {
+ setBusy(false);
+ }
+ }
+ function adoptBase() {
+ if (!current || differences.length > 0) return;
+ const merged = mergeExperimentValues(
+ base,
+ values,
+ current.values,
+ editedKeys,
+ );
+ setValues(merged);
+ setEditedKeys(
+ Object.keys(merged).filter((k) => merged[k] !== current.values[k]),
+ );
+ setBase(current.values);
+ setReferenceDocument(current.document);
+ setCatalogue(current.catalogue);
+ setVersion(current.currentVersion);
+ setOperation(createOperationKey());
+ setCurrent(null);
+ setMessage(
+ 'Versão actual usada como base. Confira o formulário e guarde quando estiver pronto.',
+ );
+ }
+ function download() {
+ if (!document) return;
+ const url = URL.createObjectURL(
+ new Blob([JSON.stringify(document, null, 2)], {
+ type: 'application/json',
+ }),
+ );
+ const anchor = window.document.createElement('a');
+ anchor.href = url;
+ anchor.download = `experiencia-${props.id}-v${document.version}.json`;
+ anchor.click();
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
+ }
+ return (
+
+
+ Registo de experiências
+
+
+ Os dados deste registo são declarações e referências do autor. A
+ distribuição de grupos e a execução da alteração ocorrem nos
+ percursos autorizados correspondentes. Este formulário não
+ altera consentimentos, permissões ou decisões de investimento.
+
+ {!props.installed && (
+
+ O registo ainda não está disponível neste destino.
+
+ )}
+ {props.historical && (
+
+ Consulta da versão {document?.version}.{' '}
+
+ Abrir versão actual
+
+
+ )}
+ {document && (
+
+
+ Versão {document.version}, registada em {document.at}{' '}
+ por {document.actor.name}.
+
+ Motivo: {document.reason || 'Primeiro registo.'}
+ {document.registration.first_at && (
+
+ Primeiro plano registado em{' '}
+ {document.registration.first_at}. Alterações
+ posteriores do plano:{' '}
+ {document.registration.amendments}. A data de
+ registo é conservada; não demonstra, por si, registo
+ anterior à execução.
+
+ )}
+ {document.registration.amended_after_observation && (
+
+ O plano foi alterado após uma observação declarada.
+ Consulte as versões e as limitações antes de
+ comparar resultados.
+
+ )}
+
+ Exportar versão consultada (JSON)
+
+
+ )}
+ {message && {message}
}
+ {!readonly && props.id && (
+
+ Consultar versão actual para comparar
+
+ )}
+ {current && (
+
+
+ Comparar com versão {current.currentVersion}
+
+
+ As suas edições foram conservadas. Escolha como tratar
+ cada diferença; os campos que não editou serão
+ actualizados a partir da versão consultada.
+
+ {differences.map((k) => (
+
+
+ {props.labels[k] ?? k}
+
+
+ Sua edição: {values[k] || '(vazio)'}
+
+
+ Versão actual: {current.values[k] || '(vazio)'}
+
+
+
+ setResolved((r) => [...r, k])
+ }
+ >
+ Manter a minha edição
+
+ {
+ change(k, current.values[k] ?? '');
+ setResolved((r) => [...r, k]);
+ }}
+ >
+ Usar valor actual
+
+
+
+ ))}
+ 0}
+ onClick={adoptBase}
+ >
+ Usar esta versão como base e rever
+
+
+ )}
+ {
+ e.preventDefault();
+ void save();
+ }}
+ >
+
+
+ Plano e alteração
+
+ {field('title', planComplete, 'text')}
+
+ Estado do registo
+ change('state', e.target.value)}
+ >
+ {Object.entries(props.states).map(([k, label]) => (
+
+ {label}
+
+ ))}
+
+
+
+ Tipo de alteração
+
+ change('change_kind', e.target.value)
+ }
+ >
+ Ainda por definir
+ {Object.entries(props.changeKinds).map(
+ ([k, label]) => (
+
+ {label}
+
+ ),
+ )}
+
+
+ {field('reference', planComplete)}
+ {field('hypothesis', planComplete)}
+
+ Indicador
+
+ change('indicator_id', e.target.value)
+ }
+ >
+ Ainda por definir
+ {catalogue.items.map((m) => (
+
+ {m.title}
+
+ ))}
+ {document?.indicator &&
+ document.indicator.id !== 'manual' &&
+ !catalogue.items.some(
+ (m) => m.id === document.indicator?.id,
+ ) && (
+
+ {document.indicator.title} · definição
+ conservada
+
+ )}
+
+ Documentar indicador próprio
+
+
+
+ {values.indicator_id === 'manual' ? (
+ <>
+ {field('indicator_title', planComplete, 'text')}
+ {field('indicator_definition', planComplete)}
+ {field('indicator_unit', planComplete, 'text')}
+ >
+ ) : (
+ selectedIndicator && (
+
+
+ Definição do indicador seleccionado
+
+ {selectedIndicator.source}
+ {selectedIndicator.limits}
+
+ Unidade: {selectedIndicator.unit}. Edição:{' '}
+ {frozenIndicator?.definition_version ??
+ catalogue.definition_version}
+ .
+
+
+ )
+ )}
+ {document?.indicator &&
+ document.indicator.id !== 'manual' &&
+ document.indicator.id === values.indicator_id &&
+ document.indicator.definition_version !==
+ catalogue.definition_version && (
+
+
+ setRefreshIndicator(e.target.checked)
+ }
+ />{' '}
+ Adoptar explicitamente a definição actual do
+ indicador
+
+ )}
+ {field('period_from', planComplete, 'date')}
+ {field('period_to', planComplete, 'date')}
+ {field('segment', planComplete)}
+ {field('control', planComplete)}
+ {field('variant', planComplete)}
+ {field('assignment', planComplete)}
+ {field('criterion', planComplete)}
+
+
+
+ Preservação dos requisitos
+
+ {['transparency', 'consent', 'security', 'equality'].map(
+ (k) => field(k, planComplete),
+ )}
+
+
+ change(
+ 'preserves_requirements',
+ e.target.checked ? 'yes' : '',
+ )
+ }
+ />{' '}
+ O plano mantém a transparência, o consentimento, a
+ segurança e a igualdade de tratamento.
+
+
+ {showObservation && (
+
+
+ Observação e decisão
+
+
+ Identifique as evidências e descreva as bases de
+ comparação. Não inclua listas de pessoas ou dados de
+ visitantes.
+
+ {field(
+ 'observed_from',
+ values.state === 'reviewed' ||
+ values.state === 'observing',
+ 'date',
+ )}
+ {field(
+ 'observed_to',
+ values.state === 'reviewed',
+ 'date',
+ )}
+ {[
+ 'control_result',
+ 'variant_result',
+ 'result',
+ 'limitations',
+ 'evidence',
+ ].map((k) => field(k, values.state === 'reviewed'))}
+
+ Decisão declarada
+
+ change('decision', e.target.value)
+ }
+ >
+ Ainda sem decisão
+ {Object.entries(props.decisions).map(
+ ([k, label]) => (
+
+ {label}
+
+ ),
+ )}
+
+
+ {field('decision_reason', values.state === 'reviewed')}
+
+
+ setConfirmObservation(e.target.checked)
+ }
+ />{' '}
+ Confirmei que estas observações se referem ao plano
+ desta versão
+
+
+ Serviço do relatório de contexto
+
+ change('report_service', e.target.value)
+ }
+ >
+ Todos os serviços
+ {catalogue.services.map((s) => (
+
+ {s.title} ({s.code})
+
+ ))}
+
+
+
+ {
+ setAttachReport(e.target.checked);
+ if (e.target.checked)
+ setRemoveReport(false);
+ }}
+ />{' '}
+ Anexar relatório operacional do período observado ao
+ guardar
+
+
+ Este relatório dá contexto à coorte operacional. Não
+ identifica controlo/variante, não mede o segmento
+ livre acima e não comprova o efeito da alteração.
+
+ {document?.operational_report && (
+
+ {
+ setRemoveReport(e.target.checked);
+ if (e.target.checked)
+ setAttachReport(false);
+ }}
+ />{' '}
+ Retirar o relatório da próxima versão; conservar
+ no histórico
+
+ )}
+
+ )}
+ {!readonly && (
+
+ )}
+
+ {document?.operational_report && (
+
+
+ Relatório operacional conservado nesta versão
+
+
+ Período {document.operational_report.filters.from} a{' '}
+ {document.operational_report.filters.to}; serviço{' '}
+ {document.operational_report.filters.service_code ??
+ 'todos'}
+ . Gerado em {document.operational_report.generated_at}.
+
+ {!document.report_matches_observation && (
+
+ Os filtros deste relatório diferem da observação
+ actual. O relatório anterior foi conservado; pode
+ anexar outro numa nova versão.
+
+ )}
+
+ Não separa grupos da experiência nem comprova
+ causalidade.
+
+
+ {document.operational_report.metrics.map((m) => (
+
+ {m.title}: {usageValue(m.value, m.unit)} ·{' '}
+ {m.state === 'partial'
+ ? 'cobertura parcial'
+ : m.state === 'unmeasured'
+ ? 'sem base para calcular'
+ : 'observado'}
+
+ ))}
+
+
+ )}
+ {document &&
+ document.observation_plan_sha256 !== document.plan_sha256 &&
+ showObservation && (
+
+ As observações conservadas referem-se a um plano
+ anterior. Reveja as diferenças e as evidências antes de
+ as reafirmar para o plano actual.
+
+ )}
+ {props.history.length > 0 && (
+
+ Histórico
+ {props.history.map((h) => (
+
+
+ Versão {h.version}
+ {' '}
+ · {h.at} · {h.actor} ·{' '}
+ {props.states[h.state] ?? h.state}. {h.reason}
+
+ ))}
+ {props.historyNext !== null && (
+
+ Versões anteriores
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/resources/js/pages/management/experiments/index.tsx b/resources/js/pages/management/experiments/index.tsx
new file mode 100644
index 00000000..237a785d
--- /dev/null
+++ b/resources/js/pages/management/experiments/index.tsx
@@ -0,0 +1,122 @@
+import { Link } from '@inertiajs/react';
+import { Frame, card, input, button } from '@/pages/investment/shared';
+
+export default function Experiments({
+ installed,
+ states,
+ filters,
+ items,
+ page,
+ pages,
+ total,
+}: {
+ installed: boolean;
+ states: Record;
+ filters: { state: string };
+ items: {
+ id: string;
+ version: number;
+ state: string;
+ title: string;
+ hypothesis: string;
+ at: string;
+ }[];
+ page: number;
+ pages: number;
+ total: number;
+}) {
+ const url = (p: number) =>
+ '/management/product-experiments?' +
+ new URLSearchParams({ state: filters.state, page: String(p) });
+ return (
+
+
+ Indicadores de utilização
+
+
+ Documente planos, comparações observadas, evidências e decisões.
+ O estado é uma declaração do autor; registar um plano ou uma
+ decisão não publica alterações nem distribui visitantes por
+ variantes.
+
+ {!installed ? (
+
+ O registo ainda não está disponível neste destino. Os
+ indicadores existentes continuam disponíveis.
+
+ ) : (
+ <>
+
+ Preparar experiência
+
+
+
+ Estado
+
+ Todos
+ {Object.entries(states).map(([code, label]) => (
+
+ {label}
+
+ ))}
+
+
+ Filtrar
+
+
+ {total} registos. Página {page} de {pages}.
+
+ {items.length === 0 && (
+ Ainda não existem registos para este filtro.
+ )}
+ {items.map((item) => (
+
+
+
+ {item.title || 'Experiência sem título'}
+
+
+
+ {states[item.state] ?? item.state} · versão{' '}
+ {item.version} · {item.at}
+
+
+ {item.hypothesis ||
+ 'Hipótese ainda por preencher.'}
+
+
+ ))}
+
+ {page > 1 && (
+
+ Anterior
+
+ )}
+ {page < pages && (
+
+ Seguinte
+
+ )}
+
+ >
+ )}
+
+ );
+}
diff --git a/resources/js/pages/management/opportunity-draft.tsx b/resources/js/pages/management/opportunity-draft.tsx
index babb3639..1c8d962d 100644
--- a/resources/js/pages/management/opportunity-draft.tsx
+++ b/resources/js/pages/management/opportunity-draft.tsx
@@ -10,6 +10,9 @@ import { createOperationKey } from '@/lib/operation-key';
import { valueText } from '@/lib/value-text';
import { modalityLabels } from '@/components/opportunity-search-filters';
import OpportunityProfileActions from '@/components/opportunity-profile-actions';
+import OpportunityTechnicalIncidents, {
+ type OpportunityTechnicalIncident,
+} from '@/components/opportunity-technical-incidents';
import OpportunityContactForm from '@/components/opportunity-contact-form';
import OpportunityCanonicalFields, {
type CanonicalOptions,
@@ -89,6 +92,7 @@ export default function OpportunityDraft({
workflowState,
canonicalResponse,
workflowTasks = [],
+ workflowIncidents = [],
workflowParticipants,
publicationPreview,
publicationState,
@@ -101,6 +105,7 @@ export default function OpportunityDraft({
profileMode?: boolean;
profileOrganization?: string | null;
profileActions?: string[];
+ workflowIncidents?: OpportunityTechnicalIncident[];
profileReauthenticationRequired?: boolean;
profileContext?: Record | null;
profileAccess?: {
@@ -1259,6 +1264,9 @@ export default function OpportunityDraft({
)}
+ {profileMode && record && (
+
+ )}
{profileMode && record && etag && (
+
Regressar ao rascunho #{opportunity.id}
diff --git a/resources/js/pages/management/proactive-supply-review.tsx b/resources/js/pages/management/proactive-supply-review.tsx
new file mode 100644
index 00000000..1d671d43
--- /dev/null
+++ b/resources/js/pages/management/proactive-supply-review.tsx
@@ -0,0 +1,419 @@
+import { Link } from '@inertiajs/react';
+import { Management, button, control } from './shared';
+
+type Filters = {
+ source_hash?: string | null;
+ observation_id?: string | null;
+ q?: string | null;
+ status: string;
+ page: number;
+};
+type Observation = {
+ id: string;
+ name: string;
+ province: string;
+ district: string;
+ territory_id: string | null;
+ territory_resolution: string;
+ canonical_territory: string | null;
+ canonical_type: string | null;
+ cae: string;
+ activity: string;
+ sector: string;
+ source_date: string;
+ sheet: string;
+ row_number: number;
+ source_hash: string;
+ identity_conflict: boolean;
+ duplicate_of: string | null;
+ source_name: string;
+ source_period: string;
+ imported_at: string;
+};
+type Source = {
+ sha256: string;
+ name: string;
+ period: string;
+ limitations: string;
+ imported_at: string;
+};
+type Coverage = {
+ observations: number;
+ distinct_observations: number;
+ repeated: number;
+ unmapped: number;
+ ambiguous: number;
+ territory_unavailable: number;
+ identity_conflict: number;
+ unclassified: number;
+ unnamed: number;
+};
+type Props = {
+ installed: boolean;
+ filters: Filters;
+ sources: Source[];
+ coverage: Coverage | null;
+ rows: Observation[];
+ total: number | null;
+ per_page: number;
+ limitations: string;
+ status: string;
+ recordId?: number | null;
+ errors?: Record;
+};
+const resolutions: Record = {
+ exact_normalized_province_district:
+ 'Distrito identificado dentro da província',
+ exact_normalized_province_subterritory:
+ 'Território subordinado identificado dentro da província',
+ province_only_district_unknown: 'Apenas província; distrito por determinar',
+ ambiguous: 'Várias correspondências possíveis, sem escolha automática',
+ unresolved: 'Sem correspondência inequívoca',
+};
+const states: Record = {
+ all: 'Todas as observações',
+ unmapped: 'Sem correspondência territorial',
+ ambiguous: 'Correspondência territorial ambígua',
+ territory_unavailable: 'Referência territorial indisponível',
+ identity_conflict: 'Identificador com denominações divergentes',
+ repeated: 'Projecções administrativas repetidas',
+ unclassified: 'Sem designação da actividade',
+ unnamed: 'Sem denominação social',
+};
+export function supplyReviewUrl(
+ filters: Partial,
+ recordId?: number | null,
+): string {
+ const values = Object.entries({
+ ...filters,
+ ...(recordId ? { record_id: recordId } : {}),
+ }).filter(
+ ([, value]) => value !== undefined && value !== null && value !== '',
+ );
+ const query = new URLSearchParams(
+ values.map(([key, value]) => [key, String(value)]),
+ );
+ return (
+ '/minhas-oportunidades/oferta-interna/revisao' +
+ (query.size ? `?${query}` : '')
+ );
+}
+export default function SupplyReview({
+ installed,
+ filters,
+ sources,
+ coverage,
+ rows,
+ total,
+ per_page,
+ limitations,
+ status,
+ recordId,
+ errors = {},
+}: Props) {
+ const pages = total === null ? 1 : Math.max(1, Math.ceil(total / per_page));
+ return (
+
+
+ Voltar à preparação de oportunidades
+
+ {limitations}
+
+ Consulta das observações já importadas, incluindo pendências que
+ não entram na pesquisa por território. Esta página não altera
+ linhas, correspondências ou cadastros, não consolida entidades e
+ não publica empresas.
+
+
+ {recordId && (
+
+ )}
+
+ Origem
+
+ Todas as origens
+ {sources.map((source) => (
+
+ {source.name}
+
+ ))}
+
+
+
+ Conferir
+
+ {Object.entries(states).map(([value, label]) => (
+
+ {label}
+
+ ))}
+
+
+
+ Nome, local original ou actividade
+
+
+ Pesquisar observações
+
+ {Object.entries(errors).map(([key, message]) => (
+
+ {message}
+
+ ))}
+ {filters.observation_id && (
+
+ Está a consultar uma referência específica.{' '}
+
+ Retirar filtro da referência
+
+
+ )}
+ {!installed && (
+
+ A base interna ainda não está carregada neste ambiente.
+
+ )}
+ {coverage && (
+
+
+ Cobertura documental da origem seleccionada
+
+
+ Contagens anteriores aos filtros de estado, texto e
+ referência; todas as origens quando nenhuma é
+ seleccionada. Os indicadores de pendência podem
+ sobrepor-se.
+
+
+ {(
+ [
+ [
+ 'observations',
+ 'Observações retidas (inclui repetições)',
+ ],
+ [
+ 'distinct_observations',
+ 'Projecções administrativas distintas',
+ ],
+ [
+ 'repeated',
+ 'Projecções repetidas conservadas',
+ ],
+ ['unmapped', 'Sem território canónico'],
+ ['ambiguous', 'Territórios ambíguos'],
+ [
+ 'territory_unavailable',
+ 'Referências territoriais indisponíveis',
+ ],
+ [
+ 'identity_conflict',
+ 'Observações com divergências de identidade',
+ ],
+ [
+ 'unclassified',
+ 'Sem designação de actividade',
+ ],
+ ['unnamed', 'Sem denominação social'],
+ ] as [keyof Coverage, string][]
+ ).map(([key, label]) => (
+
+
{label}
+
+ {coverage[key].toLocaleString('pt-MZ')}
+
+
+ ))}
+
+
+ Estas contagens não são números de empresas únicas,
+ estabelecimentos em funcionamento ou necessidades de
+ investimento confirmadas.
+
+
+ )}
+
+ {status}
+ {total !== null && (
+ <>
+ {' '}
+ {total.toLocaleString('pt-MZ')} observações nestes
+ filtros.
+ >
+ )}
+
+
+ {rows.map((row) => (
+
+
+ {row.name || 'Denominação não indicada'}
+
+
+ Local escrito no original:{' '}
+ {row.province || 'província não indicada'} /{' '}
+ {row.district || 'distrito não indicado'}.
+
+
+ Correspondência guardada:{' '}
+ {resolutions[row.territory_resolution] ||
+ 'por conferir'}
+ . Referência territorial consultável:{' '}
+ {row.canonical_territory || 'não disponível'}. Não é
+ uma georreferenciação por coordenadas.
+
+
+ CAE: {row.cae || 'não indicado'} · Actividade:{' '}
+ {row.activity || 'sem designação correspondente'} ·
+ Sector CAE: {row.sector || 'não correspondido'}.
+
+ {row.identity_conflict && (
+
+ Identificador partilhado por denominações
+ divergentes. A identidade continua por conferir;
+ não foi feita fusão automática.
+
+ )}
+ {row.duplicate_of && (
+
+ Projecção repetida, conservada para
+ rastreabilidade.{' '}
+
+ Conferir a observação de referência
+
+ . Não conte esta linha como outra empresa.
+
+ )}
+
+ Fonte: {row.source_name} · {row.sheet}, linha{' '}
+ {row.row_number}. Data original:{' '}
+ {row.source_date || 'não indicada'}. Período do
+ exemplar: {row.source_period || 'não determinado'}.
+
+
+ Importação registada em {row.imported_at}; não
+ representa actualização ou confirmação da actividade
+ da empresa.
+
+
+
+ Referência e integridade da origem
+
+
+ SHA256 do original: {row.source_hash}.
+
+
+ Código da correspondência:{' '}
+ {row.territory_resolution || 'não indicado'}.
+
+
+
+ Ligação para recuperar esta linha
+
+
+ ))}
+
+ {total !== null && total > 0 && (
+
+ {filters.page > 1 && (
+
+ Anterior
+
+ )}
+
+ Página {filters.page} de {pages}
+
+ {filters.page < pages && (
+
+ Seguinte
+
+ )}
+
+ )}
+
+ Origens disponíveis e limites dos exemplares
+ {sources.map((source) => (
+
+
{source.name}
+
+ {source.period}. {source.limitations}
+
+
Registo da importação: {source.imported_at}.
+
+ ))}
+
+
+ );
+}
diff --git a/resources/js/pages/management/product-usage.tsx b/resources/js/pages/management/product-usage.tsx
new file mode 100644
index 00000000..d1646d52
--- /dev/null
+++ b/resources/js/pages/management/product-usage.tsx
@@ -0,0 +1,267 @@
+import { Link, usePage } from '@inertiajs/react';
+import { Frame, card, input, button } from '@/pages/investment/shared';
+import { usageExport, usageValue, type UsageReport } from '@/lib/product-usage';
+import SearchUsage from '@/components/search-usage-report';
+
+const coverageLabels: Record = {
+ cohort_requests: 'Pedidos na coorte',
+ complete_histories: 'Com historial completo',
+ unknown_histories: 'Sem historial suficiente',
+ classified_returned_requests: 'Devolvidos com causa determinada',
+ unclassified_returned_requests: 'Devolvidos com causa por classificar',
+ valid_duration_requests: 'Com duração válida',
+ invalid_duration_requests: 'Com intervalo negativo excluído',
+};
+
+export default function ProductUsage({ report }: { report: UsageReport }) {
+ const { errors } = usePage().props;
+ function download() {
+ const url = URL.createObjectURL(
+ new Blob([usageExport(report)], { type: 'application/json' }),
+ );
+ const anchor = document.createElement('a');
+ anchor.href = url;
+ anchor.download = `indicadores-${report.filters.from}-${report.filters.to}.json`;
+ anchor.click();
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
+ }
+ return (
+
+
+
+ Voltar ao painel
+
+
+ Registo de experiências e decisões
+
+
+
+ Leitura dos registos operacionais disponíveis. Cada indicador
+ apresenta a sua base e as limitações de cobertura.
+
+
+
+ Desde (UTC)
+
+
+
+ Até (UTC)
+
+
+
+ Serviço
+
+ Todos os serviços
+ {report.services.map((s) => (
+
+ {s.title} ({s.code})
+
+ ))}
+
+
+ {report.search && (
+
+ Edição da recolha de pesquisa
+
+ {report.search.available_definitions.map(
+ (version) => (
+
+ {version}
+
+ ),
+ )}
+
+
+ )}
+ Aplicar filtros
+ {Object.entries(errors).map(([k, v]) => (
+
+ {String(v)}
+
+ ))}
+
+
+
+ Período aplicado: {report.filters.from} a{' '}
+ {report.filters.to}, em {report.timezone}. Serviço:{' '}
+ {report.filters.service_code ?? 'todos'}.
+
+
+ {report.search ? (
+ <>
+ Eventos do Balcão anteriores a{' '}
+ {report.observed_before}. Pesquisas usam as
+ contagens diárias na leitura indicada abaixo.
+ >
+ ) : (
+ <>Observações anteriores a {report.observed_before}.>
+ )}{' '}
+ Relatório gerado em {report.generated_at}.
+
+
+ Exportar este relatório (JSON)
+
+
+ {report.search && }
+
+
+ Cobertura da coorte de pedidos
+
+
+ {Object.entries(report.coverage).map(([key, value]) => (
+
+
{coverageLabels[key] ?? key}
+
+ {usageValue(value)}
+
+
+ ))}
+
+
+ Pedidos sem historial suficiente ficam fora das taxas. Uma
+ base vazia ou desconhecida não produz uma taxa de 0%.
+
+
+
+
+
+ Indicadores observáveis
+
+
+
+ Indicador
+ Valor
+ Base
+ Definição e limites
+
+
+
+ {report.metrics.map((m) => (
+
+
+ {m.title}
+
+
+ {usageValue(m.value, m.unit)}
+
+ {m.state === 'partial'
+ ? 'Cobertura parcial'
+ : m.state === 'unmeasured'
+ ? 'Sem base para calcular'
+ : 'Observado'}
+
+
+
+ {m.numerator !== null && (
+
+ Numerador: {usageValue(m.numerator)}
+
+ )}
+ {m.denominator !== null && (
+
+ Denominador:{' '}
+ {usageValue(m.denominator)}
+
+ )}
+ {m.numerator === null &&
+ m.denominator === null &&
+ 'Contagem directa'}
+
+
+
+
+ Consultar definição
+
+ {m.source}
+ {m.limits}
+
+
+
+ ))}
+
+
+
+
+
+ Indicadores ainda sem medição
+
+ {report.unmeasured.map((m) => (
+
+
+ {m.title}
+
+ {m.reason}
+ {m.href && (
+
+ Consultar registo
+
+ )}
+
+ ))}
+
+
+
+ Como interpretar
+
+
+ {report.limits.map((l) => (
+ {l}
+ ))}
+
+
+
+ Identificação do relatório
+
+ Definição: {report.definition_version}
+ SHA-256: {report.fingerprint}
+ Consistência da leitura: {report.read_consistency}
+
+
+
+ );
+}
diff --git a/resources/js/pages/management/shared.tsx b/resources/js/pages/management/shared.tsx
index fd8392e8..e9244ebd 100644
--- a/resources/js/pages/management/shared.tsx
+++ b/resources/js/pages/management/shared.tsx
@@ -54,7 +54,7 @@ export function Management({
const { flash, educationEnabled, aiEnabled, auth, basePath } = usePage<{
auth?: { canManagePortal?: boolean };
basePath?: string;
- flash?: { success?: string };
+ flash?: { success?: string; warning?: string };
educationEnabled?: boolean;
aiEnabled?: boolean;
}>().props;
@@ -126,6 +126,14 @@ export function Management({
{flash.success}
)}
+ {flash?.warning && (
+
+ {flash.warning}
+
+ )}
{children}
);
diff --git a/resources/js/pages/partnerships/agreement-history.tsx b/resources/js/pages/partnerships/agreement-history.tsx
new file mode 100644
index 00000000..401769e6
--- /dev/null
+++ b/resources/js/pages/partnerships/agreement-history.tsx
@@ -0,0 +1,199 @@
+import { Link } from '@inertiajs/react';
+import AgreementInstrument from '@/components/partnership-agreement-instrument';
+import { Frame, labels } from './shared';
+
+type Availability =
+ | 'available'
+ | 'not_recorded'
+ | 'scope_unknown'
+ | 'restricted'
+ | 'malformed';
+type Snapshot = {
+ availability: Availability;
+ version?: number;
+ status?: string;
+ instrument_availability?: Availability;
+ instrument?: unknown;
+ instrument_partnership_version?: number;
+ instrument_interest_version?: number;
+};
+type Entry = {
+ version: number | null;
+ restricted: boolean;
+ action: string | null;
+ actor_name: string | null;
+ occurred_at: string | null;
+ reason: string | null;
+ confirmation_party: string | null;
+ partnership_version: number | null;
+ interest_version: number | null;
+ previous: Snapshot;
+ after: Snapshot;
+};
+type Props = {
+ room_id: number;
+ entries: Entry[];
+ first_url: string;
+ next_url: string | null;
+ older_page: boolean;
+ room_href: string;
+ dashboard_href: string;
+};
+const actions: Record = {
+ record: 'Registo de instrumento',
+ confirm: 'Confirmação de parte',
+ start: 'Início do acompanhamento',
+ complete: 'Conclusão',
+ cancel: 'Cancelamento',
+ renew: 'Renovação',
+};
+const unavailable: Record = {
+ not_recorded:
+ 'Esta informação não ficou guardada no evento. Não foi preenchida com a versão actual.',
+ scope_unknown:
+ 'O âmbito deste registo antigo não ficou identificado; o conteúdo não está disponível para esta conta.',
+ restricted:
+ 'O registo pertence a uma representação à qual esta conta não tem acesso actual.',
+ malformed:
+ 'O instrumento guardado não tem uma estrutura reconhecida. O registo foi conservado.',
+};
+function Version({ value, title }: { value: Snapshot; title: string }) {
+ return (
+
+ {title}
+ {value.availability !== 'available' ? (
+ {unavailable[value.availability]}
+ ) : (
+ <>
+
+ Versão da sala {value.version} ·{' '}
+ {labels[value.status ?? ''] ??
+ value.status ??
+ 'Estado não registado'}
+
+ {value.instrument_availability !== 'available' ? (
+
+ {
+ unavailable[
+ value.instrument_availability ??
+ 'not_recorded'
+ ]
+ }
+
+ ) : (
+ <>
+
+ Contexto do instrumento: proposta{' '}
+ {value.instrument_partnership_version ??
+ 'não registada'}{' '}
+ · candidatura{' '}
+ {value.instrument_interest_version ??
+ 'não registada'}
+ .
+
+
+ >
+ )}
+ >
+ )}
+
+ );
+}
+export default function AgreementHistory(p: Props) {
+ return (
+
+
+
+
+ Voltar à sala
+
+
+ Painel de parcerias
+
+ {p.older_page && (
+
+ Versões mais recentes
+
+ )}
+
+
+ Consulta das decisões e instrumentos guardados, do mais
+ recente para o mais antigo. Os nomes de pessoas provêm do
+ cadastro actual; as condições, motivos e confirmações são os
+ que ficaram registados. Esta consulta não altera decisões
+ nem certifica assinatura jurídica.
+
+ {!p.entries.length && (
+
+ Ainda não existem alterações do acordo guardadas para
+ apresentar.
+
+ )}
+ {p.entries.map((entry, index) => (
+
+
+ Versão {entry.version ?? 'não registada'} ·{' '}
+ {entry.restricted
+ ? 'Conteúdo reservado'
+ : (actions[entry.action ?? ''] ??
+ 'Alteração registada')}
+
+ {!entry.restricted && (
+ <>
+
+ {entry.actor_name ?? 'Autor não registado'}{' '}
+ ·{' '}
+ {entry.occurred_at ?? 'Data não registada'}
+
+
+ Contexto da decisão: proposta{' '}
+ {entry.partnership_version ??
+ 'não registada'}{' '}
+ · candidatura{' '}
+ {entry.interest_version ?? 'não registada'}.
+
+ {entry.confirmation_party && (
+
+ Parte que confirmou:{' '}
+ {entry.confirmation_party ===
+ 'proponent'
+ ? 'Proponente'
+ : 'Candidata'}
+ .
+
+ )}
+ {entry.reason !== null && (
+
+ Motivo: {entry.reason || 'Não indicado'}
+
+ )}
+ >
+ )}
+
+
+
+
+
+ ))}
+ {p.next_url && (
+
+ Consultar versões anteriores
+
+ )}
+
+
+ );
+}
diff --git a/resources/js/pages/partnerships/dashboard.tsx b/resources/js/pages/partnerships/dashboard.tsx
index f6f3bddb..449c3f5f 100644
--- a/resources/js/pages/partnerships/dashboard.tsx
+++ b/resources/js/pages/partnerships/dashboard.tsx
@@ -5,7 +5,8 @@ type Props = {
interests: {
id: number;
partnership_id: number;
- title: string;
+ title: string | null;
+ partnership_href: string | null;
status: string;
decision_reason: string | null;
room_id: number | null;
@@ -38,6 +39,14 @@ export default function Dashboard(p: Props) {
{x.title || 'Ideia sem título'}
{labels[x.status] ?? x.status}
+
+
+ Consultar versões e decisões da publicação
+
+
Próxima ação:{' '}
{['draft', 'returned', 'rejected'].includes(
@@ -57,15 +66,30 @@ export default function Dashboard(p: Props) {
{p.interests.map((x) => (
-
- {x.title}
-
+ {x.partnership_href ? (
+
+ {x.title || 'Parceria sem título'}
+
+ ) : (
+
+ Parceria {x.partnership_id} · consulta da
+ proposta indisponível com o acesso actual
+
+ )}
{labels[x.status]} · {x.decision_reason}
+
+
+ Consultar versões e decisões
+
+
{x.room_id && (
{x.title} · {labels[x.status]}
+ {' · '}
+
+ Histórico da publicação
+
))}
@@ -96,6 +127,12 @@ export default function Dashboard(p: Props) {
Notificações no portal
+
+ São apresentados os avisos cuja consulta está autorizada
+ no âmbito actual e no que ficou guardado no evento.
+ Avisos antigos sem esse âmbito identificável permanecem
+ no registo.
+
{p.notifications.map((n) => (
diff --git a/resources/js/pages/partnerships/detail.tsx b/resources/js/pages/partnerships/detail.tsx
index cdb25794..72ed39d0 100644
--- a/resources/js/pages/partnerships/detail.tsx
+++ b/resources/js/pages/partnerships/detail.tsx
@@ -1,13 +1,15 @@
-import { Link, useForm, usePage } from '@inertiajs/react';
+import { useState } from 'react';
+import PartnershipPublication from '@/components/partnership-publication';
+import PublicationSummary from '@/components/partnership-publication-summary';
+import type { PublicationHistorySummary } from '@/lib/partnership-history';
+import { Link, usePage } from '@inertiajs/react';
+import PartnershipCandidacies from '@/components/partnership-candidacies';
import { ComplementEntryActions } from '@/components/investment-complements';
import StructureGeographyPanel, {
type StructureGeography,
} from '@/components/structure-geography';
import {
Frame,
- Errors,
- Field,
- control,
button,
labels,
type Catalogues,
@@ -16,10 +18,14 @@ import {
type Source,
} from './shared';
type Props = Catalogues & {
+ publicationActions: string[];
+ publicationCommands: { key: string; action: string; version: number }[];
record: Partnership;
owner: boolean;
canEdit: boolean;
moderator: boolean;
+ acceptingInterests: boolean;
+ canStartInterest: boolean;
origins: (Source & { geography: StructureGeography | null })[];
locations: {
id: string;
@@ -29,454 +35,11 @@ type Props = Catalogues & {
path: { name: string }[];
}[];
interests: Interest[];
- history: {
- event_type: string;
- actor_id: number;
- occurred_at: string;
- payload: string;
- }[];
+ historySummary: PublicationHistorySummary | null;
};
-function Publication({ p }: { p: Props }) {
- const form = useForm({ version: p.record.version, action: '', reason: '' });
- const action = (value: string) => {
- form.transform((data) => ({ ...data, action: value }));
- form.post('/parcerias/' + p.record.id + '/estado', {
- preserveScroll: true,
- });
- };
- return (
-
- Pré-visualização e publicação
-
- Estado: {labels[p.record.status] ?? p.record.status}.
- Verificação da organização, setor e localização permanecem por
- confirmar quando não há evidência.
-
-
- form.setData('reason', e.target.value)}
- />
-
-
-
- {p.canEdit &&
- ['draft', 'returned', 'rejected'].includes(
- p.record.status,
- ) && (
- action('submit')}
- >
- Submeter para publicação
-
- )}
- {p.moderator &&
- !p.owner &&
- ['submitted', 'pending'].includes(p.record.status) &&
- ['publish', 'return', 'reject'].map((value) => (
- action(value)}
- >
- {
- {
- publish: 'Publicar',
- return: 'Devolver para correção',
- reject: 'Rejeitar com fundamento',
- }[value]
- }
-
- ))}
- {p.canEdit &&
- ['published', 'suspended', 'archived'].includes(
- p.record.status,
- ) && (
- action('renew')}
- >
- Renovar em rascunho
-
- )}
- {p.canEdit &&
- ['draft', 'published', 'suspended', 'rejected'].includes(
- p.record.status,
- ) && (
- action('archive')}
- >
- Arquivar publicação
-
- )}
- {p.canEdit && (
-
- Editar rascunho
-
- )}
-
-
- );
-}
-function InterestForm({
- record,
- interest,
- organizations,
-}: {
- record: Partnership;
- interest?: Interest;
- organizations: Catalogues['organizations'];
-}) {
- const form = useForm({
- version: interest?.version ?? null,
- organization_id: interest?.organization_id ?? '',
- proposal: interest?.proposal ?? '',
- payload: {
- capacity: interest?.payload.capacity ?? '',
- availability: interest?.payload.availability ?? '',
- contribution: interest?.payload.contribution ?? '',
- conflicts: interest?.payload.conflicts ?? '',
- consent: interest?.payload.consent ?? false,
- },
- });
- return (
- {
- e.preventDefault();
- form.post('/parcerias/' + record.id + '/interesses', {
- preserveScroll: true,
- });
- }}
- >
-
- {interest
- ? 'Atualizar manifestação de interesse'
- : 'Manifestar interesse'}
-
-
- Declarações são informações comunicadas por si; não atribuem
- verificação. Dados desconhecidos podem ser esclarecidos no
- processo.
-
-
-
-
- form.setData('organization_id', e.target.value)
- }
- >
- Participação pessoal
- {organizations.map((o) => (
-
- {o.name}
-
- ))}
-
-
-
- form.setData('proposal', e.target.value)}
- />
-
- {(
- [
- 'capacity',
- 'availability',
- 'contribution',
- 'conflicts',
- ] as const
- ).map((key) => (
-
-
- form.setData('payload', {
- ...form.data.payload,
- [key]: e.target.value,
- })
- }
- />
-
- ))}
-
-
- form.setData('payload', {
- ...form.data.payload,
- consent: e.target.checked,
- })
- }
- />{' '}
- Autorizo a partilha desta candidatura com o responsável pela
- parceria.
-
-
- Guardar interesse
-
-
- );
-}
-function Candidacy({
- interest,
- owner,
- canEdit,
- record,
- organizations,
-}: {
- interest: Interest;
- owner: boolean;
- canEdit: boolean;
- record: Partnership;
- organizations: Catalogues['organizations'];
-}) {
- const assessment = Object.fromEntries(
- interest.match.criteria.map((c) => [
- c.code,
- {
- state: interest.assessment[c.code]?.state ?? 'unknown',
- evidence: interest.assessment[c.code]?.evidence ?? '',
- },
- ]),
- );
- const form = useForm({
- version: interest.version,
- action: '',
- reason: '',
- assessment,
- });
- const act = (action: string) => {
- form.transform((data) => ({
- ...data,
- action,
- assessment: action === 'assess' ? data.assessment : {},
- }));
- form.post('/parcerias/candidaturas/' + interest.id, {
- preserveScroll: true,
- });
- };
- return (
-
-
- Candidatura {interest.id} · {labels[interest.status]}
-
- {interest.proposal}
- {interest.payload.capacity}
-
- Disponibilidade:{' '}
- {interest.payload.availability || 'Por esclarecer'}
-
-
- Contribuição:{' '}
- {interest.payload.contribution || 'Por esclarecer'}
-
-
- Conflitos declarados:{' '}
- {interest.payload.conflicts || 'Sem informação'}
-
- {interest.decision_reason && (
- Última decisão: {interest.decision_reason}
- )}
-
- Correspondência: {interest.match.score_min}–
- {interest.match.score_max}% · Elegibilidade:{' '}
- {labels[interest.match.eligibility]}. O intervalo distingue
- dados desconhecidos de incumprimentos; não é uma aprovação.
-
-
- {interest.match.criteria.map((c) => (
-
- {c.label} · peso {c.weight} · {labels[c.state]}
- {c.mandatory ? ' · Obrigatório' : ''}
- {c.evidence && <> · Evidência: {c.evidence}>}
- {c.explanation}
-
- ))}
-
- {interest.room_id && (
-
- Abrir conexão privada
-
- )}
- {owner &&
- canEdit &&
- ['submitted', 'clarification', 'shortlisted'].includes(
- interest.status,
- ) && (
- <>
-
- Registar avaliação fundamentada
- {interest.match.criteria.map((c) => (
-
-
-
- form.setData('assessment', {
- ...form.data.assessment,
- [c.code]: {
- ...form.data.assessment[
- c.code
- ],
- state: e.target.value,
- },
- })
- }
- >
- {['unknown', 'met', 'unmet'].map(
- (state) => (
-
- {labels[state]}
-
- ),
- )}
-
-
-
-
- form.setData('assessment', {
- ...form.data.assessment,
- [c.code]: {
- ...form.data.assessment[
- c.code
- ],
- evidence:
- e.target.value,
- },
- })
- }
- />
-
-
- ))}
-
-
-
- form.setData('reason', e.target.value)
- }
- />
-
-
- {[
- 'assess',
- 'clarify',
- 'shortlist',
- 'reject',
- ...(interest.status === 'shortlisted'
- ? ['connect']
- : []),
- ].map((action) => (
- act(action)}
- >
- {
- {
- assess: 'Guardar avaliação',
- clarify: 'Pedir esclarecimento',
- shortlist:
- 'Adicionar à lista curta',
- reject: 'Não selecionar',
- connect: 'Abrir negociação',
- }[action]
- }
-
- ))}
-
- >
- )}
- {!owner &&
- ['submitted', 'clarification', 'shortlisted'].includes(
- interest.status,
- ) && (
- <>
-
-
- form.setData('reason', e.target.value)
- }
- />
-
- act('withdraw')}
- >
- Retirar candidatura
-
- >
- )}
- {!owner &&
- ['submitted', 'clarification', 'withdrawn'].includes(
- interest.status,
- ) && (
-
- )}
-
-
- );
-}
export default function Detail(p: Props) {
- const { auth } = usePage<{ auth: { user: unknown } }>().props;
+ const { auth } = usePage<{ auth: { user: { id: number } | null } }>().props;
+ const [publicationDirty, setPublicationDirty] = useState(false);
return (
@@ -548,8 +111,13 @@ export default function Detail(p: Props) {
)}
))}
- {(p.owner || p.moderator) && (
-
+ {auth.user && (
+
)}
{p.owner && p.interests.length > 0 && (
@@ -589,40 +157,18 @@ export default function Detail(p: Props) {
)}
- {p.interests.map((i) => (
-
- ))}
- {!p.owner &&
- p.record.status === 'published' &&
- auth.user &&
- !p.interests.length && (
-
- )}
+
{!auth.user && p.record.status === 'published' && (
Entrar para manifestar interesse
)}
- {p.history.length > 0 && (
-
- Histórico e decisões
- {p.history.map((h, i) => (
-
- {h.occurred_at} · Autor {h.actor_id} ·{' '}
- {h.event_type}
-
- ))}
-
+ {(p.owner || p.moderator) && p.historySummary && (
+
)}
diff --git a/resources/js/pages/partnerships/editor.tsx b/resources/js/pages/partnerships/editor.tsx
index e216c84f..435666b7 100644
--- a/resources/js/pages/partnerships/editor.tsx
+++ b/resources/js/pages/partnerships/editor.tsx
@@ -1,55 +1,22 @@
-import { createOperationKey } from '@/lib/operation-key';
-import { Link, useForm } from '@inertiajs/react';
+import { Link } from '@inertiajs/react';
import { useState } from 'react';
+import {
+ usePartnershipEdit,
+ type PartnershipEditProps,
+} from '@/lib/partnership-edit';
+import PartnershipEditComparison from '@/components/partnership-edit-comparison';
import {
Frame,
Field,
Errors,
control,
button,
- type Partnership,
type Catalogues,
} from './shared';
-type Location = {
- geo_location_id: string;
- role: string;
- source_reference: string;
-};
-type Origin = { type: string; target_id: string };
-type Props = Catalogues & {
- record: Partnership | null;
- locations: Location[];
- origins: Origin[];
-};
+type Props = Catalogues & PartnershipEditProps;
function Editor(p: Props) {
- const form = useForm({
- client_key: createOperationKey(),
- version: p.record?.version ?? null,
- title: p.record?.title ?? '',
- offer: p.record?.offer ?? '',
- seeking: p.record?.seeking ?? '',
- organization_id: p.record?.organization_id ?? '',
- sector_id: p.record?.sector_id?.toString() ?? '',
- kind: p.record?.kind ?? 'seeking',
- partnership_type: p.record?.partnership_type ?? '',
- deadline: p.record?.deadline ?? '',
- payload: {
- summary: p.record?.payload.summary ?? '',
- requirements: p.record?.payload.requirements ?? '',
- mandatory: p.record?.payload.mandatory ?? ([] as string[]),
- confidentiality: p.record?.payload.confidentiality ?? 'public',
- consent: p.record?.payload.consent ?? false,
- },
- locations: p.locations.map((x) => ({
- geo_location_id: x.geo_location_id,
- role: x.role,
- source_reference: x.source_reference,
- })),
- origins: p.origins.map((x) => ({
- type: x.type,
- target_id: x.target_id,
- })),
- });
+ const edit = usePartnershipEdit(p);
+ const form = edit.form;
const [place, setPlace] = useState('');
const [role, setRole] = useState('primary');
const [source, setSource] = useState('Declaração do proponente');
@@ -65,384 +32,493 @@ function Editor(p: Props) {
className="space-y-5"
onSubmit={(e) => {
e.preventDefault();
- if (p.record) form.put('/parcerias/' + p.record.id);
- else form.post('/parcerias/rascunhos');
+ edit.save();
}}
>
-
- form.setData('title', e.target.value)}
- />
-
-
-
-
- form.setData('organization_id', e.target.value)
- }
- >
-
- Ideia pessoal — sem organização indicada
-
- {p.organizations.map((x) => (
-
- {x.name}
-
- ))}
-
-
-
-
- form.setData('kind', e.target.value)
- }
- >
- Procura
- Oferta
-
-
-
-
- form.setData('partnership_type', e.target.value)
- }
- >
- Por definir
- {Object.entries(p.types).map(([k, v]) => (
-
- {v}
-
- ))}
-
-
-
-
- form.setData('sector_id', e.target.value)
- }
- >
- Por definir
- {p.sectors.map((x) => (
-
- {x.name}
-
- ))}
-
-
-
-
-
- form.setData('payload', {
- ...form.data.payload,
- summary: e.target.value,
- })
- }
- />
-
-
- form.setData('offer', e.target.value)}
- />
-
-
-
- form.setData('seeking', e.target.value)
- }
- />
-
-
-
- form.setData('payload', {
- ...form.data.payload,
- requirements: e.target.value,
- })
- }
- />
-
-
-
- Critérios obrigatórios expressos da proposta
-
-
- Marque apenas condições necessárias. Critérios
- desejáveis servem a pontuação. Informação desconhecida
- exige esclarecimento e não constitui incumprimento
- comprovado.
-
- {Object.entries(p.criteria).map(([k, v]) => (
-
-
- form.setData('payload', {
- ...form.data.payload,
- mandatory: e.target.checked
- ? [
- ...form.data.payload
- .mandatory,
- k,
- ]
- : form.data.payload.mandatory.filter(
- (x) => x !== k,
- ),
- })
- }
- />{' '}
- {v}
-
- ))}
-
-
-
- Localizações e abrangência
-
- A localização de uma origem fica como contexto. Só
- acrescente uma localização própria com fonte; não se
- deduz por proximidade ou pertença a cluster.
-
-
-
+
+
setPlace(e.target.value)}
+ value={form.data.organization_id}
+ onChange={(e) =>
+ edit.setData(
+ 'organization_id',
+ e.target.value,
+ )
+ }
>
- Escolher território
- {p.territories.map((x) => (
+
+ Sem organização indicada
+
+ {form.data.organization_id &&
+ !p.organizations.some(
+ (organization) =>
+ String(organization.id) ===
+ form.data.organization_id,
+ ) && (
+
+ Organização anteriormente indicada —
+ fora da lista actual
+
+ )}
+ {p.organizations.map((x) => (
- {x.name} · {x.location_type}
+ {x.name}
+
+ ))}
+
+
+ A autoria mantém-se. Sem organização ligada, só
+ o proponente originalmente registado pode editar
+ esta proposta.
+
+
+
+
+ edit.setData('kind', e.target.value)
+ }
+ >
+ Procura
+ Oferta
+
+
+
+
+ edit.setData(
+ 'partnership_type',
+ e.target.value,
+ )
+ }
+ >
+ Por definir
+ {form.data.partnership_type &&
+ !Object.hasOwn(
+ p.types,
+ form.data.partnership_type,
+ ) && (
+
+ Tipo anteriormente indicado — fora
+ da configuração actual
+
+ )}
+ {Object.entries(p.types).map(([k, v]) => (
+
+ {v}
))}
-
+
setRole(e.target.value)}
+ value={form.data.sector_id}
+ onChange={(e) =>
+ edit.setData('sector_id', e.target.value)
+ }
>
- Principal
-
- Área de atuação
-
- Abrangência
+ Por definir
+ {form.data.sector_id &&
+ !p.sectors.some(
+ (sector) =>
+ String(sector.id) ===
+ form.data.sector_id,
+ ) && (
+
+ Sector anteriormente indicado — fora
+ da lista actual
+
+ )}
+ {p.sectors.map((x) => (
+
+ {x.name}
+
+ ))}
-
+
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ summary: e.target.value,
+ }))
+ }
+ />
+
+
+
+ edit.setData('offer', e.target.value)
+ }
+ />
+
+
+
+ edit.setData('seeking', e.target.value)
+ }
+ />
+
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ requirements: e.target.value,
+ }))
+ }
+ />
+
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ availability: event.target.value,
+ }))
+ }
+ />
+
+ Indique quando e em que condições os recursos ou a
+ colaboração estarão disponíveis. O prazo de recepção
+ de interesses é indicado separadamente.
+
+
+
+
+ Critérios obrigatórios expressos da proposta
+
+
+ Marque apenas condições necessárias. Critérios
+ desejáveis servem a pontuação. Informação
+ desconhecida exige esclarecimento e não constitui
+ incumprimento comprovado.
+
+ {Object.entries(p.criteria).map(([k, v]) => (
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ mandatory: e.target.checked
+ ? [...previous.mandatory, k]
+ : previous.mandatory.filter(
+ (x) => x !== k,
+ ),
+ }))
+ }
+ />{' '}
+ {v}
+
+ ))}
+
+ {form.data.payload.mandatory
+ .filter((code) => !Object.hasOwn(p.criteria, code))
+ .map((code) => (
+
+ Critério anteriormente indicado — fora da
+ configuração actual: {code}. Retirá-lo da
+ preparação altera apenas a próxima gravação; o
+ histórico mantém-se.{' '}
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ mandatory:
+ previous.mandatory.filter(
+ (value) => value !== code,
+ ),
+ }))
+ }
+ >
+ Retirar da preparação
+
+
+ ))}
+
+
setSource(e.target.value)}
+ value={form.data.deadline}
+ onChange={(e) =>
+ edit.setData('deadline', e.target.value)
+ }
/>
-
- {
- if (
- !form.data.locations.some(
- (x) =>
- x.geo_location_id === place &&
- x.role === role,
- )
- )
- form.setData('locations', [
- ...form.data.locations,
- {
- geo_location_id: place,
- role,
- source_reference: source,
- },
- ]);
- }}
- >
- Acrescentar localização
-
- {form.data.locations.map((l, i) => (
-
- {
- p.territories.find(
- (t) => t.id === l.geo_location_id,
- )?.name
- }{' '}
- · {l.role} · {l.source_reference}{' '}
-
- form.setData(
- 'locations',
- form.data.locations.filter(
- (_, j) => j !== i,
- ),
- )
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ confidentiality: e.target.value,
+ }))
}
>
- Remover
-
-
- ))}
-
-
- Registos de origem
-
- setOrigin(e.target.value)}
- >
-
- Escolher empresa, investimento, projeto,
- cluster, zona ou ficha
-
- {p.sources?.map((x) => (
-
- {x.title}
+
+ Público após moderação
- ))}
-
-
- {
- const [type, target_id] = origin.split(':');
- if (
- !form.data.origins.some(
- (x) =>
- x.type === type &&
- x.target_id === target_id,
- )
- )
- form.setData('origins', [
- ...form.data.origins,
- { type, target_id },
- ]);
- }}
- >
- Ligar origem
-
- {form.data.origins.map((o, i) => (
-
- {p.sources?.find(
- (x) =>
- x.type === o.type &&
- x.target_id === o.target_id,
- )?.title ?? 'Origem documental ligada'}{' '}
-
- form.setData(
- 'origins',
- form.data.origins.filter(
- (_, j) => j !== i,
- ),
- )
- }
- >
- Remover
-
+
+ Resumo público; detalhes privados
+
+
+
+
+
+
+ Localizações e abrangência
+
+
+ A localização de uma origem fica como contexto. Só
+ acrescente uma localização própria com fonte; não se
+ deduz por proximidade ou pertença a cluster.
- ))}
-
-
-
- form.setData('payload', {
- ...form.data.payload,
- consent: e.target.checked,
- })
- }
- />{' '}
- Autorizo submeter o conteúdo indicado para divulgação no
- âmbito escolhido. Não confirma verificação ou certificação.
-
-
-
- Guardar rascunho
-
- {p.record && (
-
+
+ setPlace(e.target.value)}
+ >
+
+ Escolher território
+
+ {p.territories.map((x) => (
+
+ {x.name} · {x.location_type}
+
+ ))}
+
+
+
+ setRole(e.target.value)}
+ >
+ Principal
+
+ Área de atuação
+
+
+ Abrangência
+
+
+
+
+ setSource(e.target.value)}
+ />
+
+
+ {
+ edit.setData('locations', (previous) =>
+ previous.some(
+ (x) =>
+ x.geo_location_id === place &&
+ x.role === role,
+ )
+ ? previous
+ : [
+ ...previous,
+ {
+ geo_location_id: place,
+ role,
+ source_reference: source,
+ },
+ ],
+ );
+ }}
>
- Pré-visualizar e submeter
-
- )}
-
+ Acrescentar localização
+
+ {form.data.locations.map((l, i) => (
+
+ {
+ p.territories.find(
+ (t) => t.id === l.geo_location_id,
+ )?.name
+ }{' '}
+ · {l.role} · {l.source_reference}{' '}
+
+ edit.setData('locations', (previous) =>
+ previous.filter(
+ (item) =>
+ item.geo_location_id !==
+ l.geo_location_id ||
+ item.role !== l.role,
+ ),
+ )
+ }
+ >
+ Remover
+
+
+ ))}
+
+
+ Registos de origem
+
+ setOrigin(e.target.value)}
+ >
+
+ Escolher empresa, investimento, projeto,
+ cluster, zona ou ficha
+
+ {p.sources?.map((x) => (
+
+ {x.title}
+
+ ))}
+
+
+ {
+ const [type, target_id] = origin.split(':');
+ edit.setData('origins', (previous) =>
+ previous.some(
+ (item) =>
+ item.type === type &&
+ item.target_id === target_id,
+ )
+ ? previous
+ : [...previous, { type, target_id }],
+ );
+ }}
+ >
+ Ligar origem
+
+ {form.data.origins.map((o, i) => (
+
+ {p.sources?.find(
+ (x) =>
+ x.type === o.type &&
+ x.target_id === o.target_id,
+ )?.title ?? 'Origem documental ligada'}{' '}
+
+ edit.setData('origins', (previous) =>
+ previous.filter(
+ (item) =>
+ item.type !== o.type ||
+ item.target_id !==
+ o.target_id,
+ ),
+ )
+ }
+ >
+ Remover
+
+
+ ))}
+
+
+
+ edit.setData('payload', (previous) => ({
+ ...previous,
+ consent: e.target.checked,
+ }))
+ }
+ />{' '}
+ Autorizo submeter o conteúdo indicado para divulgação no
+ âmbito escolhido. Não confirma verificação ou
+ certificação.
+
+
+
+ {edit.retryingCreation
+ ? 'Recuperar gravação anterior'
+ : edit.current?.status === 'published'
+ ? 'Guardar revisão em rascunho'
+ : 'Guardar rascunho'}
+
+ {p.record && (
+
+ Pré-visualizar e submeter
+
+ )}
+
+
);
}
export default function Page(p: Props) {
- return (
-
- );
+ return ;
}
diff --git a/resources/js/pages/partnerships/interest-history.tsx b/resources/js/pages/partnerships/interest-history.tsx
new file mode 100644
index 00000000..facbf3cf
--- /dev/null
+++ b/resources/js/pages/partnerships/interest-history.tsx
@@ -0,0 +1,350 @@
+import { Link } from '@inertiajs/react';
+import { Frame, labels } from './shared';
+
+type Assessment = {
+ code: string;
+ label: string;
+ state: string | null;
+ evidence: string | null;
+ actor_name: string | null;
+ assessed_at: string | null;
+};
+type Snapshot = {
+ availability: 'available' | 'not_recorded' | 'scope_unknown' | 'restricted';
+ version?: number | null;
+ status?: string | null;
+ scope_known?: boolean;
+ organization_id?: string | null;
+ organization_name?: string | null;
+ fields?: Record;
+ consent_known?: boolean;
+ consent?: boolean | null;
+ assessment_recorded?: boolean;
+ assessment?: Assessment[];
+ references?: Record;
+ complete?: boolean;
+};
+type Matching = {
+ algorithm_version: string | null;
+ weights_hash: string | null;
+ eligibility: string | null;
+ score_min: number | null;
+ score_max: number | null;
+ unknown_weight: number | null;
+ criteria: {
+ code: string;
+ label: string | null;
+ state: string | null;
+ weight: number | null;
+ mandatory: boolean | null;
+ evidence: string | null;
+ explanation: string | null;
+ }[];
+};
+type Entry = {
+ version: number | null;
+ restricted: boolean;
+ action: string | null;
+ actor_name: string | null;
+ occurred_at: string | null;
+ reason: string | null;
+ previous: Snapshot;
+ after: Snapshot;
+ matching: Matching | null;
+ partnership_version: number | null;
+};
+type Props = {
+ candidacy_id: number;
+ entries: Entry[];
+ next_url: string | null;
+ first_url: string;
+ older_page: boolean;
+ partnership_href: string | null;
+ dashboard_href: string;
+};
+const actions: Record = {
+ submit: 'Submissão',
+ assess: 'Avaliação',
+ clarify: 'Pedido de esclarecimento',
+ shortlist: 'Selecção para lista curta',
+ reject: 'Rejeição',
+ connect: 'Abertura de negociação',
+ withdraw: 'Retirada',
+};
+const fields: Record = {
+ proposal: 'Proposta curta',
+ capacity: 'Capacidade disponível',
+ availability: 'Disponibilidade',
+ contribution: 'Contribuição proposta',
+ conflicts: 'Conflitos de interesse declarados',
+ decision_reason: 'Motivo da decisão',
+};
+const display = (value: string | null | undefined) =>
+ value ? (labels[value] ?? value) : 'Não consta do registo';
+function Version({ value, title }: { value: Snapshot; title: string }) {
+ const unavailable = {
+ not_recorded: 'Esta versão não foi guardada no evento.',
+ scope_unknown:
+ 'O âmbito desta versão antiga não ficou identificado; o seu conteúdo não está disponível para esta conta.',
+ restricted:
+ 'Esta versão pertence a uma representação à qual esta conta não tem acesso actual.',
+ };
+ return (
+
+ {title}
+ {value.availability !== 'available' ? (
+ {unavailable[value.availability]}
+ ) : (
+ <>
+ {!value.complete && (
+
+ Registo parcial. Os campos em falta não foram
+ completados com dados actuais.
+
+ )}
+
+ Versão: {value.version ?? 'Não consta do registo'} ·
+ Estado: {display(value.status)}
+
+
+ Participação:{' '}
+ {!value.scope_known
+ ? 'Âmbito não registado'
+ : value.organization_id
+ ? (value.organization_name ??
+ `Organização ${value.organization_id}`)
+ : 'Em nome pessoal'}
+
+
+ {Object.entries(fields).map(([key, label]) => (
+
+
{label}
+
+ {Object.hasOwn(value.fields ?? {}, key)
+ ? value.fields?.[key] || 'Não indicado'
+ : 'Não consta do registo'}
+
+
+ ))}
+
+
+ Autorização de partilha
+
+
+ {value.consent_known
+ ? value.consent
+ ? 'Autorizada'
+ : 'Não autorizada'
+ : 'Não consta do registo'}
+
+
+
+ Avaliação guardada
+ {!value.assessment_recorded ? (
+ Não consta do registo.
+ ) : !value.assessment?.length ? (
+ Sem critérios avaliados nesta versão.
+ ) : (
+ <>
+
+ Os nomes dos critérios abaixo provêm do catálogo
+ actual; os estados e evidências são os que
+ ficaram guardados.
+
+
+ {value.assessment.map((item, index) => (
+
+
+ {item.label} · {display(item.state)}
+
+
+ Evidência:{' '}
+ {item.evidence ||
+ 'Não consta do registo'}
+
+
+ {item.actor_name ||
+ 'Autor não registado'}{' '}
+ ·{' '}
+ {item.assessed_at ||
+ 'Data não registada'}
+
+
+ ))}
+
+ >
+ )}
+ {Object.keys(value.references ?? {}).length > 0 && (
+
+ Referências guardadas
+
+ {Object.entries(value.references ?? {}).map(
+ ([key, id]) => (
+
+
+ {key === 'sector_id'
+ ? 'Sector'
+ : 'Localização'}{' '}
+ · referência
+
+ {id}
+
+ ),
+ )}
+
+
+ )}
+ >
+ )}
+
+ );
+}
+function FrozenMatching({ value }: { value: Matching | null }) {
+ if (!value)
+ return (
+
+ O contexto de correspondência não ficou guardado ou não está
+ disponível neste âmbito. Não foi recalculado.
+
+ );
+ return (
+
+ Correspondência guardada na decisão
+
+ Intervalo:{' '}
+ {value.score_min === null || value.score_max === null
+ ? 'Por determinar'
+ : `${value.score_min}–${value.score_max}%`}{' '}
+ · Elegibilidade: {display(value.eligibility)}. Este registo não
+ constitui aprovação.
+
+
+ São apresentados os parâmetros guardados, sem aplicar os
+ critérios actuais.
+
+
+ {value.criteria.map((item, index) => (
+
+
+ {item.label ?? item.code} · Peso:{' '}
+ {item.weight ?? 'Por determinar'} ·{' '}
+ {display(item.state)} ·{' '}
+ {item.mandatory === null
+ ? 'Obrigatoriedade não registada'
+ : item.mandatory
+ ? 'Obrigatório'
+ : 'Não obrigatório'}
+
+
+ Evidência:{' '}
+ {item.evidence || 'Não consta do registo'}
+
+ {item.explanation || 'Explicação não registada'}
+
+ ))}
+
+
+ Parâmetros do cálculo guardado
+
+ Algoritmo:{' '}
+ {value.algorithm_version ?? 'Não consta do registo'}
+
+
+ Referência dos pesos:{' '}
+ {value.weights_hash ?? 'Não consta do registo'}
+
+
+ Peso desconhecido:{' '}
+ {value.unknown_weight ?? 'Por determinar'}
+
+
+
+ );
+}
+export default function InterestHistory(p: Props) {
+ return (
+
+
+
+
+ Painel de parcerias
+
+ {p.partnership_href && (
+
+ Consultar parceria
+
+ )}
+ {p.older_page && (
+
+ Versões mais recentes
+
+ )}
+
+
+ Consulta dos valores guardados em cada alteração, do mais
+ recente para o mais antigo. Os nomes de pessoas e
+ organizações são os disponíveis no cadastro actual para as
+ referências guardadas.
+
+ {!p.entries.length && (
+
Ainda não existem versões guardadas para apresentar.
+ )}
+ {p.entries.map((entry, index) => (
+
+
+ Versão {entry.version ?? 'não registada'} ·{' '}
+ {entry.restricted
+ ? 'Conteúdo reservado'
+ : (actions[entry.action ?? ''] ??
+ 'Alteração registada')}
+
+ {!entry.restricted && (
+ <>
+
+ {entry.actor_name ?? 'Autor não registado'}{' '}
+ ·{' '}
+ {entry.occurred_at ?? 'Data não registada'}
+
+
+ Versão da parceria:{' '}
+ {entry.partnership_version ??
+ 'Não consta do registo'}
+
+ {entry.reason && (
+
+ Motivo: {entry.reason}
+
+ )}
+ >
+ )}
+
+
+
+
+ {!entry.restricted && (
+
+ )}
+
+ ))}
+ {p.next_url && (
+
+ Consultar versões anteriores
+
+ )}
+
+
+ );
+}
diff --git a/resources/js/pages/partnerships/publication-history.tsx b/resources/js/pages/partnerships/publication-history.tsx
new file mode 100644
index 00000000..cd4748d2
--- /dev/null
+++ b/resources/js/pages/partnerships/publication-history.tsx
@@ -0,0 +1,349 @@
+import { Link } from '@inertiajs/react';
+import { publicationHistoryActions as actions } from '@/lib/partnership-history';
+import { Frame, labels } from './shared';
+
+type Snapshot = {
+ availability: 'available' | 'not_recorded' | 'scope_unknown' | 'restricted';
+ version?: number | null;
+ status?: string | null;
+ scope_known?: boolean;
+ organization_id?: string | null;
+ organization_name?: string | null;
+ fields?: Record;
+ sector_recorded?: boolean;
+ sector_id?: string | null;
+ consent_known?: boolean;
+ consent?: boolean | null;
+ mandatory_known?: boolean;
+ mandatory?: string[];
+ origins_recorded?: boolean;
+ origins_incomplete?: boolean;
+ origins?: { type: string; target_id: string }[];
+ locations_recorded?: boolean;
+ locations_incomplete?: boolean;
+ locations?: {
+ geo_location_id: string;
+ role: string | null;
+ source_reference: string | null;
+ }[];
+ complete?: boolean;
+};
+type Entry = {
+ version: number | null;
+ restricted: boolean;
+ action: string | null;
+ actor_name: string | null;
+ occurred_at: string | null;
+ reason: string | null;
+ previous: Snapshot;
+ after: Snapshot;
+};
+type Props = {
+ partnership_id: number;
+ entries: Entry[];
+ first_url: string;
+ next_url: string | null;
+ older_page: boolean;
+ partnership_href: string;
+ dashboard_href: string;
+};
+const fields: Record = {
+ title: 'Título',
+ kind: 'Oferta ou procura',
+ partnership_type: 'Tipo de parceria',
+ summary: 'Resumo público',
+ offer: 'O que oferece',
+ seeking: 'O que procura',
+ requirements: 'Requisitos',
+ availability: 'Disponibilidade',
+ confidentiality: 'Partilha dos detalhes',
+ deadline: 'Prazo',
+ published_at: 'Data de publicação guardada',
+};
+function display(key: string, value: string | null | undefined) {
+ if (!value) return 'Não indicado';
+ if (key === 'kind')
+ return value === 'offering'
+ ? 'Oferta'
+ : value === 'seeking'
+ ? 'Procura'
+ : value;
+ if (key === 'confidentiality')
+ return value === 'private'
+ ? 'Detalhes reservados à conexão privada'
+ : value === 'public'
+ ? 'Pública'
+ : value;
+ return value;
+}
+function Version({ value, title }: { value: Snapshot; title: string }) {
+ const unavailable = {
+ not_recorded: 'Esta versão não foi guardada no evento.',
+ scope_unknown:
+ 'O âmbito ou a identidade desta versão antiga não está suficientemente identificado para a apresentar nesta consulta.',
+ restricted:
+ 'Esta versão pertence a uma representação à qual a conta não tem acesso actual.',
+ };
+ return (
+
+ {title}
+ {value.availability !== 'available' ? (
+ {unavailable[value.availability]}
+ ) : (
+ <>
+ {!value.complete && (
+
+ Registo parcial. Os campos em falta não foram
+ preenchidos com dados actuais.
+
+ )}
+
+ Versão: {value.version ?? 'Não consta do registo'} ·
+ Estado:{' '}
+ {value.status
+ ? (labels[value.status] ?? value.status)
+ : 'Não consta do registo'}
+
+
+ Participação:{' '}
+ {!value.scope_known
+ ? 'Âmbito não registado'
+ : value.organization_id
+ ? (value.organization_name ??
+ `Organização ${value.organization_id}`)
+ : 'Em nome pessoal'}
+
+
+ {Object.entries(fields).map(([key, label]) => (
+
+
{label}
+
+ {Object.hasOwn(value.fields ?? {}, key)
+ ? display(key, value.fields?.[key])
+ : 'Não consta do registo'}
+
+
+ ))}
+
+
+ Autorização de partilha
+
+
+ {value.consent_known
+ ? value.consent
+ ? 'Autorizada'
+ : 'Não autorizada'
+ : 'Não consta do registo'}
+
+
+
+
+ Critérios obrigatórios · códigos guardados
+
+
+ {!value.mandatory_known
+ ? 'Não consta do registo'
+ : value.mandatory?.length
+ ? value.mandatory.join(', ')
+ : 'Sem critérios obrigatórios nesta versão'}
+
+
+
+
+ Referência do sector
+
+
+ {value.sector_recorded
+ ? (value.sector_id ??
+ 'Sem classificação indicada')
+ : 'Não consta do registo'}
+
+
+
+
+
+ Referências da origem e localização guardadas
+
+
+
+ As referências identificam as ligações guardadas
+ nesta versão. Consultar os dados das fontes
+ continua sujeito às suas permissões actuais.
+
+
Origens
+ {!value.origins_recorded ? (
+
Não constam do registo.
+ ) : (
+ <>
+ {value.origins_incomplete && (
+
+ Há referências incompletas que não
+ podem ser apresentadas
+ integralmente.
+
+ )}
+ {!value.origins?.length &&
+ !value.origins_incomplete ? (
+
Sem origens ligadas nesta versão.
+ ) : (
+
+ {value.origins?.map(
+ (origin, index) => (
+
+ {origin.type} ·{' '}
+ {origin.target_id}
+
+ ),
+ )}
+
+ )}
+ >
+ )}
+
Localizações
+ {!value.locations_recorded ? (
+
Não constam do registo.
+ ) : (
+ <>
+ {value.locations_incomplete && (
+
+ Há localizações incompletas que não
+ podem ser apresentadas
+ integralmente.
+
+ )}
+ {!value.locations?.length &&
+ !value.locations_incomplete ? (
+
+ Sem localizações ligadas nesta
+ versão.
+
+ ) : (
+
+ {value.locations?.map(
+ (location, index) => (
+
+
+ Referência:{' '}
+ {
+ location.geo_location_id
+ }{' '}
+ ·{' '}
+ {location.role
+ ? ({
+ primary:
+ 'Principal',
+ operating:
+ 'Área de actuação',
+ coverage:
+ 'Abrangência',
+ }[
+ location
+ .role
+ ] ??
+ location.role)
+ : 'Papel não registado'}
+
+
+ Fonte declarada:{' '}
+ {location.source_reference ||
+ 'Não consta do registo'}
+
+
+ ),
+ )}
+
+ )}
+ >
+ )}
+
+
+ >
+ )}
+
+ );
+}
+export default function PublicationHistory(p: Props) {
+ return (
+
+
+
+
+ Painel de parcerias
+
+
+ Consultar parceria
+
+ {p.older_page && (
+
+ Versões mais recentes
+
+ )}
+
+
+ São apresentados os valores guardados, do mais recente para
+ o mais antigo. Os nomes de pessoas e organizações provêm do
+ cadastro actual das referências identificadas. Este
+ histórico não restaura nem volta a publicar versões.
+
+ {!p.entries.length && (
+
Não existem versões guardadas para apresentar.
+ )}
+ {p.entries.map((entry, index) => (
+
+
+ Versão {entry.version ?? 'não registada'} ·{' '}
+ {entry.restricted
+ ? 'Conteúdo reservado'
+ : (actions[entry.action ?? ''] ??
+ 'Alteração registada')}
+
+ {!entry.restricted && (
+ <>
+
+ {entry.actor_name ?? 'Autor não registado'}{' '}
+ ·{' '}
+ {entry.occurred_at ?? 'Data não registada'}
+
+ {entry.reason !== null && (
+
+ Motivo: {entry.reason}
+
+ )}
+ >
+ )}
+
+
+
+
+
+ ))}
+ {p.next_url && (
+
+ Consultar versões anteriores
+
+ )}
+
+
+ );
+}
diff --git a/resources/js/pages/partnerships/room.tsx b/resources/js/pages/partnerships/room.tsx
index ef47f6d2..e507a345 100644
--- a/resources/js/pages/partnerships/room.tsx
+++ b/resources/js/pages/partnerships/room.tsx
@@ -1,5 +1,10 @@
-import { createOperationKey } from '@/lib/operation-key';
-import { useForm, usePage, Link, router } from '@inertiajs/react';
+import { usePage, Link, router } from '@inertiajs/react';
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { useRoomEdit, useRoomLeaveGuard } from '@/lib/partnership-room-edit';
+import RoomComparison from '@/components/partnership-room-comparison';
+import { useRoomDelivery } from '@/lib/partnership-room-delivery';
+import { readAgreement } from '@/lib/partnership-agreement';
+import AgreementInstrument from '@/components/partnership-agreement-instrument';
import {
Frame,
Field,
@@ -13,31 +18,44 @@ type Room = {
id: number;
status: string;
version: number;
- agreement: {
- title: string;
- terms: string;
- confirmations: Record;
- legal_signature_status: string;
- } | null;
+ agreement: unknown;
};
type Milestone = {
id: number;
title: string;
responsible_id: number;
+ responsible_name: string | null;
+ responsible_is_participant: boolean;
due_date: string | null;
status: string;
evidence: string | null;
version: number;
+ client_key?: string | null;
};
type Props = {
+ agreementActorId: number;
+ agreementParty: 'proponent' | 'candidate' | null;
+ agreementCommands: {
+ key: string;
+ action: string;
+ version: number;
+ status: string;
+ party: string | null;
+ }[];
room: Room;
partnership: Partnership & { user_id: number };
- interest: { id: number; user_id: number };
+ interest: { id: number; user_id: number; version: number };
canWrite: boolean;
+ participants: {
+ id: number;
+ name: string;
+ parties: ('proponent' | 'candidate')[];
+ }[];
messages: {
id: number;
name: string;
author_id: number;
+ client_key?: string | null;
body: string;
created_at: string;
}[];
@@ -48,119 +66,267 @@ type Props = {
shared: boolean;
status: string;
malware_scan_status: string;
+ document_id: string;
}[];
milestones: Milestone[];
};
-function MilestoneForm({ p, item }: { p: Props; item?: Milestone }) {
- const form = useForm({
- title: item?.title ?? '',
- responsible_id: item?.responsible_id ?? p.partnership.user_id,
- due_date: item?.due_date ?? '',
- status: item?.status ?? 'pending',
- evidence: item?.evidence ?? '',
- version: item?.version ?? null,
+function MilestoneForm({
+ p,
+ item,
+ onDirty,
+}: {
+ p: Props;
+ item?: Milestone;
+ onDirty?: (id: string, dirty: boolean) => void;
+}) {
+ const editor = useRoomEdit({
+ props: p,
+ roomId: p.room.id,
+ kind: 'milestone',
+ itemId: item?.id ?? null,
});
+ const form = editor.form;
+ const draftId = 'milestone:' + (item?.id ?? 'new');
+ useEffect(() => {
+ onDirty?.(draftId, editor.dirty);
+ }, [onDirty, draftId, editor.dirty]);
+ useEffect(() => () => onDirty?.(draftId, false), [onDirty, draftId]);
+ if (!editor.editable && !editor.dirty && !editor.problem) return null;
+ const currentResponsible = p.participants.some(
+ (participant) =>
+ String(participant.id) === editor.values.responsible_id,
+ );
return (
{
e.preventDefault();
- if (item)
- form.put(
- `/parcerias/salas/${p.room.id}/marcos/${item.id}`,
- { preserveScroll: true },
- );
- else
- form.post(`/parcerias/salas/${p.room.id}/marcos`, {
- preserveScroll: true,
- });
+ if (
+ form.processing ||
+ (!currentResponsible && !editor.recovering)
+ )
+ return;
+ editor.submit();
}}
>
{item ? 'Atualizar marco' : 'Acrescentar marco'}
-
- form.setData('title', e.target.value)}
- />
-
-
-
- form.setData('responsible_id', Number(e.target.value))
- }
- >
- Proponente
- Candidato
-
-
-
- form.setData('due_date', e.target.value)}
- />
-
-
- form.setData('status', e.target.value)}
- >
- {['pending', 'progress', 'completed'].map((x) => (
-
- {x === 'pending' ? 'Pendente' : labels[x]}
+
+ key === 'responsible_id'
+ ? (p.participants.find(
+ (person) => String(person.id) === value,
+ )?.name ??
+ (String(item?.responsible_id) === value
+ ? item?.responsible_name
+ : null) ??
+ 'Participante já indisponível')
+ : key === 'status'
+ ? value === 'pending'
+ ? 'Pendente'
+ : (labels[value] ?? value)
+ : value || 'Não indicado'
+ }
+ />
+
+
+ editor.change('title', e.target.value)}
+ />
+
+
+
+ editor.change('responsible_id', e.target.value)
+ }
+ >
+
+ Seleccione um participante autorizado
- ))}
-
-
-
- form.setData('evidence', e.target.value)}
- />
-
+ {item &&
+ !p.participants.some(
+ (participant) =>
+ participant.id === item.responsible_id,
+ ) && (
+
+ {item.responsible_name ??
+ 'Responsável registado indisponível'}{' '}
+ {item.responsible_is_participant
+ ? '— atribuição registada; selecção indisponível neste estado'
+ : '— sem representação actual'}
+
+ )}
+ {p.participants.map((participant) => (
+
+ {participant.name} —{' '}
+ {participant.parties
+ .map((party) =>
+ party === 'proponent'
+ ? 'Proponente'
+ : 'Candidato',
+ )
+ .join(' / ')}
+
+ ))}
+
+
+ {editor.editable &&
+ editor.values.responsible_id &&
+ !currentResponsible && (
+
+ {item &&
+ editor.values.responsible_id ===
+ String(item.responsible_id)
+ ? 'A atribuição anterior foi conservada. Para guardar uma alteração, seleccione um participante actualmente autorizado; consultar não altera o responsável.'
+ : 'O participante seleccionado deixou de estar disponível para esta atribuição. Escolha outro participante autorizado antes de guardar.'}
+
+ )}
+
+
+ editor.change('due_date', e.target.value)
+ }
+ />
+
+
+
+ editor.change('status', e.target.value)
+ }
+ >
+ {['pending', 'progress', 'completed'].map((x) => (
+
+ {x === 'pending' ? 'Pendente' : labels[x]}
+
+ ))}
+
+
+
+
+ editor.change('evidence', e.target.value)
+ }
+ />
+
+
-
- Guardar marco
+
+ {editor.recovering
+ ? 'Recuperar criação do marco'
+ : 'Guardar marco'}
);
}
export default function Page(p: Props) {
- return ;
-}
-function RoomPage(p: Props) {
const { auth } = usePage<{ auth: { user: { id: number } } }>().props;
- const message = useForm({ body: '', client_key: createOperationKey() });
- const agreement = useForm({
- version: p.room.version,
- action: 'record',
- title: p.room.agreement?.title ?? '',
- terms: p.room.agreement?.terms ?? '',
- reason: '',
- });
- const upload = useForm<{ file: File | null; shared: boolean }>({
- file: null,
- shared: false,
- });
- const act = (action: string) => {
- agreement.transform((data) => ({ ...data, action }));
- agreement.post(`/parcerias/salas/${p.room.id}/acordo`, {
- preserveScroll: true,
- });
- };
+ const openedRoom = useRef(p.room.id);
+ return (
+
+ );
+}
+function RoomPage(p: Props & { expectedRoomId: number }) {
+ const instrument = readAgreement(p.room.agreement);
+ const { auth } = usePage<{ auth: { user: { id: number } } }>().props;
const mutable =
- p.canWrite && !['closed', 'cancelled'].includes(p.room.status);
+ p.canWrite &&
+ p.room.id === p.expectedRoomId &&
+ !['closed', 'cancelled'].includes(p.room.status);
+ const messageEdit = useRoomDelivery({
+ roomId: p.expectedRoomId,
+ actorId: auth.user.id,
+ kind: 'message',
+ mutable,
+ canWrite: p.canWrite && p.room.id === p.expectedRoomId,
+ });
+ const message = messageEdit.form;
+ const agreementEdit = useRoomEdit({
+ props: p,
+ roomId: p.expectedRoomId,
+ kind: 'agreement',
+ });
+ const agreement = agreementEdit.form;
+ const uploadEdit = useRoomDelivery({
+ roomId: p.expectedRoomId,
+ actorId: auth.user.id,
+ kind: 'upload',
+ mutable,
+ canWrite: p.canWrite && p.room.id === p.expectedRoomId,
+ });
+ const upload = uploadEdit.form;
+ const uploadInput = useRef(null);
+ useEffect(() => {
+ if (!upload.data.file && uploadInput.current)
+ uploadInput.current.value = '';
+ }, [upload.data.file]);
+ const act = (action: string) => agreementEdit.submit(action);
+ const childDrafts = useRef(new Map());
+ const [childDraftCount, setChildDraftCount] = useState(0);
+ const onDirty = useCallback((id: string, dirty: boolean) => {
+ if ((childDrafts.current.get(id) ?? false) === dirty) return;
+ childDrafts.current.set(id, dirty);
+ setChildDraftCount(
+ [...childDrafts.current.values()].filter(Boolean).length,
+ );
+ }, []);
+ useRoomLeaveGuard(
+ agreementEdit.dirty ||
+ messageEdit.dirty ||
+ uploadEdit.dirty ||
+ childDraftCount > 0,
+ );
return (
+ {p.room.id !== p.expectedRoomId && (
+
+ A resposta não corresponde à sala aberta. Recupere os
+ dados antes de continuar; a sua preparação foi
+ conservada.
+
+ )}
{m.body}
))}
- {mutable && (
+ {(mutable || messageEdit.dirty) && (
{
e.preventDefault();
- message.post(
- `/parcerias/salas/${p.room.id}/mensagens`,
- {
- preserveScroll: true,
- onSuccess: () => {
- message.setData({
- body: '',
- client_key:
- createOperationKey(),
- });
- },
- },
- );
+ messageEdit.submit();
}}
>
- message.setData('body', e.target.value)
+ messageEdit.change(
+ 'body',
+ e.target.value,
+ )
}
/>
+ {messageEdit.problem && (
+ {messageEdit.problem}
+ )}
+ {!mutable && messageEdit.dirty && (
+
+ A mensagem em preparação foi conservada. O
+ estado ou acesso actual não permite novas
+ mensagens.
+
+ )}
+ {messageEdit.recovering && (
+
+ Recuperar repete a mensagem original com a
+ mesma chave; o texto escrito depois fica
+ para outra mensagem.
+
+ )}
- Enviar mensagem
+ {messageEdit.recovering
+ ? 'Recuperar mensagem enviada'
+ : 'Enviar mensagem'}
)}
@@ -290,39 +467,42 @@ function RoomPage(p: Props) {
)}
))}
- {mutable && (
+ {(mutable || uploadEdit.dirty) && (
{
e.preventDefault();
- upload.post(
- `/parcerias/salas/${p.room.id}/documentos`,
- {
- forceFormData: true,
- preserveScroll: true,
- },
- );
+ uploadEdit.submit();
}}
>
- upload.setData(
+ uploadEdit.change(
'file',
e.target.files?.[0] ?? null,
)
}
/>
+ {upload.data.file && (
+
+ Ficheiro preparado: {upload.data.file.name}
+
+ )}
- upload.setData(
+ uploadEdit.change(
'shared',
e.target.checked,
)
@@ -331,13 +511,35 @@ function RoomPage(p: Props) {
Autorizo a consulta pela contraparte desta sala.
+ {uploadEdit.problem && (
+ {uploadEdit.problem}
+ )}
+ {!mutable && uploadEdit.dirty && (
+
+ O ficheiro em preparação foi conservado em
+ memória. O estado ou acesso actual não
+ permite novos documentos.
+
+ )}
+ {uploadEdit.recovering && (
+
+ Recuperar repete o ficheiro e a autorização
+ originais, sem criar outro documento. Uma
+ selecção posterior fica preparada para outro
+ envio.
+
+ )}
- Guardar documento privado
+ {uploadEdit.recovering
+ ? 'Recuperar envio do documento'
+ : 'Guardar documento privado'}
)}
@@ -353,143 +555,200 @@ function RoomPage(p: Props) {
concordância comunicada pelas partes; não certifica
assinatura jurídica ou due diligence.
- {p.room.agreement && (
- <>
-
- {p.room.agreement.title}
-
-
- {p.room.agreement.terms}
-
-
- Confirmações:{' '}
- {Object.entries(p.room.agreement.confirmations)
- .map(
- ([party, c]) =>
- `${party}: autor ${c.actor_id}, ${c.date}`,
- )
- .join('; ') || 'Pendentes'}
-
- >
+
+ Consultar histórico do acordo
+
+
+ {p.agreementParty && (
+
+ A sua acção é registada pela parte{' '}
+ {p.agreementParty === 'proponent'
+ ? 'proponente'
+ : 'candidata'}
+ , segundo a representação actual. Registar outra
+ versão retira as confirmações dessa versão e
+ conserva o histórico.
+
)}
- {mutable && (
+
+ {(mutable || agreementEdit.dirty) && (
<>
-
-
- agreement.setData(
- 'reason',
- e.target.value,
- )
- }
- />
-
- {['negotiation', 'agreement_recorded'].includes(
- p.room.status,
- ) && (
- <>
-
-
- agreement.setData(
- 'title',
- e.target.value,
- )
+
+
+
+ agreementEdit.change(
+ 'reason',
+ e.target.value,
+ )
+ }
+ />
+
+ {([
+ 'negotiation',
+ 'agreement_recorded',
+ ].includes(p.room.status) ||
+ agreementEdit.dirty) && (
+ <>
+
+
+ agreementEdit.change(
+ 'title',
+ e.target.value,
+ )
+ }
+ />
+
+
+
+ agreementEdit.change(
+ 'terms',
+ e.target.value,
+ )
+ }
+ />
+
+
-
-
-
- agreement.setData(
- 'terms',
- e.target.value,
- )
+ onClick={() => act('record')}
+ >
+ Registar versão do acordo
+
+ >
+ )}
+
+ {(agreementEdit.values.title !==
+ agreementEdit.current.title ||
+ agreementEdit.values.terms !==
+ agreementEdit.current.terms) && (
+
+ Há alterações locais no instrumento
+ ainda por registar. As outras acções
+ referem-se à versão actualmente
+ guardada, apresentada acima.
+
+ )}
+ {p.room.status === 'agreement_recorded' && (
+
-
+ onClick={() => act('confirm')}
+ >
+ {p.agreementParty &&
+ instrument.confirmations[
+ p.agreementParty
+ ]?.actorId
+ ? 'Actualizar confirmação da minha parte'
+ : 'Confirmar pela minha parte'}
+
+ )}
+ {p.room.status === 'agreed' && (
+
act('start')}
+ >
+ Iniciar acompanhamento
+
+ )}
+ {p.room.status === 'execution' && (
+
act('complete')}
+ >
+ Concluir após os marcos
+
+ )}
+ {['agreed', 'execution'].includes(
+ p.room.status,
+ ) && (
+
act('renew')}
+ >
+ Registar renovação
+
+ )}
act('record')}
+ onClick={() => act('cancel')}
>
- Registar versão do acordo
+ Cancelar conexão com motivo
- >
- )}
-
- {p.room.status === 'agreement_recorded' && (
- act('confirm')}
- >
- Confirmar pela minha parte
-
- )}
- {p.room.status === 'agreed' && (
- act('start')}
- >
- Iniciar acompanhamento
-
- )}
- {p.room.status === 'execution' && (
- act('complete')}
- >
- Concluir após os marcos
-
- )}
- {['agreed', 'execution'].includes(
- p.room.status,
- ) && (
- act('renew')}
- >
- Registar renovação
-
- )}
- act('cancel')}
- >
- Cancelar conexão com motivo
-
-
-
+
+
+
>
)}
@@ -505,25 +764,23 @@ function RoomPage(p: Props) {
.
{p.milestones.map((m) => (
-
+
{m.title} ·{' '}
{m.status === 'pending'
? 'Pendente'
: labels[m.status]}{' '}
· Prazo: {m.due_date ?? 'Pendente'} ·
- Responsável ID {m.responsible_id}
+ Responsável:{' '}
+ {m.responsible_name ??
+ 'Responsável registado indisponível'}
+ {!m.responsible_is_participant &&
+ ' · Sem representação actual; atribuição anterior conservada'}
- {mutable && }
+
))}
- {mutable &&
- ['agreement_recorded', 'agreed', 'execution'].includes(
- p.room.status,
- ) && }
+
diff --git a/resources/js/pages/partnerships/shared.tsx b/resources/js/pages/partnerships/shared.tsx
index 85d8c3db..c9044638 100644
--- a/resources/js/pages/partnerships/shared.tsx
+++ b/resources/js/pages/partnerships/shared.tsx
@@ -28,6 +28,7 @@ export type Partnership = {
title: string;
status: string;
version: number;
+ client_key?: string | null;
kind: string;
partnership_type: string | null;
sector_id: number | null;
@@ -45,6 +46,7 @@ export type Partnership = {
};
};
export type Match = {
+ weights_hash?: string;
score_min: number | null;
score_max: number | null;
eligibility: string;
@@ -67,12 +69,16 @@ export type Interest = {
status: string;
decision_reason: string | null;
organization_id: string | null;
+ can_edit?: boolean;
+ commands?: { key: string; version: number; action: string }[];
payload: {
capacity?: string;
availability?: string;
contribution?: string;
conflicts?: string;
consent?: boolean;
+ sector_id?: number | null;
+ territory_id?: string | null;
};
assessment: Record;
match: Match;
diff --git a/resources/js/pages/portal/privacy-policy.tsx b/resources/js/pages/portal/privacy-policy.tsx
index dedb3fb8..e162e947 100644
--- a/resources/js/pages/portal/privacy-policy.tsx
+++ b/resources/js/pages/portal/privacy-policy.tsx
@@ -58,6 +58,17 @@ const PrivacyPolicy = () => {
dispositivo, navegador utilizado e informações
relacionadas com cookies ou tecnologias semelhantes.
+
+ Nos pedidos do Balcão com gravação automática
+ disponível, as respostas ainda incompletas e a
+ justificação do rascunho são conservadas cifradas no
+ servidor para recuperação pela própria conta,
+ sujeita ao acesso actual ao pedido. Esta recuperação
+ não submete o pedido nem confirma a revisão do
+ contexto ou a autorização de submissão. O estado e
+ as falhas da gravação são apresentados no
+ formulário.
+
@@ -75,6 +86,17 @@ const PrivacyPolicy = () => {
legais e produzir estatísticas agregadas sobre a
utilização do portal.
+
+ Os contadores de pesquisa dos catálogos
+ instrumentados conservam apenas totais por dia UTC,
+ canal e edição da medição, incluindo respostas sem
+ resultados e os instantes da primeira e última
+ observação agregada. Estes contadores não guardam os
+ termos pesquisados, valores de filtros, endereço IP,
+ cookies ou identificadores de utilizadores ou
+ visitantes. A recolha é omitida nos pedidos que
+ enviem DNT: 1 ou Sec-GPC: 1.
+
diff --git a/resources/js/pages/portal/services.tsx b/resources/js/pages/portal/services.tsx
index 1614c83e..a3ab064e 100644
--- a/resources/js/pages/portal/services.tsx
+++ b/resources/js/pages/portal/services.tsx
@@ -573,7 +573,29 @@ export default function Services(p: Props) {
{['procedures', 'documents', 'legislation'].includes(
p.section,
) && }
- {p.section === 'procedures' && }
+ {p.section === 'procedures' && (
+ <>
+
+ Comparar formas jurídicas antes de preparar a
+ constituição
+
+
+
+ Conhecer formas de capitalização e preparar o
+ financiamento
+
+
+ Consultar o guião de admissão à Bolsa de Valores de
+ Moçambique
+
+ >
+ )}
{(p.section === 'documents' || p.section === 'legislation') && (
<>
- {['validator', 'publisher', 'auditor'].map((v) => (
- {v}
+ {[
+ 'validator',
+ 'publisher',
+ 'auditor',
+ ...(technicalSupportAvailable
+ ? ['technical_support']
+ : []),
+ ].map((v) => (
+
+ {
+ (
+ {
+ validator: 'Validador',
+ publisher: 'Publicador',
+ auditor: 'Auditor',
+ technical_support:
+ 'Suporte técnico',
+ } as Record
+ )[v]
+ }
+
))}
@@ -839,7 +860,9 @@ export default function Administration({
operatorOrganizations,
internalTypes,
staffAccounts,
+ technicalSupportAvailable = false,
}: {
+ technicalSupportAvailable?: boolean;
operatorOrganizations: OperatorOrganization[];
internalTypes: string[];
staffAccounts: {
@@ -920,7 +943,11 @@ export default function Administration({
organizations={organizations}
operators={operatorOrganizations}
/>
-
+
(null);
const [installationKey] = useState(createOperationKey);
const [bootstrapKey] = useState(createOperationKey);
+ const [confirmedPreparation, setConfirmedPreparation] = useState({
+ reason: '',
+ first: '',
+ second: '',
+ });
+ usePagePreparationGuard(
+ busy ||
+ reason !== confirmedPreparation.reason ||
+ first !== confirmedPreparation.first ||
+ second !== confirmedPreparation.second,
+ 'Existe uma preparação ou uma operação de perfis em curso. Sair desta página?',
+ );
async function run(bootstrap = false) {
setBusy(true);
setMessage('');
@@ -55,6 +70,11 @@ export default function Installation(initial: Plan) {
: {}),
},
);
+ setConfirmedPreparation((previous) => ({
+ ...previous,
+ reason,
+ ...(bootstrap ? { first, second } : {}),
+ }));
setMessage(
bootstrap
? 'Pedido registado, sem atribuir privilégios. O segundo titular deve autenticar-se com MFA e confirmar pelo endereço abaixo.'
@@ -85,6 +105,14 @@ export default function Installation(initial: Plan) {
}
return (
+ {plan.technicalSupportUpdateUrl && (
+
+ Actualização do Suporte técnico
+
+ )}
Base {plan.target.database}:{plan.target.port} ·{' '}
{plan.installed ? 'Schema instalado' : 'Schema por instalar'}
diff --git a/resources/js/pages/profiles/support-installation.tsx b/resources/js/pages/profiles/support-installation.tsx
new file mode 100644
index 00000000..d6c9b5b5
--- /dev/null
+++ b/resources/js/pages/profiles/support-installation.tsx
@@ -0,0 +1,170 @@
+import { Link } from '@inertiajs/react';
+import { Management, button, control } from '../management/shared';
+import {
+ useProfileSupportInstallation,
+ type SupportPlan,
+} from '@/lib/profile-support-installation';
+function SupportInstallationForm({ initial }: { initial: SupportPlan }) {
+ const edit = useProfileSupportInstallation(initial),
+ plan = edit.plan;
+ return (
+
+
+ Destino: {plan.target.database}:{plan.target.port}
+
+
+ {plan.installed
+ ? 'Suporte técnico actualizado'
+ : plan.repairable
+ ? 'Migração registada com a restrição anterior; reposição delimitada disponível.'
+ : 'Actualização do Suporte técnico por aplicar'}
+
+
+ {plan.ready
+ ? 'Provas actuais verificadas.'
+ : 'Dependências ou provas por completar.'}{' '}
+ Backup/restauro: {plan.backupDate ?? 'Prova actual pendente'}
+
+ {!plan.mfa_confirmed && (
+
+ Renove a autenticação MFA nesta conta antes de aplicar a
+ actualização.
+
+ )}
+ {!plan.consistent && !plan.repairable && (
+
+ A estrutura não corresponde à versão reconhecida. Preserve
+ os dados e reconcilie a divergência antes de instalar.
+
+ )}
+
+ {Object.entries(plan.dependencies).map(([name, ok]) => (
+
+ {(
+ {
+ profiles_installed: 'Base dos perfis instalada',
+ profiles_consistent:
+ 'Base dos perfis consistente',
+ management_020000: 'Gestão de oportunidades',
+ resources_030000: 'Recursos das oportunidades',
+ existing_identity_organization_audit:
+ 'Identidades, organizações e auditoria',
+ } as Record
+ )[name] ?? 'Dependência da instalação'}
+ : {ok ? 'presente' : 'pendente'}
+
+ ))}
+
+
+ {plan.changes.map((change) => (
+ {change}
+ ))}
+
+ {plan.rollback}
+ {edit.stale && (
+
+ A prévia mudou
+
+ Anterior:{' '}
+ {edit.base.installed ? 'Actualizado' : 'Por actualizar'}{' '}
+ ·{' '}
+ {edit.base.ready
+ ? 'Provas verificadas'
+ : 'Provas pendentes'}{' '}
+ · {edit.base.backupDate ?? 'Sem prova actual'}
+
+
+ Actual:{' '}
+ {plan.installed ? 'Actualizado' : 'Por actualizar'} ·{' '}
+ {plan.ready ? 'Provas verificadas' : 'Provas pendentes'}{' '}
+ · {plan.backupDate ?? 'Sem prova actual'}
+
+
+ Confira novamente o destino, a estrutura e as alterações
+ indicadas antes de confirmar.
+
+
+ Confirmar leitura da prévia actual
+
+
+ )}
+
+ Fundamento da actualização
+ edit.change(event.target.value)}
+ />
+
+
+
+ edit.setConfirmed(event.target.checked)
+ }
+ />{' '}
+ Confirmo esta actualização no destino indicado
+
+ {edit.uncertain && (
+
+ O envio original aguarda confirmação. A repetição conserva o
+ plano, o fundamento e a confirmação originais.
+
+ )}
+
+ void edit.send()}
+ >
+ Aplicar actualização do Suporte técnico
+
+ {edit.canRetry && (
+ void edit.send(true)}
+ >
+ Repetir envio original
+
+ )}
+ void edit.refresh()}
+ >
+ Actualizar prévia
+
+
+ {edit.message && {edit.message}
}
+ {edit.error && {edit.error}
}
+
+ );
+}
+export default function SupportInstallation(plan: SupportPlan) {
+ return (
+
+
+ Voltar à instalação dos perfis
+
+
+
+ );
+}
diff --git a/resources/js/pages/profiles/technical-incident.tsx b/resources/js/pages/profiles/technical-incident.tsx
new file mode 100644
index 00000000..7dc8e8cf
--- /dev/null
+++ b/resources/js/pages/profiles/technical-incident.tsx
@@ -0,0 +1,98 @@
+import { Link } from '@inertiajs/react';
+import TechnicalIncidentHandling from '@/components/technical-incident-handling';
+import TechnicalIncidentNotice from '@/components/technical-incident-notice';
+import {
+ handlingLabels,
+ commandLabels,
+ incidentOperationLabel,
+ incidentErrorLabel,
+} from '@/lib/technical-incident-labels';
+import type { HandlingProps, Command } from '@/lib/technical-incident-handling';
+import { Management, Pagination, type Paginated } from '../management/shared';
+export default function TechnicalIncident(
+ props: HandlingProps & {
+ backUrl: string;
+ notice?: { unread: boolean };
+ history: Paginated<{
+ id: string;
+ version: number | null;
+ action: Command | null;
+ status: string | null;
+ actor: string | null;
+ occurred_at: string;
+ note: string | null;
+ note_available: boolean;
+ }>;
+ },
+) {
+ const row = props.incident;
+ return (
+
+
+ Voltar à fila de suporte
+
+
+
+ {incidentOperationLabel(row.operation)} · versão observada{' '}
+ {row.observed_version}
+
+ Referência: {row.reference}
+ {row.occurred_at}
+ {incidentErrorLabel(row.error_code)}
+ Estado técnico: {handlingLabels[row.handling.status]}
+
+ Responsável actual:{' '}
+ {row.handling.assignee_name || 'Por assumir'}
+
+
+ {props.notice && (
+
+ )}
+
+
+
+ Histórico do tratamento
+
+ {!props.history.data.length && Sem tratamento registado.
}
+ {props.history.data.map((entry) => (
+
+
+ Versão {entry.version ?? 'não identificada'} ·{' '}
+ {entry.action
+ ? commandLabels[entry.action]
+ : 'Registo anterior'}
+
+
+ {entry.actor || 'Autor não identificado'} ·{' '}
+ {entry.occurred_at}
+
+
+ Estado:{' '}
+ {entry.status
+ ? handlingLabels[entry.status] ||
+ 'Não identificado'
+ : 'Não identificado'}
+
+
+ {entry.note_available
+ ? entry.note
+ : 'Nota indisponível para leitura; original preservado.'}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/resources/js/pages/profiles/technical-support.tsx b/resources/js/pages/profiles/technical-support.tsx
new file mode 100644
index 00000000..b7cbb1af
--- /dev/null
+++ b/resources/js/pages/profiles/technical-support.tsx
@@ -0,0 +1,150 @@
+import { Management, Pagination, type Paginated } from '../management/shared';
+import type { OpportunityTechnicalIncident } from '@/components/opportunity-technical-incidents';
+import { Link } from '@inertiajs/react';
+import {
+ handlingLabels,
+ incidentOperationLabel,
+ incidentErrorLabel,
+} from '@/lib/technical-incident-labels';
+import type { HandlingState } from '@/lib/technical-incident-handling';
+import TechnicalIncidentNotice from '@/components/technical-incident-notice';
+export default function TechnicalSupport({
+ incidents,
+ actorId,
+ filters = { status: 'all' },
+}: {
+ actorId?: number;
+ incidents: Paginated<
+ OpportunityTechnicalIncident & {
+ handling?: HandlingState | null;
+ details_url?: string;
+ unread?: boolean;
+ }
+ >;
+ filters?: { status: string; unread?: boolean };
+}) {
+ function href(status: string, unread = !!filters.unread) {
+ const query = new URLSearchParams({
+ ...(status !== 'all' ? { status } : {}),
+ ...(unread ? { unread: '1' } : {}),
+ }).toString();
+ return '/suporte-tecnico/incidentes' + (query ? '?' + query : '');
+ }
+ return (
+
+
+ Incidentes de submissão, publicação, uploads e preparação de
+ imagens nas organizações e tipos abrangidos pela sua atribuição
+ actual. A fila apresenta metadados técnicos; o perfil de suporte
+ não concede acesso aos processos ou documentos.
+
+
+ {Object.entries({ all: 'Todos', ...handlingLabels }).map(
+ ([value, label]) => (
+
+ {label}
+
+ ),
+ )}
+
+
+
+ Todos os avisos
+
+
+ Por consultar
+
+
+ {!incidents.data.length && (
+ Não existem incidentes disponíveis neste âmbito.
+ )}
+ {incidents.data.map((incident) => (
+
+
+ {incidentOperationLabel(incident.operation)} · versão
+ observada {incident.version}
+
+ {incident.occurred_at}
+ {incidentErrorLabel(incident.error_code)}
+
+ Referência: {incident.reference}
+
+ {actorId && typeof incident.unread === 'boolean' && (
+
+ )}
+ {incident.handling ? (
+
+ Estado técnico:{' '}
+ {handlingLabels[incident.handling.status]} ·{' '}
+ {incident.handling.assignee_name || 'Por assumir'}
+
+ ) : (
+
+ Estado técnico indisponível; registos preservados.
+
+ )}
+ {incident.details_url && (
+ 1 ||
+ filters.status !== 'all' ||
+ filters.unread
+ ? '?' +
+ new URLSearchParams({
+ ...(incidents.current_page > 1
+ ? {
+ page: String(
+ incidents.current_page,
+ ),
+ }
+ : {}),
+ ...(filters.status !== 'all'
+ ? { status: filters.status }
+ : {}),
+ ...(filters.unread
+ ? { unread: '1' }
+ : {}),
+ }).toString()
+ : '')
+ }
+ >
+ Consultar e tratar incidente
+
+ )}
+
+ ))}
+
+
+ );
+}
diff --git a/resources/js/types/profile-access.ts b/resources/js/types/profile-access.ts
index 7bc68dcb..d5247ea4 100644
--- a/resources/js/types/profile-access.ts
+++ b/resources/js/types/profile-access.ts
@@ -10,5 +10,7 @@ export type ProfileAccess = {
request: string;
review: string | null;
audit?: string | null;
+ technicalSupport?: string | null;
+ technicalSupportUnread?: number | null;
administration: string | null;
};
diff --git a/resources/views/desk/receipt-answers.blade.php b/resources/views/desk/receipt-answers.blade.php
index 73b3877a..9cc6ee21 100644
--- a/resources/views/desk/receipt-answers.blade.php
+++ b/resources/views/desk/receipt-answers.blade.php
@@ -3,6 +3,15 @@
$field = $definition['fields'][$key] ?? [];
$empty = $value === null || $value === '' || $value === [];
$display = $empty ? 'Não informado' : (is_bool($value) ? ($value ? 'Sim' : 'Não') : (is_scalar($value) ? ($field['options'][(string) $value] ?? (string) $value) : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)));
+ if (!$empty && ($field['type'] ?? null) === 'multiselect' && is_array($value)) {
+ $display = implode(' · ', array_map(fn ($code) => $field['options'][$code] ?? $code, $value));
+ }
+ if (!$empty && ($field['type'] ?? null) === 'consent') {
+ $display = ['accepted' => 'Aceite', 'declined' => 'Recusado'][$value] ?? 'Resposta conservada sem classificação';
+ }
+ if (!$empty && ($field['type'] ?? null) === 'attachment' && is_array($value)) {
+ $display = implode(' · ', array_column($snapshot['field_attachments'][$key]['files'] ?? [], 'file_name')) ?: 'Selecção documental conservada; consulte o original técnico.';
+ }
if (!$empty && in_array($key, ['investment_amount', 'own_finance', 'other_finance'], true) && is_numeric($value)) {
$display = number_format((float)$value, 2, ',', ' ').' '.(($snapshot['payload']['currency'] ?? '') ?: '(moeda não informada)');
}
diff --git a/resources/views/desk/receipt.blade.php b/resources/views/desk/receipt.blade.php
index c9c083e2..fb9fd5a1 100644
--- a/resources/views/desk/receipt.blade.php
+++ b/resources/views/desk/receipt.blade.php
@@ -43,7 +43,23 @@ footer { margin-top:28px; border-top:1px solid #cbd8d3; padding-top:12px; }
@include('desk.receipt-answers', ['answers' => $inactiveAnswers])
@endif
+@if(!empty($snapshot['field_declarations']))
+
Declarações registadas nesta submissão
+Estas escolhas correspondem ao texto da versão do formulário utilizada. Não substituem os controlos de acesso, outras autorizações ou decisões oficiais.
+Texto e escolha efectivamente submetidos
+@foreach($snapshot['field_declarations'] as $declaration)
+{{ $declaration['label'] }} {{ $declaration['statement'] }}{{ $declaration['answer'] === 'accepted' ? 'Aceite' : 'Recusado' }} Registado em {{ $declaration['declared_at'] }} · SHA-256 {{ $declaration['statement_sha256'] }}
+@endforeach
+
+@endif
Suportes documentais
+@foreach(($snapshot['field_attachments'] ?? []) as $attachment)
+{{ $attachment['label'] }}
+{{ $attachment['applicable'] ? 'Pergunta aplicável à submissão.' : 'Resposta conservada de pergunta não aplicável; não é evidência aplicável.' }} Limites desta versão: {{ $attachment['limits']['max_size_kb'] }} KB por ficheiro · {{ $attachment['limits']['max_files'] }} ficheiro(s).
+@foreach($attachment['files'] as $file)
+{{ $file['file_name'] }} · Versão {{ $file['version_no'] ?? 'não informada' }} · {{ $file['size_bytes'] }} bytes · {{ $file['source_reference'] }} SHA-256 {{ $file['sha256'] }} · {{ $file['usable_at_submission'] ? 'Disponibilidade, integridade e segurança verificadas para esta submissão interna.' : 'Disponibilidade não validada como evidência aplicável nesta submissão.' }}
+@endforeach
+@endforeach
@forelse(($snapshot['documents'] ?? []) as $document)
{{ data_get($document, 'source_reference') ?: 'Referência não informada' }} · Versão {{ data_get($document, 'version_no') ?? 'Não informada' }}
@empty
diff --git a/routes/investor-path.php b/routes/investor-path.php
index cba9000c..02c07b39 100644
--- a/routes/investor-path.php
+++ b/routes/investor-path.php
@@ -1,6 +1,9 @@
middleware('throttle:60,1');
+Route::get('/formas-juridicas', [CompanyComparisonController::class, 'index'])->middleware([PrivateInvestmentResponse::class, 'throttle:60,1']);
+Route::get('/guias-investimento/{slug}', [InvestmentGuideController::class, 'index'])->where('slug', '[a-z0-9-]+')->middleware([PrivateInvestmentResponse::class, 'throttle:60,1']);
Route::middleware(['auth', 'verified', PrivateInvestmentResponse::class, VirtualDeskInstalled::class, 'throttle:60,1'])->prefix('investimentos')->group(function () {
Route::get('/', [Path::class, 'index']);
@@ -17,6 +22,12 @@ Route::middleware(['auth', 'verified', PrivateInvestmentResponse::class, Virtual
Route::put('/contexto-atual', [InvestorContextController::class, 'focus']);
Route::get('/fontes-contexto', [InvestorContextController::class, 'options']);
Route::get('/opcoes-corredor', [InvestorContextController::class, 'corridorOptions']);
+ Route::get('/{id}/forma-juridica', [CompanyComparisonController::class, 'show'])->whereUuid('id');
+ Route::post('/{id}/forma-juridica', [CompanyComparisonController::class, 'save'])->whereUuid('id');
+ Route::get('/{id}/preparar-empresa', [CompanyPreparationController::class, 'show'])->whereUuid('id');
+ Route::post('/{id}/preparar-empresa', [CompanyPreparationController::class, 'save'])->whereUuid('id');
+ Route::get('/{id}/guias/{slug}', [InvestmentGuideController::class, 'show'])->whereUuid('id')->where('slug', '[a-z0-9-]+');
+ Route::post('/{id}/guias/{slug}', [InvestmentGuideController::class, 'save'])->whereUuid('id')->where('slug', '[a-z0-9-]+');
Route::get('/{id}/contexto', [InvestorContextController::class, 'show'])->whereUuid('id');
Route::get('/{id}/contexto/editar', [InvestorContextController::class, 'edit'])->whereUuid('id');
Route::post('/{id}/contexto/rascunho', [InvestorContextController::class, 'saveDraft'])->whereUuid('id');
diff --git a/routes/partnerships.php b/routes/partnerships.php
index e89e3a79..feed19fa 100644
--- a/routes/partnerships.php
+++ b/routes/partnerships.php
@@ -12,11 +12,14 @@ Route::middleware(['auth', PartnershipInstalled::class, PrivateInvestmentRespons
Route::get('/parcerias/criar', [Exchange::class, 'edit']);
Route::post('/parcerias/rascunhos', [Exchange::class, 'save']);
Route::get('/parcerias/{id}/editar', [Exchange::class, 'edit'])->whereNumber('id');
+ Route::get('/parcerias/{id}/historico', [Exchange::class, 'publicationHistory'])->whereNumber('id');
Route::put('/parcerias/{id}', [Exchange::class, 'save'])->whereNumber('id');
Route::post('/parcerias/{id}/estado', [Exchange::class, 'transition'])->whereNumber('id');
Route::post('/parcerias/{id}/interesses', [Exchange::class, 'interest'])->whereNumber('id');
Route::post('/parcerias/candidaturas/{id}', [Exchange::class, 'decide'])->whereNumber('id');
+ Route::get('/parcerias/candidaturas/{id}/historico', [Exchange::class, 'candidacyHistory'])->whereNumber('id');
Route::get('/parcerias/salas/{id}', [Exchange::class, 'room'])->whereNumber('id');
+ Route::get('/parcerias/salas/{id}/historico', [Exchange::class, 'agreementHistory'])->whereNumber('id');
Route::post('/parcerias/salas/{id}/mensagens', [Exchange::class, 'message'])->whereNumber('id');
Route::post('/parcerias/salas/{id}/acordo', [Exchange::class, 'agreement'])->whereNumber('id');
Route::post('/parcerias/salas/{id}/marcos', [Exchange::class, 'milestone'])->whereNumber('id');
diff --git a/routes/virtual-desk.php b/routes/virtual-desk.php
index bec109d4..f1014fbf 100644
--- a/routes/virtual-desk.php
+++ b/routes/virtual-desk.php
@@ -1,5 +1,6 @@
group
Route::get('contextos', [Guidance::class, 'contexts']);
Route::post('dossiers', [Desk::class, 'createCase']);
Route::get('dossiers/{id}', [Desk::class, 'showCase'])->whereUuid('id');
+ Route::put('dossiers/{id}/estado', [Desk::class, 'caseState'])->whereUuid('id');
Route::post('dossiers/{id}/etapas', [Desk::class, 'stage'])->whereUuid('id');
Route::post('dossiers/{id}/pedidos', [Desk::class, 'createRequest'])->whereUuid('id');
Route::post('dossiers/{id}/documentos', [Desk::class, 'attach'])->whereUuid('id');
+ Route::get('dossiers/{id}/documentos-disponiveis', [Desk::class, 'availableDocuments'])->whereUuid('id');
Route::get('dossiers/{id}/documentos/{document}', [Desk::class, 'download'])->whereUuid(['id', 'document']);
Route::post('dossiers/{id}/documentos/{document}/conferencia', [Operations::class, 'documentReview'])->whereUuid(['id', 'document']);
Route::get('dossiers/{id}/orientacao', [Guidance::class, 'show'])->whereUuid('id');
@@ -30,10 +33,13 @@ Route::middleware(['auth', 'verified', PrivateInvestmentResponse::class])->group
Route::post('dossiers/{id}/fontes', [Guidance::class, 'search'])->whereUuid('id');
Route::get('pedidos/{id}', [Desk::class, 'showRequest'])->whereUuid('id');
Route::put('pedidos/{id}', [Desk::class, 'save'])->whereUuid('id');
+ Route::get('pedidos/{id}/rascunho', [Checkpoint::class, 'show'])->whereUuid('id');
+ Route::post('pedidos/{id}/rascunho', [Checkpoint::class, 'save'])->whereUuid('id');
Route::post('pedidos/{id}/estado', [Desk::class, 'transition'])->whereUuid('id');
Route::post('pedidos/{id}/responsavel', [Desk::class, 'assign'])->whereUuid('id');
Route::post('pedidos/{id}/mensagens', [Desk::class, 'message'])->whereUuid('id');
Route::post('pedidos/{id}/pagamentos', [Operations::class, 'payment'])->whereUuid('id');
+ Route::put('pedidos/{id}/pagamentos/{payment}/comprovativo', [Operations::class, 'paymentDocument'])->whereUuid(['id', 'payment']);
Route::post('pedidos/{id}/pagamentos/{payment}/conferencia', [Operations::class, 'paymentReview'])->whereUuid(['id', 'payment']);
Route::post('pedidos/{id}/comunicacoes', [Operations::class, 'communication'])->whereUuid('id');
Route::get('pedidos/{id}/recibo', [Desk::class, 'receipt'])->whereUuid('id');
diff --git a/routes/web.php b/routes/web.php
index db29d8c2..0ecbc5b0 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -20,6 +20,7 @@ use App\Http\Controllers\DocumentMalwareController;
use App\Http\Controllers\EconomicReferenceController;
use App\Http\Controllers\EditorialArticleController;
use App\Http\Controllers\EducationController;
+use App\Http\Controllers\EducationDeclarationDraftController;
use App\Http\Controllers\EducationInvestmentController;
use App\Http\Controllers\InvestmentCoordinatesController;
use App\Http\Controllers\InvestmentDiscoveryController;
@@ -40,6 +41,8 @@ use App\Http\Controllers\PortalProfileController;
use App\Http\Controllers\PortalProfileInstallationController;
use App\Http\Controllers\PortalServicesController;
use App\Http\Controllers\ProactiveSupplyController;
+use App\Http\Controllers\ProductExperimentController;
+use App\Http\Controllers\ProductUsageMetricsController;
use App\Http\Controllers\PublicBusinessOpportunityController;
use App\Http\Controllers\PublicGeographyController;
use App\Http\Controllers\PublicPortalController;
@@ -52,6 +55,7 @@ use App\Http\Middleware\EnsurePortalProfileAdministration;
use App\Http\Middleware\EnsurePortalProfiles;
use App\Http\Middleware\EnsureScopedEditorial;
use App\Http\Middleware\EnsureScopedPortalAdministration;
+use App\Http\Middleware\PrivateInvestmentResponse;
use App\Http\Middleware\RequireZoneMfa;
use App\Http\Middleware\VerifiedOrSimpleParticipation;
use App\Services\ContentManagement;
@@ -133,6 +137,14 @@ Route::middleware(['auth', 'verified'])->group(function () {
require __DIR__.'/settings.php';
require __DIR__.'/investment.php';
require __DIR__.'/land-assistance.php';
+Route::get('/management/product-usage', [ProductUsageMetricsController::class, 'index'])->middleware(['auth', 'verified', 'can:manage-portal', PrivateInvestmentResponse::class, 'throttle:30,1']);
+Route::middleware(['auth', 'verified', 'can:manage-portal', PrivateInvestmentResponse::class, 'throttle:30,1'])->prefix('management/product-experiments')->group(function () {
+ Route::get('/', [ProductExperimentController::class, 'index']);
+ Route::get('/new', [ProductExperimentController::class, 'create']);
+ Route::post('/', [ProductExperimentController::class, 'store']);
+ Route::get('/{id}', [ProductExperimentController::class, 'show'])->whereUuid('id');
+ Route::post('/{id}/revisions', [ProductExperimentController::class, 'revise'])->whereUuid('id');
+});
Route::middleware(['auth', 'verified', 'can:manage-portal', AiEnabled::class])->group(function () {
Route::get('/management/ai', [AiController::class, 'index'])->name('ai.index');
@@ -158,6 +170,8 @@ Route::get('/api/v1/investment/territory-geometries', [InvestmentTerritoryContro
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/management/profile-install', [PortalProfileInstallationController::class, 'preview']);
Route::post('/management/profile-install', [PortalProfileInstallationController::class, 'apply']);
+ Route::get('/management/profile-install/technical-support',[PortalProfileInstallationController::class,'supportPreview']);
+ Route::post('/management/profile-install/technical-support',[PortalProfileInstallationController::class,'applySupport']);
Route::post('/management/profile-install/bootstrap', [PortalProfileInstallationController::class, 'bootstrap']);
Route::get('/management/profile-install/bootstrap/{id}', [PortalProfileInstallationController::class, 'bootstrapPreview'])->whereUuid('id');
Route::post('/management/profile-install/bootstrap/{id}/confirm', [PortalProfileInstallationController::class, 'confirmBootstrap'])->whereUuid('id');
@@ -166,6 +180,10 @@ Route::middleware(['auth', 'verified'])->group(function () {
});
Route::middleware(['auth', 'verified', EnsurePortalProfileAdministration::class])->group(function () {
+ Route::get('/suporte-tecnico/incidentes',[\App\Http\Controllers\TechnicalSupportController::class,'index']);
+ Route::get('/suporte-tecnico/incidentes/{reference}',[\App\Http\Controllers\TechnicalSupportController::class,'show'])->whereUuid('reference');
+ Route::post('/suporte-tecnico/incidentes/{reference}',[\App\Http\Controllers\TechnicalSupportController::class,'decide'])->whereUuid('reference');
+ Route::post('/suporte-tecnico/incidentes/{reference}/consultado',[\App\Http\Controllers\TechnicalSupportController::class,'consulted'])->whereUuid('reference');
$profiles = PortalProfileController::class;
Route::get('/perfil/promotor', [$profiles, 'requests']);
Route::post('/perfil/promotor', [$profiles, 'requestProfile']);
@@ -185,6 +203,7 @@ Route::middleware(['auth', 'verified', EnsurePortalProfileAdministration::class]
Route::middleware(['auth', 'verified', EnsurePortalProfiles::class])->group(function () {
Route::get('/minhas-oportunidades/oferta-interna', [ProactiveSupplyController::class, 'index'])->middleware('throttle:60,1');
+ Route::get('/minhas-oportunidades/oferta-interna/revisao', [ProactiveSupplyController::class, 'review'])->middleware(['throttle:60,1', PrivateInvestmentResponse::class]);
$profiles = PortalProfileController::class;
Route::get('/minhas-oportunidades', [$profiles, 'opportunities']);
Route::get('/minhas-oportunidades/lotes/agronegocio', [CorridorAgribusinessController::class, 'show']);
@@ -251,7 +270,13 @@ Route::middleware(['auth', 'verified', EnsureScopedPortalAdministration::class])
Route::post('territories/{kind}/{id}', [InvestmentTerritoryController::class, 'save']);
$controller = PortalManagementController::class;
Route::prefix('education')->name('education.')->middleware(EducationEnabled::class)->group(function () {
+ Route::get('drafts/{kind}', [EducationDeclarationDraftController::class, 'index'])->whereIn('kind', ['demands', 'capacities']);
+ Route::post('drafts/{kind}', [EducationDeclarationDraftController::class, 'save'])->whereIn('kind', ['demands', 'capacities']);
+ Route::get('drafts/{kind}/{id}', [EducationDeclarationDraftController::class, 'show'])->whereIn('kind', ['demands', 'capacities'])->whereUuid('id');
+ Route::put('drafts/{kind}/{id}', [EducationDeclarationDraftController::class, 'save'])->whereIn('kind', ['demands', 'capacities'])->whereUuid('id');
+ Route::post('drafts/{kind}/{id}/submit', [EducationDeclarationDraftController::class, 'submit'])->whereIn('kind', ['demands', 'capacities'])->whereUuid('id');
Route::get('/', [EducationController::class, 'index'])->name('index');
+ Route::get('{kind}/{id}', [EducationController::class, 'declaration'])->whereIn('kind',['demands','capacities'])->whereUuid('id')->name('declaration');
Route::post('catalog/{kind}', [EducationController::class, 'catalog'])->whereIn('kind', ['skills', 'occupations', 'providers', 'courses'])->name('catalog');
Route::post('{kind}', [EducationController::class, 'store'])->whereIn('kind', ['demands', 'capacities'])->name('store');
Route::post('{kind}/{id}/review', [EducationController::class, 'review'])->whereIn('kind', ['demands', 'capacities'])->whereUuid('id')->name('review');
@@ -293,6 +318,7 @@ Route::middleware(['auth', 'verified', EnsureScopedPortalAdministration::class])
Route::get('crm/leads/{lead}', [CrmController::class, 'show'])->name('crm.lead');
Route::patch('crm/leads/{lead}', [CrmController::class, 'update'])->name('crm.update');
Route::post('crm/leads/{lead}/tasks', [CrmController::class, 'task'])->name('crm.tasks');
+ Route::post('crm/leads/{lead}/task-preparation', [CrmController::class, 'taskPreparation'])->name('crm.task-preparation');
Route::patch('crm/leads/{lead}/tasks/{task}', [CrmController::class, 'updateTask'])->name('crm.task-update');
Route::get('history', [$controller, 'history'])->name('history');
Route::get('interests/atribuicoes', [$controller, 'interestAssignments'])->name('interests.assignments');
diff --git a/tests/Feature/BusinessPointPublicationTest.php b/tests/Feature/BusinessPointPublicationTest.php
new file mode 100644
index 00000000..a2411e46
--- /dev/null
+++ b/tests/Feature/BusinessPointPublicationTest.php
@@ -0,0 +1,242 @@
+withoutVite();
+ config(['existing-business.enabled' => true, 'portal.profile_access_enabled' => false, 'portal.profile_administration_enabled' => false]);
+ $this->owner = User::factory()->create();
+ $country = $this->territory('country');
+ $this->province = $this->territory('province', $country);
+ $this->district = $this->territory('district', $this->province);
+ $this->sector = DB::table('sectors')->insertGetId(['name' => 'Synthetic point sector', 'slug' => 'synthetic-point-sector', 'is_active' => true]);
+ }
+
+ private function territory(string $kind, ?string $parent = null): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $id, 'name' => 'Synthetic '.$kind, 'code' => $id, 'location_type' => $kind,
+ 'parent_id' => $parent, 'version_no' => 1, 'data_classification' => 'public', 'source_system' => 'cartografia-workbook',
+ 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$id]);
+
+ return $id;
+ }
+
+ private function draft(array $payload = []): array
+ {
+ return ['modality' => 'participation_sale', 'classification' => 'restricted', 'reason' => 'Synthetic point preparation',
+ 'public_title' => 'Synthetic public point listing', 'sector_id' => $this->sector,
+ 'payload' => [...[
+ 'title' => 'Synthetic private point listing', 'description' => 'Synthetic description for a staged independent publication.',
+ 'source_reference' => 'SYNTHETIC source already registered', 'source_date' => '2026-10-02',
+ 'geography_scope' => 'specific', 'province_id' => $this->province, 'district_id' => $this->district,
+ 'location_unknown' => 'no', 'disclosure_precision' => 'exact', 'location_point_enabled' => 'yes',
+ 'location_latitude' => '-26.0001', 'location_longitude' => '32.0001',
+ 'location_point_source_mode' => 'listing', 'location_point_share_source' => 'yes',
+ ], ...$payload]];
+ }
+
+ private function create(array $payload = []): array
+ {
+ return $this->actingAs($this->owner)->postJson($this->base, $this->draft($payload))->assertCreated()->json();
+ }
+
+ private function designated(string $role): User
+ {
+ $user = User::factory()->create();
+ $user->forceFill(['two_factor_secret' => Crypt::encryptString('SYNTHETIC'), 'two_factor_confirmed_at' => now()])->save();
+ config(['portal.managers' => [...config('portal.managers', []), $user->email],
+ 'existing-business.'.$role => [...config('existing-business.'.$role, []), $user->email]]);
+
+ return $user;
+ }
+
+ private function approve(string $id, int $version): User
+ {
+ $locationsBefore = DB::table('existing_business_locations')->orderBy('id')->get()->toJson();
+ $roles = ['submitted' => null, 'triage' => 'triagers', 'in_review' => 'reviewers', 'approval_l1' => 'reviewers', 'approval_l2' => 'approvers_l1', 'approved' => 'approvers_l2'];
+ $users = [];
+ foreach ($roles as $action => $role) {
+ if ($role === null) {
+ $this->actingAs($this->owner);
+ } else {
+ $this->actingAsWithMfa($users[$role] ??= $this->designated($role));
+ }
+ $this->postJson($this->base.'/'.$id.'/transitions', ['version_no' => $version++, 'action' => $action,
+ 'note' => 'Synthetic normal workflow decision', 'review_consent' => $action === 'submitted'])->assertOk();
+ $this->assertSame($locationsBefore, DB::table('existing_business_locations')->orderBy('id')->get()->toJson());
+ }
+
+ return $this->designated('publishers');
+ }
+
+ public function test_point_stays_private_until_normal_independent_publication_then_feeds_radius_and_source_dates(): void
+ {
+ $record = $this->create();
+ $id = $record['id'];
+ $this->assertDatabaseCount('existing_business_locations', 0);
+ $raw = DB::table('existing_businesses')->where('id', $id)->value('payload');
+ $this->assertStringNotContainsString('-26.0001', $raw);
+ $this->getJson($this->base.'/'.$id)->assertOk()->assertJsonPath('record.payload.location_point_source_mode', 'listing')
+ ->assertHeader('Cache-Control', 'no-store, private');
+ $this->actingAs(User::factory()->create())->getJson($this->base.'/'.$id)->assertForbidden();
+ $this->getJson('/api/v1/business-opportunities')->assertOk()->assertJsonCount(0, 'data');
+ $publisher = $this->approve($id, 1);
+ $this->actingAs($this->owner)->postJson($this->base.'/'.$id.'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic owner cannot self publish'])->assertForbidden();
+ $this->actingAsWithMfa($publisher)->postJson($this->base.'/'.$id.'/transitions', ['version_no' => 6, 'action' => 'published', 'note' => 'Synthetic stale publication'])->assertConflict();
+ $this->assertDatabaseCount('existing_business_locations', 0);
+ $saved = $this->postJson($this->base.'/'.$id.'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic authorized publication'])->assertOk()->assertJsonPath('version_no', 8);
+ $point = DB::table('existing_business_locations')->where('existing_business_id', $id)->first();
+ $this->assertTrue($point->is_primary);
+ $this->assertTrue($point->is_public);
+ $this->assertSame(8, $point->source_payload_version);
+ $this->assertSame($this->district, $point->district_id);
+ $response = $this->getJson('/api/v1/business-opportunities?'.http_build_query(['near_business' => $id, 'radius_km' => 10]))->assertOk()
+ ->assertJsonCount(1, 'data')->assertJsonPath('data.0.id', $id)
+ ->assertJsonPath('data.0.location_source_reference', 'SYNTHETIC source already registered')
+ ->assertJsonPath('data.0.location_source_date', '2026-10-02')->assertJsonPath('geographicCoverage.origin_source_date', '2026-10-02')
+ ->assertJsonMissingPath('data.0.location_latitude')->assertJsonMissingPath('data.0.source_payload_version');
+ $this->assertStringNotContainsString('-26.0001', $response->getContent());
+ $this->get('/negocios/'.$saved->json('public_slug'))->assertOk()->assertInertia(fn ($page) => $page->where('similarRadiusAvailable', true));
+ $snapshot = json_decode(Crypt::decryptString(DB::table('existing_business_revisions')->where('business_id', $id)->where('action', 'published')->value('snapshot')), true);
+ $this->assertSame('Synthetic district', $snapshot['context']['point_publication']['used']['reference_snapshot'][1]['name']);
+ $this->assertSame('SYNTHETIC source already registered', $snapshot['context']['point_publication']['used']['source_reference']);
+ $this->assertCount(1, $snapshot['locations']);
+ $before = DB::table('existing_business_revisions')->where('business_id', $id)->pluck('sha256')->all();
+ DB::table('geo_locations')->where('id', $this->district)->update(['name' => 'Updated synthetic district', 'version_no' => 2]);
+ $this->assertSame($before, DB::table('existing_business_revisions')->where('business_id', $id)->pluck('sha256')->all());
+ $this->putJson($this->base.'/'.$id, [...$this->draft(), 'version_no' => 8])->assertForbidden();
+ }
+
+ public function test_point_chooses_one_declared_path_and_does_not_assume_the_first_of_multiple_locations(): void
+ {
+ $other = $this->territory('district', $this->province);
+ $paths = [['province_id' => $this->province, 'district_id' => $this->district], ['province_id' => $this->province, 'district_id' => $other]];
+ $record = $this->create(['geography_scope' => 'multiple', 'locations_json' => json_encode($paths)]);
+ $url = $this->base.'/'.$record['id'];
+ $this->postJson($url.'/transitions', ['version_no' => 1, 'action' => 'submitted', 'review_consent' => true, 'note' => 'Synthetic point needs a selected site'])
+ ->assertUnprocessable()->assertJsonValidationErrors('location_point_territory');
+ $key = app(BusinessPointPublication::class)->pathKey($paths[1]);
+ $point = app(BusinessPointPublication::class)->candidate([...$this->draft()['payload'], 'geography_scope' => 'multiple', 'locations_json' => json_encode($paths), 'location_point_territory' => $key]);
+ $this->assertSame($other, $point['path']['district_id']);
+ $this->assertSame('-26.0001', $record['payload']['location_latitude']);
+ $this->expectException(ValidationException::class);
+ app(BusinessPointPublication::class)->candidate([...$this->draft()['payload'], 'geography_scope' => 'multiple', 'locations_json' => json_encode([$paths[0]]), 'location_point_territory' => $key]);
+ }
+
+ public function test_inapplicable_point_fields_remain_private_and_do_not_block_or_activate_a_point(): void
+ {
+ foreach ([['geography_scope' => 'national'], ['geography_scope' => 'digital'], ['disclosure_precision' => 'administrative'], ['location_unknown' => 'yes'], ['location_point_enabled' => 'no']] as $changes) {
+ $payload = [...$this->draft()['payload'], ...$changes, 'location_latitude' => 'unfinished', 'location_point_source_mode' => 'custom', 'location_point_source_date' => 'unfinished'];
+ $record = $this->actingAs($this->owner)->postJson($this->base, $this->draft($payload))->assertCreated()->json();
+ $this->assertSame('unfinished', $record['payload']['location_latitude']);
+ $this->assertNull(app(BusinessPointPublication::class)->candidate($payload));
+ }
+ $this->assertDatabaseCount('existing_business_locations', 0);
+ }
+
+ public function test_custom_source_unknown_date_and_reserved_reference_are_preserved_without_false_public_citation(): void
+ {
+ $record = $this->create(['location_point_source_mode' => 'custom', 'location_point_source_reference' => 'SYNTHETIC PRIVATE point source', 'location_point_source_date' => '', 'location_point_share_source' => 'no']);
+ $publisher = $this->approve($record['id'], 1);
+ $this->actingAsWithMfa($publisher)->postJson($this->base.'/'.$record['id'].'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic authorized source-aware publication'])->assertOk();
+ $this->getJson('/api/v1/business-opportunities')->assertOk()->assertJsonPath('data.0.location_source_reference', null)->assertJsonPath('data.0.location_source_date', null)
+ ->assertDontSee('SYNTHETIC PRIVATE point source');
+ $snapshot = Crypt::decryptString(DB::table('existing_business_revisions')->where('business_id', $record['id'])->where('action', 'published')->value('snapshot'));
+ $this->assertStringContainsString('SYNTHETIC PRIVATE point source', $snapshot);
+ $this->assertStringNotContainsString('SYNTHETIC PRIVATE point source', DB::table('existing_business_revisions')->where('business_id', $record['id'])->where('action', 'published')->value('snapshot'));
+ }
+
+ public function test_invalid_coordinates_and_retired_territory_do_not_publish_or_change_the_workflow(): void
+ {
+ foreach ([['location_latitude' => '91'], ['location_longitude' => '-181'], ['location_latitude' => 'NaN'], ['location_latitude' => 'Infinity']] as $change) {
+ $this->actingAs($this->owner)->postJson($this->base, $this->draft($change))->assertUnprocessable();
+ }
+ $record = $this->create(['location_longitude' => '']);
+ $this->postJson($this->base.'/'.$record['id'].'/transitions', ['version_no' => 1, 'action' => 'submitted', 'review_consent' => true, 'note' => 'Synthetic incomplete point submission'])->assertUnprocessable();
+ $this->assertDatabaseCount('business_workflow_transitions', 0);
+ $record = $this->create();
+ $publisher = $this->approve($record['id'], 1);
+ DB::table('geo_locations')->where('id', $this->district)->update(['data_classification' => 'restricted']);
+ $this->actingAsWithMfa($publisher)->postJson($this->base.'/'.$record['id'].'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic retired point cannot publish'])->assertUnprocessable();
+ $this->assertDatabaseHas('existing_businesses', ['id' => $record['id'], 'status' => 'approved', 'version_no' => 7]);
+ $this->assertDatabaseCount('existing_business_locations', 0);
+ }
+
+ public function test_migration_preserves_legacy_rows_and_public_queries_work_without_optional_source_columns(): void
+ {
+ $migration = require database_path('migrations/2026_11_03_000000_existing_business_location_sources.php');
+ $migration->down();
+ $this->assertFalse(Schema::hasColumn('existing_business_locations', 'public_source_reference'));
+ $this->getJson('/api/v1/business-opportunities')->assertOk();
+ $migration->up();
+ $this->create();
+ DB::table('existing_business_locations')->insert(['id' => (string) Str::uuid(), 'existing_business_id' => DB::table('existing_businesses')->value('id'),
+ 'province_id' => $this->province, 'precision_level' => 'province', 'is_primary' => true, 'is_public' => false, 'source_system' => 'synthetic-private-source']);
+ $this->expectException(\RuntimeException::class);
+ $migration->down();
+ }
+
+ public function test_explicit_point_replacement_preserves_primary_identity_secondary_rows_and_prior_geometry_in_history(): void
+ {
+ $record = $this->create();
+ $primary = (string) Str::uuid();
+ $secondary = (string) Str::uuid();
+ foreach ([$primary, $secondary] as $location) {
+ DB::table('existing_business_locations')->insert(['id' => $location, 'existing_business_id' => $record['id'],
+ 'province_id' => $this->province, 'district_id' => $this->district, 'precision_level' => 'exact', 'is_primary' => $location === $primary,
+ 'is_public' => false, 'geom' => DB::raw("ST_GeomFromText('POINT(33 -27)',4326)"), 'source_system' => 'SYNTHETIC previous source']);
+ }
+ $secondaryBefore = DB::table('existing_business_locations')->where('id', $secondary)->first();
+ $this->getJson($this->base.'/'.$record['id'])->assertOk()->assertJsonPath('registeredLocation.longitude', 33);
+ $publisher = $this->approve($record['id'], 1);
+ $this->actingAsWithMfa($publisher)->postJson($this->base.'/'.$record['id'].'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic explicit reviewed replacement'])->assertOk();
+ $this->assertDatabaseCount('existing_business_locations', 2);
+ $this->assertDatabaseHas('existing_business_locations', ['id' => $primary, 'is_primary' => true, 'is_public' => true, 'source_system' => 'portal-business-form']);
+ $this->assertEquals($secondaryBefore, DB::table('existing_business_locations')->where('id', $secondary)->first());
+ $snapshot = json_decode(Crypt::decryptString(DB::table('existing_business_revisions')->where('business_id', $record['id'])->where('action', 'published')->value('snapshot')), true);
+ $this->assertSame('SRID=4326;POINT(33 -27)', $snapshot['context']['point_publication']['previous']['geometry_snapshot']);
+ $this->assertSame('SYNTHETIC previous source', $snapshot['context']['point_publication']['previous']['source_system']);
+ }
+
+ public function test_no_point_opt_in_preserves_existing_location_and_source_through_publication(): void
+ {
+ $record = $this->create(['location_point_enabled' => 'no']);
+ DB::table('existing_business_locations')->insert(['id' => (string) Str::uuid(), 'existing_business_id' => $record['id'],
+ 'province_id' => $this->province, 'precision_level' => 'province', 'is_primary' => true, 'is_public' => true,
+ 'source_system' => 'SYNTHETIC preserved source', 'public_source_reference' => 'Synthetic previous public citation']);
+ $before = DB::table('existing_business_locations')->first();
+ $publisher = $this->approve($record['id'], 1);
+ $this->actingAsWithMfa($publisher)->postJson($this->base.'/'.$record['id'].'/transitions', ['version_no' => 7, 'action' => 'published', 'note' => 'Synthetic preserve source publication'])->assertOk();
+ $this->assertEquals($before, DB::table('existing_business_locations')->first());
+ $this->getJson('/api/v1/business-opportunities')->assertOk()->assertJsonPath('data.0.location_source_reference', 'Synthetic previous public citation')->assertJsonPath('data.0.distance_km', null);
+ }
+}
diff --git a/tests/Feature/BusinessProximitySearchTest.php b/tests/Feature/BusinessProximitySearchTest.php
new file mode 100644
index 00000000..d4aa9b38
--- /dev/null
+++ b/tests/Feature/BusinessProximitySearchTest.php
@@ -0,0 +1,157 @@
+withoutVite();
+ config(['existing-business.enabled' => true]);
+ }
+
+ private function business(?string $geometry = 'POINT(32 -26)', array $location = [], array $attributes = []): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('existing_businesses')->insert([...[
+ 'id' => $id, 'code' => 'QA-'.Str::uuid(), 'owner_user_id' => User::factory()->create()->id,
+ 'modality' => 'company_sale', 'status' => 'published', 'classification' => 'confidential',
+ 'version_no' => 1, 'payload' => Crypt::encryptString('{"title":"PRIVATE SYNTHETIC"}'),
+ 'public_title' => 'Synthetic public '.$id, 'public_slug' => 'qa-'.$id,
+ 'published_at' => now()->subDay(), 'created_at' => now(), 'updated_at' => now(),
+ ], ...$attributes]);
+ if ($geometry !== null || $location !== []) {
+ DB::table('existing_business_locations')->insert([...[
+ 'id' => (string) Str::uuid(), 'existing_business_id' => $id,
+ 'precision_level' => 'exact', 'is_primary' => true, 'is_public' => true,
+ 'geom' => $geometry === null ? null : DB::raw("ST_GeomFromText('".$geometry."',4326)"),
+ 'created_at' => '2026-10-01 10:00:00+00', 'updated_at' => '2026-10-02 10:00:00+00',
+ ], ...$location]);
+ }
+
+ return $id;
+ }
+
+ private function url(string $origin, array $filters = []): string
+ {
+ return '/api/v1/business-opportunities?'.http_build_query(['near_business' => $origin, 'radius_km' => 20, ...$filters]);
+ }
+
+ public function test_radius_orders_by_distance_excludes_unusable_and_private_points_and_retains_context(): void
+ {
+ $origin = $this->business();
+ $near = $this->business('POINT(32.01 -26)');
+ $far = $this->business('POINT(34 -26)');
+ $this->business('POINT(32.001 -26)', ['is_public' => false]);
+ $this->business('POINT(32.001 -26)', ['is_primary' => false]);
+ $this->business('POLYGON((32 -26,32.01 -26,32.01 -26.01,32 -26))');
+ $this->business('POINT(200 -26)');
+ $this->business(null);
+ $this->business('POINT(32.001 -26)', [], ['status' => 'draft']);
+ $this->business('POINT(32.001 -26)', [], ['published_at' => now()->addDay()]);
+ $this->business('POINT(32.001 -26)', [], ['expires_at' => now()->subDay()]);
+ $deleted = $this->business();
+ DB::table('existing_businesses')->where('id', $deleted)->update(['deleted_at' => now()]);
+ $response = $this->getJson($this->url($origin))->assertOk()->assertJsonCount(2, 'data')
+ ->assertJsonPath('data.0.id', $origin)->assertJsonPath('data.0.distance_km', 0)
+ ->assertJsonPath('data.1.id', $near)->assertJsonPath('geographicCoverage.with_public_point', 3)
+ ->assertJsonPath('geographicCoverage.without_public_point', 5)
+ ->assertJsonPath('geographicCoverage.origin_id', $origin)
+ ->assertJsonPath('data.1.location_recorded_at', '2026-10-02T10:00:00+00:00');
+ $this->assertGreaterThan(0, $response->json('data.1.distance_km'));
+ $this->assertLessThan(2, $response->json('data.1.distance_km'));
+ foreach (['geom', 'point', 'ewkt', 'owner_user_id', 'payload'] as $field) {
+ $response->assertJsonMissingPath('data.0.'.$field)->assertJsonMissingPath('geographicCoverage.'.$field);
+ }
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', $response->getContent());
+ $first = $this->getJson($this->url($origin, ['per_page' => 1]))->assertOk();
+ $next = $first->json('links.next');
+ $this->assertStringContainsString('near_business='.$origin, $next);
+ $this->getJson($next)->assertOk()->assertJsonPath('data.0.id', $near);
+ $this->getJson($this->url($origin, ['radius_km' => 300]))->assertOk()->assertJsonCount(3, 'data')->assertJsonPath('data.2.id', $far);
+ $this->get('/negocios?'.http_build_query(['near_business' => $origin, 'radius_km' => 20]))
+ ->assertInertia(fn (Assert $page) => $page->where('geographicCoverage.origin_id', $origin)->has('results.data', 2));
+ $query = '?'.http_build_query(['near_business' => $origin, 'radius_km' => 20]);
+ $this->get('/negocios/qa-'.$near.$query)->assertInertia(fn (Assert $page) => $page
+ ->where('similarRadiusAvailable', true)->where('returnUrl', '/negocios'.$query)
+ ->where('interestUrl', '/negocios/qa-'.$near.'/manifestar-interesse'.$query));
+ }
+
+ public function test_radius_combines_sector_modality_and_disclosed_classification_without_widening(): void
+ {
+ $sector = Sector::create(['name' => 'Synthetic QA', 'slug' => 'synthetic-proximity', 'is_active' => true, 'published_at' => now()]);
+ $origin = $this->business();
+ $match = $this->business('POINT(32.01 -26)', [], ['sector_id' => $sector->id]);
+ $this->business('POINT(32.01 -26)', [], ['sector_id' => $sector->id]);
+ $other = $this->business('POINT(32.01 -26)', [], ['sector_id' => $sector->id, 'modality' => 'real_estate']);
+ $wrongSector = $this->business('POINT(32.01 -26)');
+ foreach ([$match, $other, $wrongSector] as $id) {
+ $row = ['related_id' => (string) $sector->id, 'classification' => ['target_type' => 'sector', 'purpose' => 'coverage',
+ 'disclosure' => 'public', 'requested_state' => 'preliminary', 'external_status' => 'not_declared', 'source_reference' => 'Synthetic QA source']];
+ $state = ['schema_version' => ExistingBusinessClassification::VERSION, 'relations' => [$row], 'authors' => [], 'decisions' => [], 'publication' => [$row]];
+ DB::table('existing_business_revisions')->insert(['id' => (string) Str::uuid(), 'business_id' => $id, 'version_no' => 1,
+ 'action' => 'classification_disclosed', 'snapshot' => Crypt::encryptString(json_encode(['context' => ['multidimensional' => $state]], JSON_THROW_ON_ERROR)),
+ 'sha256' => hash('sha256', $id), 'actor_id' => DB::table('existing_businesses')->where('id', $id)->value('owner_user_id'),
+ 'reason' => 'Synthetic disclosed classification', 'created_at' => now()]);
+ }
+ $this->getJson($this->url($origin, ['sector' => $sector->id, 'modality' => 'company_sale', 'association_type' => 'sector', 'association_target' => (string) $sector->id]))
+ ->assertOk()->assertJsonCount(1, 'data')->assertJsonPath('data.0.id', $match)
+ ->assertJsonPath('geographicCoverage.with_public_point', 1)->assertJsonPath('geographicCoverage.without_public_point', 0);
+ }
+
+ public function test_invalid_or_unpublished_reference_never_falls_back_to_an_area_or_centroid(): void
+ {
+ $private = $this->business('POINT(32 -26)', ['is_public' => false]);
+ $polygon = $this->business('POLYGON((32 -26,32.01 -26,32.01 -26.01,32 -26))');
+ $draft = $this->business('POINT(32 -26)', [], ['status' => 'draft']);
+ foreach ([$private, $polygon, $draft, (string) Str::uuid()] as $origin) {
+ $this->getJson($this->url($origin))->assertUnprocessable()->assertJsonValidationErrors('near_business');
+ }
+ $origin = $this->business();
+ foreach ([0, -1, 2001, 'bad'] as $radius) {
+ $this->getJson($this->url($origin, ['radius_km' => $radius]))->assertUnprocessable()->assertJsonValidationErrors('radius_km');
+ }
+ $this->getJson('/api/v1/business-opportunities?near_business='.$origin)->assertUnprocessable()->assertJsonValidationErrors('radius_km');
+ $this->getJson('/api/v1/business-opportunities?radius_km=20')->assertUnprocessable()->assertJsonValidationErrors('near_business');
+ }
+
+ public function test_coarse_precision_does_not_disclose_a_finer_territory_through_filters_or_radius(): void
+ {
+ $ids = ['country' => (string) Str::uuid(), 'province' => (string) Str::uuid(), 'district' => (string) Str::uuid()];
+ foreach ($ids as $kind => $id) {
+ DB::table('geo_locations')->insert(['id' => $id, 'code' => $id, 'name' => 'Synthetic '.$kind, 'location_type' => $kind,
+ 'parent_id' => $kind === 'country' ? null : $ids[$kind === 'province' ? 'country' : 'province'],
+ 'data_classification' => 'public', 'source_system' => 'cartografia-workbook',
+ 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$id]);
+ }
+ $coarse = $this->business('POINT(32 -26)', ['precision_level' => 'province', 'province_id' => $ids['province'], 'district_id' => $ids['district']]);
+ $fine = $this->business('POINT(32 -26)', ['precision_level' => 'district', 'province_id' => $ids['province'], 'district_id' => $ids['district']]);
+ $this->getJson('/api/v1/business-opportunities?province_id='.$ids['province'].'&district_id='.$ids['district'])
+ ->assertOk()->assertJsonCount(1, 'data')->assertJsonPath('data.0.id', $fine);
+ $this->getJson('/api/v1/business-opportunities/qa-'.$coarse)->assertOk()->assertJsonPath('data.district', null);
+ foreach ([$coarse, $fine] as $origin) {
+ $this->getJson($this->url($origin))->assertUnprocessable();
+ }
+ $exact = $this->business('POINT(32 -26)', ['province_id' => $ids['province'], 'district_id' => $ids['district']]);
+ $origin = $this->business();
+ $this->getJson($this->url($origin, ['province_id' => $ids['province'], 'district_id' => $ids['district']]))
+ ->assertOk()->assertJsonCount(1, 'data')->assertJsonPath('data.0.id', $exact)
+ ->assertJsonPath('geographicCoverage.with_public_point', 1)->assertJsonPath('geographicCoverage.without_public_point', 1);
+ DB::table('geo_locations')->where('id', $ids['district'])->update(['data_classification' => 'restricted']);
+ $this->getJson($this->url($exact))->assertUnprocessable();
+ $this->getJson('/api/v1/business-opportunities/qa-'.$coarse)->assertOk()->assertJsonPath('data.province', 'Synthetic province');
+ }
+}
diff --git a/tests/Feature/BvmAdmissionGuideTest.php b/tests/Feature/BvmAdmissionGuideTest.php
new file mode 100644
index 00000000..afb6e023
--- /dev/null
+++ b/tests/Feature/BvmAdmissionGuideTest.php
@@ -0,0 +1,174 @@
+withoutVite();
+ config(['investor-path.enabled' => true, 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false]);
+ Http::preventStrayRequests();
+ $this->owner = User::factory()->create();
+ }
+
+ private function dossier(): string
+ {
+ return $this->actingAs($this->owner)->postJson('/investimentos', ['title' => 'SYNTHETIC BVM preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ private function url(string $id, string $slug = 'bolsa'): string
+ {
+ return '/investimentos/'.$id.'/guias/'.$slug;
+ }
+
+ /** @return array */
+ private function input(string $id, string $slug = 'bolsa', array $extra = []): array
+ {
+ return [...['version' => DB::table('desk_cases')->where('id', $id)->value('version'), 'operation_key' => (string) Str::uuid(), 'sha256' => app(InvestmentGuides::class)->guide($slug)['sha256'], 'instruments' => $slug === 'bolsa' ? ['third_shares'] : ['debt'], 'note' => 'SYNTHETIC private '.$slug], ...$extra];
+ }
+
+ public function test_public_guide_has_five_real_paths_with_article_page_and_redaction_per_requirement(): void
+ {
+ $r = $this->getJson('/guias-investimento/bolsa')->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertJsonCount(5, 'guide.instruments')->assertJsonCount(7, 'guide.sources')->assertJsonCount(6, 'guide.preparation')->assertJsonPath('case', null)->json();
+ $guide = $r['guide'];
+ $this->assertSame(['official_shares', 'official_bonds', 'second_shares', 'second_bonds', 'third_shares'], array_keys($guide['instruments']));
+ foreach ([$guide['requirements'], ...array_column($guide['instruments'], 'requirements')] as $requirements) {
+ foreach ($requirements as $requirement) {
+ $this->assertNotEmpty($requirement['citations']);
+ foreach ($requirement['citations'] as $cite) {
+ $this->assertArrayHasKey($cite['source'], $guide['sources']);
+ $this->assertNotEmpty($guide['sources'][$cite['source']]['edition']);
+ $this->assertGreaterThan(0, $cite['page']);
+ $this->assertMatchesRegularExpression('/art|âmbito/iu', $cite['reference']);
+ }
+ }
+ }
+ $this->get('/guias-investimento/bolsa')->assertOk()->assertInertia(fn ($page) => $page->component('investment/guide'));
+ $this->assertDatabaseCount('desk_cases', 0);
+ $this->assertDatabaseCount('desk_requests', 0);
+ }
+
+ public function test_current_minimums_remain_unknown_instead_of_reusing_the_expired_amounts_or_zero(): void
+ {
+ $guide = $this->getJson('/guias-investimento/bolsa')->assertOk()->assertJsonPath('guide.sources.minimums_historical.valid_until', '2025-03-31')->json('guide');
+ foreach ($guide['instruments'] as $path) {
+ $gap = collect($path['requirements'])->firstWhere('kind', 'gap');
+ $this->assertNull($gap['value']);
+ $this->assertSame('MZN', $gap['unit']);
+ $this->assertStringContainsString('31/03/2025', $gap['text']);
+ $this->assertStringContainsString('regulamento anual', $gap['text']);
+ }
+ $serialized = json_encode($guide, JSON_THROW_ON_ERROR);
+ foreach (['16.000.000', '4.000.000', '1.000.000', '8.000.000', '2.000.000'] as $expired) {
+ $this->assertStringNotContainsString($expired, $serialized);
+ }
+ $this->assertStringContainsString('um quarto', $guide['instruments']['second_shares']['requirements'][0]['text']);
+ $this->assertStringContainsString('25%', $guide['instruments']['third_shares']['requirements'][0]['text']);
+ }
+
+ public function test_third_market_uses_2021_instead_of_the_old_nine_month_transition_and_keeps_initial_waivers_scoped(): void
+ {
+ $guide = app(InvestmentGuides::class)->guide('bolsa');
+ $third = collect($guide['instruments']['third_shares']['requirements'])->keyBy('id');
+ $this->assertStringContainsString('dois anos', $third['third_entry_dispersion']['text']);
+ $this->assertStringContainsString('mais um ano', $third['third_entry_dispersion']['text']);
+ $this->assertStringContainsString('sem extensão automática', $third['third_entry_dispersion']['text']);
+ $this->assertStringNotContainsString('nove meses', json_encode($third, JSON_THROW_ON_ERROR));
+ $this->assertSame('exception', $third['third_entry_audit']['kind']);
+ $this->assertStringContainsString('momento do pedido', $third['third_entry_audit']['text']);
+ $this->assertStringContainsString('OCAM', $third['third_finances']['text']);
+ $this->assertStringContainsString('semestrais', $third['third_reporting']['text']);
+ $docs = collect($guide['documents'])->keyBy('id');
+ $this->assertNotContains('third_shares', $docs['audit']['paths']);
+ $this->assertContains('third_shares', $docs['updated_information']['paths']);
+ $this->assertStringContainsString('não reproduz uma dispensa geral', $docs['updated_information']['text']);
+ $this->assertStringContainsString('um ano', $guide['instruments']['second_shares']['requirements'][1]['text']);
+ $this->assertStringContainsString('nove meses', $guide['instruments']['second_shares']['requirements'][1]['text']);
+ }
+
+ public function test_sources_distinguish_supervision_sponsorship_registry_and_the_2022_nominative_and_sas_rules(): void
+ {
+ $guide = app(InvestmentGuides::class)->guide('bolsa');
+ $roles = implode(' ', array_column($guide['eligibility'], 'text'));
+ foreach (['Banco de Moçambique', 'BVM', 'operador', 'Central de Valores Mobiliários', 'Não é um regulador separado'] as $expected) {
+ $this->assertStringContainsString($expected, $roles);
+ }
+ $rules = collect($guide['requirements'])->keyBy('id');
+ $this->assertStringContainsString('simplificada', $rules['legal_form']['text']);
+ $this->assertSame(63, $rules['legal_form']['citations'][1]['page']);
+ $this->assertStringContainsString('2022', $rules['nominative']['text']);
+ $this->assertStringContainsString('ao portador', $rules['nominative']['text']);
+ foreach ($guide['handoffs'] as $link) {
+ $this->assertStringStartsWith('https://www.bvm.co.mz/', $link['url']);
+ $this->assertStringNotContainsString('?', $link['url']);
+ }
+ }
+
+ public function test_dossier_choice_and_creation_pin_the_bvm_edition_without_saving_or_submitting_by_arrasto(): void
+ {
+ $guide = app(InvestmentGuides::class)->guide('bolsa');
+ $selection = ['slug' => 'bolsa', 'sha256' => $guide['sha256'], 'instruments' => ['second_bonds', 'third_shares']];
+ $target = '/investimentos?'.http_build_query(['investment_guide' => $selection]);
+ $this->get($target)->assertRedirect('/login');
+ $this->assertSame(url($target), session('url.intended'));
+ $id = $this->dossier();
+ $this->getJson($target)->assertOk()->assertJsonPath('guideSelection.slug', 'bolsa');
+ $record = $this->postJson('/investimentos', ['title' => 'SYNTHETIC selected destination', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'investment_guide' => $selection])->assertCreated()->json();
+ $this->getJson($record['guide_href'])->assertOk()->assertJsonPath('guide.slug', 'bolsa')->assertJsonPath('instruments', ['second_bonds', 'third_shares'])->assertJsonPath('saved', null);
+ $this->assertSame(0, DB::table('desk_events')->where('action', InvestmentGuides::EVENT)->count());
+ $this->getJson($this->url($id).'?instruments[0]=third_bonds')->assertUnprocessable();
+ $this->getJson($this->url($id).'?instruments[0]=debt')->assertUnprocessable();
+ }
+
+ public function test_multiple_guides_reuse_one_dossier_and_cannot_replay_or_open_each_others_revisions(): void
+ {
+ $id = $this->dossier();
+ $before = DB::table('journey_steps')->orderBy('id')->get()->toJson();
+ $capital = $this->input($id, 'capitalizacao');
+ $this->postJson($this->url($id, 'capitalizacao'), $capital)->assertOk();
+ $first = $this->getJson($this->url($id, 'capitalizacao'))->json();
+ $bvm = $this->input($id);
+ $this->postJson($this->url($id), $bvm)->assertOk()->assertJsonPath('revision', 1);
+ $this->postJson($this->url($id), $bvm)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($this->url($id), [...$bvm, 'operation_key' => $capital['operation_key']])->assertConflict();
+ $this->getJson($this->url($id).'?revision='.$first['history'][0]['id'])->assertNotFound();
+ $this->getJson($this->url($id, 'capitalizacao'))->assertOk()->assertJsonPath('saved', $first['saved'])->assertJsonCount(1, 'history');
+ $this->getJson($this->url($id))->assertOk()->assertJsonCount(1, 'history')->assertJsonPath('guide.slug', 'bolsa');
+ $this->assertSame($before, DB::table('journey_steps')->orderBy('id')->get()->toJson());
+ $stored = DB::table('desk_cases')->where('id', $id)->first();
+ $this->assertStringNotContainsString('SYNTHETIC private bolsa', $stored->payload);
+ $payload = app(VirtualDesk::class)->decode($stored->payload);
+ $this->assertCount(2, $payload['investment_guides']);
+ $this->assertDatabaseCount('desk_requests', 0);
+ $this->assertDatabaseCount('organizations', 0);
+ }
+
+ public function test_pagination_filters_the_requested_guide_when_the_shared_event_stream_is_interleaved(): void
+ {
+ $id = $this->dossier();
+ for ($i = 1; $i <= 26; $i++) {
+ $this->postJson($this->url($id), $this->input($id, 'bolsa', ['note' => 'SYNTHETIC BVM revision '.$i]))->assertOk();
+ $this->postJson($this->url($id, 'capitalizacao'), $this->input($id, 'capitalizacao', ['note' => 'SYNTHETIC capital revision '.$i]))->assertOk();
+ }
+ $page = $this->getJson($this->url($id))->assertOk()->assertJsonCount(25, 'history')->assertJsonPath('saved.revision', 26)->json();
+ $old = $this->getJson($this->url($id).'?history_before='.$page['historyNext'])->assertOk()->assertJsonCount(1, 'history')->assertJsonPath('history.0.revision', 1)->json();
+ $this->getJson($this->url($id).'?revision='.$old['history'][0]['id'])->assertOk()->assertJsonPath('guide.slug', 'bolsa')->assertJsonPath('note', 'SYNTHETIC BVM revision 1');
+ $this->getJson($this->url($id, 'capitalizacao').'?revision='.$old['history'][0]['id'])->assertNotFound();
+ }
+}
diff --git a/tests/Feature/CompanyComparisonTest.php b/tests/Feature/CompanyComparisonTest.php
new file mode 100644
index 00000000..3a40eef4
--- /dev/null
+++ b/tests/Feature/CompanyComparisonTest.php
@@ -0,0 +1,199 @@
+withoutVite();
+ config(['investor-path.enabled' => true, 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false]);
+ Http::preventStrayRequests();
+ $this->owner = User::factory()->create();
+ }
+
+ private function dossier(): string
+ {
+ return $this->actingAs($this->owner)->postJson('/investimentos', ['title' => 'SYNTHETIC company preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ public function test_public_incomplete_comparison_uses_exact_mozambican_source_without_writing_or_requiring_ia(): void
+ {
+ $this->getJson('/formas-juridicas')->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertJsonPath('result.source.sha256', '8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f')
+ ->assertJsonCount(5, 'result.forms')->assertJsonPath('case', null)->assertJsonCount(8, 'result.pending');
+ $this->get('/formas-juridicas')->assertOk()->assertInertia(fn ($page) => $page->component('investment/company-comparison'));
+ $this->assertDatabaseCount('desk_cases', 0);
+ $this->assertDatabaseCount('organizations', 0);
+ }
+
+ public function test_answers_explain_single_participant_and_listing_conflicts_without_an_automatic_winner(): void
+ {
+ $r = $this->getJson('/formas-juridicas?'.http_build_query(['answers' => ['purpose' => 'new', 'participants' => 'one', 'listing' => 'yes', 'participation' => 'shares', 'preferred' => 'simplified']]))->assertOk();
+ $forms = collect($r->json('result.forms'))->keyBy('code');
+ $this->assertNotEmpty($forms['collective']['constraints']);
+ $this->assertNotEmpty($forms['simplified']['constraints']);
+ $this->assertTrue($forms['simplified']['selected']);
+ foreach (['quotas', 'anonymous', 'simplified'] as $code) {
+ $this->assertStringContainsString('unipessoal', implode(' ', $forms[$code]['notes']));
+ }
+ $this->assertArrayNotHasKey('score', $forms['simplified']);
+ $this->assertStringContainsString('preferência', implode(' ', $forms['quotas']['notes']));
+ $this->getJson('/formas-juridicas?'.http_build_query(['answers' => ['participants' => 'several']]))->assertOk()->assertJsonCount(1, 'result.forms.0.constraints');
+ $this->getJson('/formas-juridicas?'.http_build_query(['answers' => ['unexpected' => 'field']]))->assertUnprocessable();
+ $this->getJson('/formas-juridicas?'.http_build_query(['answers' => ['preferred' => 'invented']]))->assertUnprocessable();
+ }
+
+ public function test_representation_and_cooperation_keep_inactive_answers_without_treating_them_as_new_societies(): void
+ {
+ foreach (['representation', 'cooperation'] as $purpose) {
+ $this->getJson('/formas-juridicas?'.http_build_query(['answers' => ['purpose' => $purpose, 'participants' => 'one', 'preferred' => 'quotas']]))->assertOk()
+ ->assertJsonCount(0, 'result.forms')->assertJsonPath('result.active', ['purpose', 'regulated'])
+ ->assertJsonPath('answers.participants', 'one')->assertJsonPath('answers.preferred', 'quotas');
+ }
+ }
+
+ public function test_questions_produce_applicable_preparation_without_a_false_choice_between_partners_and_administration(): void
+ {
+ $answers = ['purpose' => 'new', 'participants' => 'several', 'participation' => 'work', 'capital' => 'defined', 'management' => 'both', 'responsibility' => 'limited', 'listing' => 'yes', 'regulated' => 'yes'];
+ $response = $this->getJson('/formas-juridicas?'.http_build_query(['answers' => $answers]))->assertOk()->assertJsonCount(0, 'result.pending');
+ $preparation = implode(' ', $response->json('result.preparation'));
+ foreach (['contribuições definidas', 'poderes de gestão', 'nomeação', 'regime de responsabilidade', 'mercado pretendido', 'habilitações específicas'] as $expected) {
+ $this->assertStringContainsString($expected, $preparation);
+ }
+ $this->assertStringContainsString('trabalho', implode(' ', $response->json('result.forms.1.notes')));
+ }
+
+ public function test_private_comparison_saves_recovers_and_replays_without_changing_master_identity_or_steps(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/forma-juridica';
+ $before = DB::table('journey_steps')->orderBy('id')->get()->toJson();
+ $case = DB::table('desk_cases')->where('id', $id)->first();
+ $payloadBefore = app(VirtualDesk::class)->decode($case->payload);
+ $input = ['version' => $case->version, 'operation_key' => (string) Str::uuid(), 'answers' => ['participants' => 'one', 'preferred' => 'quotas']];
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', false)->assertJsonPath('revision', 1);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, [...$input, 'answers' => ['participants' => 'several']])->assertConflict();
+ $this->getJson($url)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('saved.revision', 1)->assertJsonPath('answers.participants', 'one');
+ $this->assertSame(1, DB::table('desk_events')->where('case_id', $id)->where('action', CompanyComparison::EVENT)->count());
+ $stored = DB::table('desk_cases')->where('id', $id)->first();
+ $payload = app(VirtualDesk::class)->decode($stored->payload);
+ unset($payload['company_comparison']);
+ $this->assertSame($payloadBefore, $payload);
+ $this->assertStringNotContainsString('company_comparison', $stored->payload);
+ $this->assertSame($before, DB::table('journey_steps')->orderBy('id')->get()->toJson());
+ $this->assertDatabaseCount('organizations', 0);
+ $this->assertDatabaseCount('investment_company_declarations', 0);
+ $this->assertDatabaseCount('desk_requests', 0);
+ $currentVersion = $stored->version;
+ $this->postJson($url, [...$input, 'version' => $currentVersion, 'operation_key' => (string) Str::uuid()])->assertOk()->assertJsonPath('unchanged', true);
+ $this->assertSame($currentVersion, DB::table('desk_cases')->where('id', $id)->value('version'));
+ $this->assertSame(1, DB::table('desk_events')->where('case_id', $id)->where('action', CompanyComparison::EVENT)->count());
+ $this->getJson('/investimentos/'.$id)->assertOk()->assertJsonPath('tools.company', $url);
+ $this->postJson($url, [...$input, 'operation_key' => (string) Str::uuid()])->assertConflict();
+ }
+
+ public function test_historical_answers_sources_and_results_do_not_follow_future_engine_changes(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/forma-juridica';
+ $version = DB::table('desk_cases')->where('id', $id)->value('version');
+ $original = ['version' => $version, 'operation_key' => (string) Str::uuid(), 'answers' => ['participants' => 'one']];
+ $this->postJson($url, $original)->assertOk();
+ $first = $this->getJson($url)->assertOk()->json();
+ config(['company-comparison.version' => 'SYNTHETIC-future-version', 'company-comparison.source.edition' => 'SYNTHETIC-future-edition']);
+ config(['company-comparison.questions.synthetic_future' => ['label' => 'SYNTHETIC future question', 'options' => ['unknown' => 'Unknown']]]);
+ $this->postJson($url, [...$original, 'version' => (string) $original['version']])->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('revision', 1);
+ $this->getJson($url)->assertOk()->assertJsonPath('result', $first['result']);
+ $this->postJson($url, ['version' => $first['case']['version'], 'operation_key' => (string) Str::uuid(), 'answers' => ['participants' => 'several']])->assertOk()->assertJsonPath('revision', 2);
+ $revision = $first['history'][0]['id'];
+ $this->getJson($url.'?revision='.$revision)->assertOk()->assertJsonPath('historical', true)->assertJsonPath('result', $first['result'])->assertJsonPath('answers.participants', 'one');
+ $this->getJson($url.'?'.http_build_query(['revision' => $revision, 'answers' => ['participants' => 'several']]))->assertUnprocessable();
+ $this->getJson($url)->assertOk()->assertJsonPath('result.engine_version', 'SYNTHETIC-future-version')->assertJsonPath('answers.participants', 'several');
+ }
+
+ public function test_scope_is_rechecked_before_validation_and_revocation_or_closure_does_not_allow_writes(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/forma-juridica';
+ $input = ['version' => DB::table('desk_cases')->where('id', $id)->value('version'), 'operation_key' => (string) Str::uuid(), 'answers' => []];
+ $this->actingAs(User::factory()->create())->getJson($url)->assertForbidden();
+ $this->postJson($url, [])->assertForbidden();
+ $this->actingAs($this->owner);
+ $this->postJson($url, $input)->assertOk();
+ DB::table('desk_cases')->where('id', $id)->update(['closed_at' => now()]);
+ $this->getJson($url)->assertOk()->assertJsonPath('canWrite', false);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, [...$input, 'operation_key' => (string) Str::uuid()])->assertConflict();
+ }
+
+ public function test_public_answers_continue_through_dossier_choice_and_explicit_creation_without_automatic_save(): void
+ {
+ $answers = ['participants' => 'one', 'preferred' => 'anonymous'];
+ $target = '/investimentos?'.http_build_query(['company_comparison' => $answers]);
+ $this->get($target)->assertRedirect('/login');
+ $this->assertSame(url($target), session('url.intended'));
+ $id = $this->dossier();
+ $this->getJson($target)->assertOk()->assertJsonPath('companyComparisonAnswers.participants', 'one');
+ $record = $this->postJson('/investimentos', ['title' => 'SYNTHETIC comparison destination', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'company_comparison' => $answers])->assertCreated()->json();
+ $this->assertStringContainsString('/forma-juridica?', $record['comparison_href']);
+ $this->getJson($record['comparison_href'])->assertOk()->assertJsonPath('workingCopy', true)->assertJsonPath('answers.preferred', 'anonymous')->assertJsonPath('saved', null);
+ $this->assertSame(0, DB::table('desk_events')->where('action', CompanyComparison::EVENT)->count());
+ $this->getJson('/investimentos/'.$id.'/forma-juridica?'.http_build_query(['answers' => $answers]))->assertOk()->assertJsonPath('saved', null);
+ }
+
+ public function test_organization_coeditor_revocation_is_effective_before_replay_or_validation(): void
+ {
+ $id = $this->dossier();
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC comparison organization', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $id)->update(['organization_id' => $org]);
+ $coeditor = User::factory()->create();
+ $viewer = User::factory()->create();
+ foreach ([[$this->owner, 'officer'], [$coeditor, 'officer'], [$viewer, 'viewer']] as [$actor, $role]) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $actor->id, 'role' => $role]);
+ }
+ $url = '/investimentos/'.$id.'/forma-juridica';
+ $input = ['version' => DB::table('desk_cases')->where('id', $id)->value('version'), 'operation_key' => (string) Str::uuid(), 'answers' => ['participants' => 'several']];
+ $this->actingAs($coeditor)->postJson($url, $input)->assertOk();
+ $this->actingAs($viewer)->getJson($url)->assertOk()->assertJsonPath('canWrite', false);
+ $this->postJson($url, $input)->assertForbidden();
+ $this->actingAs($coeditor);
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $coeditor->id)->update(['deleted_at' => now()]);
+ $this->getJson($url)->assertForbidden();
+ $this->postJson($url, $input)->assertForbidden();
+ $this->postJson($url, [])->assertForbidden();
+ $this->actingAs($this->owner)->getJson($url)->assertOk()->assertJsonPath('answers.participants', 'several');
+ $this->assertSame(1, DB::table('desk_events')->where('case_id', $id)->where('action', CompanyComparison::EVENT)->count());
+ }
+
+ public function test_all_history_pages_recover_old_editions_without_overwriting_the_latest_snapshot(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/forma-juridica';
+ $version = DB::table('desk_cases')->where('id', $id)->value('version');
+ for ($revision = 1; $revision <= 26; $revision++) {
+ $this->postJson($url, ['version' => $version++, 'operation_key' => (string) Str::uuid(), 'answers' => ['participants' => $revision % 2 === 1 ? 'one' : 'several']])->assertOk()->assertJsonPath('revision', $revision);
+ }
+ $page = $this->getJson($url)->assertOk()->assertJsonCount(25, 'history')->assertJsonPath('saved.revision', 26)->json();
+ $this->assertNotNull($page['historyNext']);
+ $older = $this->getJson($url.'?history_before='.$page['historyNext'])->assertOk()->assertJsonCount(1, 'history')->assertJsonPath('history.0.revision', 1)->assertJsonPath('saved.revision', 26)->json();
+ $this->getJson($url.'?revision='.$older['history'][0]['id'])->assertOk()->assertJsonPath('saved.revision', 1);
+ $this->getJson($url)->assertOk()->assertJsonPath('saved.revision', 26);
+ }
+}
diff --git a/tests/Feature/CompanyPreparationTest.php b/tests/Feature/CompanyPreparationTest.php
new file mode 100644
index 00000000..a1a911c2
--- /dev/null
+++ b/tests/Feature/CompanyPreparationTest.php
@@ -0,0 +1,198 @@
+withoutVite();
+ config(['investor-path.enabled' => true, 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false]);
+ Http::preventStrayRequests();
+ $this->owner = User::factory()->create(['name' => 'SYNTHETIC Proponent']);
+ }
+
+ private function dossier(): string
+ {
+ return $this->actingAs($this->owner)->postJson('/investimentos', ['title' => 'SYNTHETIC corporate preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ /** @return array */
+ private function party(array $changes = []): array
+ {
+ return [...['id' => (string) Str::uuid(), 'name' => 'SYNTHETIC Participant', 'kind' => 'person', 'source' => null, 'roles' => ['subscriber'], 'cash' => '0', 'in_kind' => '0', 'paid' => '0'], ...$changes];
+ }
+
+ /** @return array */
+ private function input(string $id, array $facts): array
+ {
+ return ['version' => DB::table('desk_cases')->where('id', $id)->value('version'), 'operation_key' => (string) Str::uuid(), 'facts' => $facts];
+ }
+
+ public function test_private_empty_preparation_needs_no_templates_ia_or_master_writes(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $this->getJson($url)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('definition.template_status', 'source_pending')->assertJsonPath('review.totals', null)->assertJsonPath('saved', null);
+ $this->get($url)->assertOk()->assertInertia(fn ($page) => $page->component('investment/company-preparation'));
+ $this->postJson($url, $this->input($id, []))->assertOk()->assertJsonPath('revision', 1);
+ $this->getJson($url)->assertOk()->assertJsonPath('saved.revision', 1)->assertJsonPath('review.status', 'preparation');
+ $this->assertDatabaseCount('organizations', 0);
+ $this->assertDatabaseCount('investment_company_declarations', 0);
+ $this->assertDatabaseCount('desk_requests', 0);
+ }
+
+ public function test_exact_capital_and_shares_do_not_round_large_or_fractional_values(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $facts = ['form' => 'anonymous', 'currency' => 'MZN', 'capital' => '999999999999999999.000003', 'nominal_value' => '0,000001', 'parties' => [
+ $this->party(['cash' => '999999999999999999', 'in_kind' => '0', 'paid' => '999999999999999999', 'share_count' => '999999999999999999']),
+ $this->party(['cash' => '0.000001', 'in_kind' => '0.000002', 'paid' => '0.000001', 'share_count' => '3']),
+ ]];
+ $this->postJson($url, $this->input($id, $facts))->assertOk();
+ $r = $this->getJson($url)->assertOk()->assertJsonPath('review.totals.subscribed', '999999999999999999.000003')
+ ->assertJsonPath('review.totals.paid', '999999999999999999.000001')->assertJsonPath('review.totals.unpaid', '0.000002')
+ ->assertJsonPath('review.totals.shares_nominal', '1000000000000.000002')->json();
+ $this->assertStringContainsString('valor nominal', implode(' ', $r['review']['issues']));
+ $this->assertStringNotContainsString('soma das subscrições difere', implode(' ', $r['review']['issues']));
+ }
+
+ public function test_unknown_amounts_never_become_zero_and_inconsistencies_can_be_saved_as_draft(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $facts = ['form' => 'quotas', 'capital' => '100', 'currency' => 'MZN', 'parties' => [$this->party(['cash' => null, 'paid' => null])]];
+ $this->postJson($url, $this->input($id, $facts))->assertOk();
+ $this->getJson($url)->assertOk()->assertJsonPath('review.totals.subscribed', null)->assertJsonPath('review.totals.paid', null)->assertJsonPath('review.totals.unpaid', null);
+ $facts['parties'][0]['cash'] = '40';
+ $facts['parties'][0]['paid'] = '41';
+ $this->postJson($url, $this->input($id, $facts))->assertOk();
+ $r = $this->getJson($url)->assertOk()->assertJsonPath('review.totals.unpaid', '-1')->json();
+ $issues = implode(' ', $r['review']['issues']);
+ $this->assertStringContainsString('excede', $issues);
+ $this->assertStringContainsString('difere do capital', $issues);
+ foreach (['-1', '1e3', '1.1234567', '1 000', '1000000000000000000'] as $invalid) {
+ $this->postJson($url, $this->input($id, ['capital' => $invalid]))->assertUnprocessable()->assertJsonValidationErrors('facts.capital');
+ }
+ $this->postJson($url, $this->input($id, ['parties' => [$this->party(['share_count' => '1.5'])]]))->assertUnprocessable();
+ }
+
+ public function test_role_accumulation_distinct_people_and_work_are_not_merged_or_counted_as_capital(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $a = $this->party(['cash' => '10', 'work' => 'SYNTHETIC labour', 'roles' => ['subscriber', 'administrator']]);
+ $b = $this->party(['cash' => '20', 'roles' => ['subscriber', 'representative'], 'represented_id' => $a['id']]);
+ $this->postJson($url, $this->input($id, ['form' => 'collective', 'capital' => '30', 'currency' => 'MZN', 'parties' => [$a, $b]]))->assertOk();
+ $r = $this->getJson($url)->assertOk()->assertJsonCount(2, 'facts.parties')->assertJsonPath('review.totals.subscribed', '30')->json();
+ $this->assertStringContainsString('artigo 266', $r['review']['note']);
+ $this->assertStringNotContainsString('representante', implode(' ', $r['review']['issues']));
+ $this->assertNotContains('beneficial_owner', $r['facts']['parties'][0]['roles']);
+ $b['represented_id'] = $b['id'];
+ $this->postJson($url, $this->input($id, ['parties' => [$a, $b]]))->assertOk();
+ $this->assertStringContainsString('representante', implode(' ', $this->getJson($url)->json('review.issues')));
+ $this->postJson($url, $this->input($id, ['parties' => [$a, $a]]))->assertUnprocessable();
+ }
+
+ public function test_reused_dossier_identity_is_server_resolved_and_historical_values_remain_frozen(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $party = $this->party(['source' => 'case_proponent', 'name' => 'FORGED identity', 'kind' => 'entity']);
+ $this->postJson($url, $this->input($id, ['parties' => [$party]]))->assertOk();
+ $r = $this->getJson($url)->assertOk()->assertJsonPath('facts.parties.0.name', 'SYNTHETIC Proponent')->assertJsonPath('facts.parties.0.kind', 'person')->json();
+ $this->assertSame($id, $r['facts']['parties'][0]['source_snapshot']['reference']);
+ $case = DB::table('desk_cases')->where('id', $id)->first();
+ $payload = app(VirtualDesk::class)->decode($case->payload);
+ $payload['name'] = 'SYNTHETIC future context';
+ DB::table('desk_cases')->where('id', $id)->update(['payload' => app(VirtualDesk::class)->encode($payload)]);
+ $this->postJson($url, $this->input($id, ['parties' => [$party]]))->assertOk()->assertJsonPath('unchanged', true);
+ $this->getJson($url)->assertJsonPath('facts.parties.0.name', 'SYNTHETIC Proponent');
+ $this->postJson($url, $this->input($id, ['parties' => [$this->party(['source' => 'case_company'])]]))->assertUnprocessable();
+ $forged = $this->party(['source_snapshot' => ['reference' => 'invented']]);
+ $this->postJson($url, $this->input($id, ['parties' => [$forged]]))->assertUnprocessable();
+ $stored = DB::table('desk_cases')->where('id', $id)->first();
+ $this->assertStringNotContainsString('SYNTHETIC Proponent', $stored->payload);
+ $event = DB::table('desk_events')->where('case_id', $id)->where('action', CompanyPreparation::EVENT)->first();
+ $this->assertStringNotContainsString('SYNTHETIC Proponent', $event->payload);
+ $this->assertStringNotContainsString('SYNTHETIC Proponent', DB::table('audit_events')->where('entity_id', $id)->get()->toJson());
+ }
+
+ public function test_correct_draft_history_and_dossier_version_are_preserved_without_advancing_workflow(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $before = DB::table('journey_steps')->orderBy('id')->get()->toJson();
+ $input = $this->input($id, ['form' => 'quotas', 'capital' => '10']);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('revision', 1);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, [...$input, 'facts' => ['capital' => '11']])->assertConflict();
+ $this->postJson($url, [...$input, 'operation_key' => (string) Str::uuid()])->assertConflict();
+ $first = $this->getJson($url)->json();
+ $this->postJson($url, $this->input($id, ['form' => 'quotas', 'capital' => '10.000']))->assertOk()->assertJsonPath('unchanged', true);
+ $this->postJson($url, $this->input($id, ['form' => 'individual', 'capital' => '10']))->assertOk()->assertJsonPath('revision', 2);
+ $this->getJson($url)->assertJsonPath('facts.capital', '10')->assertJsonPath('review.totals', null);
+ config(['company-comparison.source.edition' => 'SYNTHETIC future edition']);
+ $this->getJson($url.'?revision='.$first['history'][0]['id'])->assertOk()->assertJsonPath('historical', true)->assertJsonPath('facts.form', 'quotas')->assertJsonPath('definition.source', $first['definition']['source']);
+ $this->getJson($url)->assertJsonPath('saved.revision', 2);
+ $this->assertSame($before, DB::table('journey_steps')->orderBy('id')->get()->toJson());
+ DB::table('desk_cases')->where('id', $id)->update(['closed_at' => now()]);
+ config(['company-comparison.forms' => ['individual' => ['title' => 'SYNTHETIC future catalogue']]]);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, $this->input($id, []))->assertConflict();
+ }
+
+ public function test_all_history_pages_and_cross_dossier_revision_access(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ for ($i = 1; $i <= 26; $i++) {
+ $this->postJson($url, $this->input($id, ['notes' => 'SYNTHETIC revision '.$i]))->assertOk();
+ }
+ $r = $this->getJson($url)->assertJsonCount(25, 'history')->json();
+ $old = $this->getJson($url.'?history_before='.$r['historyNext'])->assertJsonCount(1, 'history')->json();
+ $this->getJson($url.'?revision='.$old['history'][0]['id'])->assertOk()->assertJsonPath('saved.revision', 1);
+ $other = $this->dossier();
+ $this->getJson('/investimentos/'.$other.'/preparar-empresa?revision='.$old['history'][0]['id'])->assertNotFound();
+ $this->getJson($url.'?history_before=invalid')->assertUnprocessable();
+ }
+
+ public function test_current_permission_is_required_before_read_replay_or_validation(): void
+ {
+ $id = $this->dossier();
+ $url = '/investimentos/'.$id.'/preparar-empresa';
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC Org', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $id)->update(['organization_id' => $org]);
+ $editor = User::factory()->create();
+ $viewer = User::factory()->create();
+ foreach ([[$this->owner, 'officer'], [$editor, 'officer'], [$viewer, 'viewer']] as [$actor, $role]) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $actor->id, 'role' => $role]);
+ }
+ $input = $this->input($id, ['notes' => 'SYNTHETIC private']);
+ $this->actingAs($editor)->postJson($url, $input)->assertOk();
+ $this->actingAs($viewer)->getJson($url)->assertOk()->assertJsonPath('canWrite', false);
+ $this->postJson($url, $input)->assertForbidden();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $editor->id)->update(['deleted_at' => now()]);
+ $this->actingAs($editor)->getJson($url)->assertForbidden();
+ $this->postJson($url, $input)->assertForbidden();
+ $this->postJson($url, [])->assertForbidden();
+ $this->actingAs(User::factory()->create())->getJson($url)->assertForbidden();
+ $this->assertSame(1, DB::table('desk_events')->where('case_id', $id)->where('action', CompanyPreparation::EVENT)->count());
+ }
+}
diff --git a/tests/Feature/CrmIntakeTest.php b/tests/Feature/CrmIntakeTest.php
index fd45aaf4..196399c2 100644
--- a/tests/Feature/CrmIntakeTest.php
+++ b/tests/Feature/CrmIntakeTest.php
@@ -124,10 +124,10 @@ class CrmIntakeTest extends TestCase
$this->post('/management/crm/convert/'.$interest->id, $this->data($user))->assertRedirect();
$lead = Lead::firstOrFail();
$task = CrmTask::firstOrFail();
- $this->patch('/management/crm/leads/'.$lead->id.'/tasks/'.$task->id, ['status' => 'done'])->assertSessionHasErrors('status');
+ $this->patch('/management/crm/leads/'.$lead->id.'/tasks/'.$task->id, ['version' => $task->fresh()->getAttribute('version_no'), 'status' => 'done'])->assertSessionHasErrors('status');
$this->post('/management/crm/leads/'.$lead->id.'/tasks', ['title' => 'Reunião', 'due_at' => now()->addDays(2)->toIso8601String(), 'assignee_user_id' => $user->id])->assertRedirect();
- $this->patch('/management/crm/leads/'.$lead->id.'/tasks/'.$task->id, ['status' => 'done'])->assertRedirect();
- $this->patch('/management/crm/leads/'.$lead->id, ['status' => 'qualified', 'owner_user_id' => $user->id, 'qualification_reason' => 'Informação confirmada pelo gestor.'])->assertRedirect();
+ $this->patch('/management/crm/leads/'.$lead->id.'/tasks/'.$task->id, ['version' => $task->fresh()->getAttribute('version_no'), 'status' => 'done'])->assertRedirect();
+ $this->patch('/management/crm/leads/'.$lead->id, ['version' => $lead->fresh()->getAttribute('version_no'), 'status' => 'qualified', 'owner_user_id' => $user->id, 'qualification_reason' => 'Informação confirmada pelo gestor.'])->assertRedirect();
$this->assertSame('qualified', $lead->fresh()->status);
$this->assertDatabaseHas('audit_events', ['entity_id' => $lead->id, 'action' => 'updated']);
}
@@ -141,10 +141,10 @@ class CrmIntakeTest extends TestCase
$contact = Contact::firstOrFail();
$this->get('/management/crm/investors')->assertOk();
$this->get('/management/crm/investors/'.$investor->id)->assertOk();
- $this->patch('/management/crm/investors/'.$investor->id, ['legal_name' => 'Nome revisto', 'investor_type' => 'domestic', 'status' => 'active'])->assertRedirect();
+ $this->patch('/management/crm/investors/'.$investor->id, ['version' => $investor->fresh()->getAttribute('version_no'), 'legal_name' => 'Nome revisto', 'investor_type' => 'domestic', 'status' => 'active'])->assertRedirect();
$this->assertSame('Nome revisto', $investor->fresh()->legal_name);
$other = Contact::create(['full_name' => 'Outro', 'email' => 'other@example.invalid']);
- $this->patch('/management/crm/investors/'.$investor->id.'/contacts/'.$contact->id, ['full_name' => 'Nome revisto', 'email' => 'OTHER@example.invalid'])->assertSessionHasErrors('email');
- $this->patch('/management/crm/investors/'.$investor->id.'/contacts/'.$other->id, ['full_name' => 'Outro', 'email' => 'new@example.invalid'])->assertNotFound();
+ $this->patch('/management/crm/investors/'.$investor->id.'/contacts/'.$contact->id, ['version' => $contact->fresh()->getAttribute('version_no'), 'full_name' => 'Nome revisto', 'email' => 'OTHER@example.invalid'])->assertSessionHasErrors('email');
+ $this->patch('/management/crm/investors/'.$investor->id.'/contacts/'.$other->id, ['version' => $other->fresh()->getAttribute('version_no'), 'full_name' => 'Outro', 'email' => 'new@example.invalid'])->assertNotFound();
}
}
diff --git a/tests/Feature/CrmNextActionTest.php b/tests/Feature/CrmNextActionTest.php
new file mode 100644
index 00000000..5c334ce0
--- /dev/null
+++ b/tests/Feature/CrmNextActionTest.php
@@ -0,0 +1,199 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->manager = User::factory()->create();
+ $this->owner = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->lead = Lead::create(['title' => 'SYNTHETIC next action lead', 'status' => 'new', 'owner_user_id' => $this->manager->id])->fresh();
+ $this->actingAsWithMfa($this->manager);
+ }
+
+ private function caseId(): string
+ {
+ return app(VirtualDesk::class)->createCase($this->owner, ['title' => 'SYNTHETIC next action dossier', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->id;
+ }
+
+ private function task(?string $case = null, array $changes = []): CrmTask
+ {
+ $data = ['lead_id' => $this->lead->id, 'title' => 'SYNTHETIC next action task', 'status' => 'open', 'due_at' => now()->addDay(), 'assignee_user_id' => $this->manager->id];
+ if ($case !== null) {
+ $data = [...$data, 'desk_case_id' => $case, 'accepted_by' => $this->owner->id, 'accepted_at' => now(), 'guidance_key' => 'synthetic-'.Str::uuid(), 'data_classification' => 'confidential', 'external_sync_status' => 'pending_authorization'];
+ }
+
+ return CrmTask::create([...$data, ...$changes])->fresh();
+ }
+
+ private function state(string $case, string $state): void
+ {
+ app(VirtualDesk::class)->changeCaseState($this->owner, $case, ['version' => (int) DB::table('desk_cases')->where('id', $case)->value('version'), 'state' => $state, 'reason' => 'SYNTHETIC owner changes dossier availability', 'client_key' => (string) Str::uuid()]);
+ }
+
+ private function qualification(string $status = 'qualified'): array
+ {
+ return ['version' => $this->lead->fresh()->version_no, 'owner_user_id' => $this->manager->id, 'status' => $status, 'qualification_reason' => 'SYNTHETIC internal qualification reason'];
+ }
+
+ public function test_a_suspended_future_task_cannot_qualify_the_lead(): void
+ {
+ $case = $this->caseId();
+ $task = $this->task($case);
+ $this->state($case, 'closed');
+ $before = [$this->lead->fresh()->getAttributes(), $task->fresh()->getAttributes(), DB::table('audit_events')->count()];
+ $this->patchJson('/management/crm/leads/'.$this->lead->id, $this->qualification())->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->assertSame($before, [$this->lead->fresh()->getAttributes(), $task->fresh()->getAttributes(), DB::table('audit_events')->count()]);
+ }
+
+ public function test_a_suspended_alternative_cannot_allow_finishing_the_last_available_task(): void
+ {
+ $current = $this->task();
+ $case = $this->caseId();
+ $alternative = $this->task($case);
+ $this->state($case, 'closed');
+ $this->patchJson('/management/crm/leads/'.$this->lead->id.'/tasks/'.$current->id, ['version' => 1, 'status' => 'done'])->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->assertSame('open', $current->fresh()->status);
+ $this->assertSame(1, $current->fresh()->version_no);
+ $this->assertSame('open', $alternative->fresh()->status);
+ }
+
+ public function test_guidance_cannot_bypass_the_next_action_rule_for_a_task_linked_to_an_active_lead(): void
+ {
+ $case = $this->caseId();
+ $task = $this->task($case);
+ $events = DB::table('desk_events')->count();
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$task->id, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC attempted final response'])->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->assertSame('open', $task->fresh()->status);
+ $this->assertSame(1, $task->fresh()->version_no);
+ $this->assertSame($events, DB::table('desk_events')->count());
+ }
+
+ public function test_owner_reopening_restores_eligibility_without_rewriting_task_states(): void
+ {
+ $current = $this->task();
+ $case = $this->caseId();
+ $alternative = $this->task($case);
+ $before = $alternative->getAttributes();
+ $this->state($case, 'closed');
+ $this->state($case, 'open');
+ $this->assertSame($before, $alternative->fresh()->getAttributes());
+ $this->patchJson('/management/crm/leads/'.$this->lead->id, $this->qualification())->assertRedirect();
+ $this->patchJson('/management/crm/leads/'.$this->lead->id.'/tasks/'.$current->id, ['version' => 1, 'status' => 'done'])->assertRedirect();
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$alternative->id, ['version' => 1, 'status' => 'cancelled', 'reason' => 'SYNTHETIC last alternative cannot finish'])->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->assertSame('open', $alternative->fresh()->status);
+ }
+
+ public function test_guidance_can_finish_with_another_available_future_task_and_keeps_its_audit_route(): void
+ {
+ $case = $this->caseId();
+ $current = $this->task($case);
+ $other = $this->task(null, ['status' => 'in_progress']);
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$current->id, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC response with next action'])->assertOk();
+ $this->assertSame('done', $current->fresh()->status);
+ $this->assertSame(2, $current->fresh()->version_no);
+ $this->assertSame('in_progress', $other->fresh()->status);
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'guidance_task_updated')->count());
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$current->id, ['version' => 1, 'status' => 'open', 'reason' => 'SYNTHETIC stale response'])->assertConflict();
+ }
+
+ public function test_expired_undated_deleted_and_other_lead_tasks_are_not_future_replacements_but_disqualification_still_works(): void
+ {
+ $current = $this->task(null, ['due_at' => now()->subDay()]);
+ $this->task(null, ['due_at' => null]);
+ $this->task()->delete();
+ $other = Lead::create(['title' => 'SYNTHETIC different lead', 'status' => 'new']);
+ $this->task(null, ['lead_id' => $other->id]);
+ $this->patchJson('/management/crm/leads/'.$this->lead->id, $this->qualification())->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->patchJson('/management/crm/leads/'.$this->lead->id, $this->qualification('disqualified'))->assertRedirect();
+ $this->patchJson('/management/crm/leads/'.$this->lead->id.'/tasks/'.$current->id, ['version' => 1, 'status' => 'done'])->assertRedirect();
+ }
+
+ public function test_guidance_without_a_crm_lead_keeps_existing_permissions_and_owner_closure(): void
+ {
+ $case = $this->caseId();
+ $task = $this->task($case, ['lead_id' => null, 'assignee_user_id' => $this->owner->id]);
+ $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$task->id, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC standalone investor task'])->assertOk();
+ $this->state($case, 'closed');
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$task->id, ['version' => 2, 'status' => 'open', 'reason' => 'SYNTHETIC closed case remains read only'])->assertConflict();
+ $this->assertSame('done', $task->fresh()->status);
+ }
+
+ public function test_new_rule_does_not_grant_crm_or_dossier_access(): void
+ {
+ $case = $this->caseId();
+ $task = $this->task($case);
+ $other = User::factory()->create();
+ $this->actingAs($other)->patchJson('/management/crm/leads/'.$this->lead->id.'/tasks/'.$task->id, ['version' => 1, 'status' => 'done'])->assertForbidden();
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$task->id, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC unrelated account'])->assertForbidden();
+ $this->assertSame('open', $task->fresh()->status);
+ }
+
+ public function test_archived_lead_does_not_block_an_existing_authorized_guidance_response(): void
+ {
+ $case = $this->caseId();
+ $task = $this->task($case);
+ $this->lead->delete();
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/tarefas/'.$task->id, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC archived lead retains dossier response'])->assertOk();
+ $this->assertSame('done', $task->fresh()->status);
+ $this->assertSoftDeleted('leads', ['id' => $this->lead->id]);
+ }
+
+ public function test_unlinked_crm_does_not_depend_on_optional_desk_tables(): void
+ {
+ $first = $this->task();
+ $this->task();
+ DB::statement('ALTER TABLE desk_cases RENAME TO desk_cases_qa_unavailable');
+ try {
+ $this->patchJson('/management/crm/leads/'.$this->lead->id, $this->qualification())->assertRedirect();
+ $this->patchJson('/management/crm/leads/'.$this->lead->id.'/tasks/'.$first->id, ['version' => 1, 'status' => 'done'])->assertRedirect();
+ } finally {
+ DB::statement('ALTER TABLE desk_cases_qa_unavailable RENAME TO desk_cases');
+ }
+ }
+
+ public function test_read_models_distinguish_suspended_tasks_and_keep_their_history(): void
+ {
+ $case = $this->caseId();
+ $suspended = $this->task($case, ['due_at' => now()->subDay()]);
+ $this->state($case, 'closed');
+ $available = $this->task(null, ['due_at' => now()->subHour()]);
+ $this->get('/management/crm/leads')->assertInertia(fn ($page) => $page->where('leads.data.0.overdue_tasks_count', 1));
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertInertia(fn ($page) => $page->where('nextAction.future_tasks', 0)->has('lead.tasks', 2));
+ $this->assertSame('open', $suspended->fresh()->status);
+ $this->assertSame('open', $available->fresh()->status);
+ $available->delete();
+ $alerts = app(AssistiveRules::class)->quality();
+ $this->assertCount(1, array_filter($alerts, fn ($row) => ($row['rule'] ?? null) === 'missing_next_action' && ($row['record_id'] ?? null) === $this->lead->id));
+ Http::assertNothingSent();
+ Mail::assertNothingSent();
+ }
+}
diff --git a/tests/Feature/CrmRecordVersionsTest.php b/tests/Feature/CrmRecordVersionsTest.php
new file mode 100644
index 00000000..8b3b4cfb
--- /dev/null
+++ b/tests/Feature/CrmRecordVersionsTest.php
@@ -0,0 +1,140 @@
+withoutVite();
+ $this->first = User::factory()->create();
+ $this->second = User::factory()->create();
+ config(['portal.managers' => [$this->first->email, $this->second->email]]);
+ $this->actingAsWithMfa($this->first);
+ $this->investor = Investor::create(['legal_name' => 'SYNTHETIC original investor', 'investor_type' => 'domestic', 'status' => 'prospect'])->fresh();
+ }
+
+ private function investorData(array $changes = []): array
+ {
+ return ['version' => 1, 'legal_name' => 'SYNTHETIC first edit', 'investor_type' => 'domestic', 'status' => 'active', ...$changes];
+ }
+
+ public function test_stale_investor_form_cannot_overwrite_a_more_recent_edit_and_audit_excludes_personal_text(): void
+ {
+ $url = '/management/crm/investors/'.$this->investor->id;
+ $this->patchJson($url, $this->investorData())->assertRedirect();
+ $this->actingAsWithMfa($this->second)->patchJson($url, $this->investorData(['legal_name' => 'SYNTHETIC stale edit']))->assertUnprocessable()->assertJsonValidationErrors('version');
+ $this->assertDatabaseHas('investors', ['id' => $this->investor->id, 'legal_name' => 'SYNTHETIC first edit', 'version_no' => 2]);
+ $events = DB::table('audit_events')->where('entity_type', 'investors')->where('entity_id', $this->investor->id)->where('action', 'updated')->get();
+ $this->assertCount(1, $events);
+ $this->assertSame(1, json_decode($events[0]->before_data, true)['values']['version_no']);
+ $this->assertSame(2, json_decode($events[0]->after_data, true)['values']['version_no']);
+ $this->assertStringNotContainsString('SYNTHETIC first edit', $events[0]->after_data);
+ }
+
+ public function test_shared_contact_has_one_version_across_investors_and_old_forms_do_not_restore_old_phone(): void
+ {
+ $contact = Contact::create(['full_name' => 'SYNTHETIC shared contact', 'email' => 'synthetic-shared@example.invalid', 'phone' => '111'])->fresh();
+ $other = Investor::create(['legal_name' => 'SYNTHETIC other investor', 'investor_type' => 'domestic', 'status' => 'prospect']);
+ foreach ([$this->investor->id, $other->id] as $id) {
+ DB::table('investor_contacts')->insert(['investor_id' => $id, 'contact_id' => $contact->id]);
+ }
+ $data = ['version' => 1, 'full_name' => 'SYNTHETIC shared contact', 'email' => 'SYNTHETIC-SHARED@example.invalid', 'phone' => '222'];
+ $this->patchJson('/management/crm/investors/'.$this->investor->id.'/contacts/'.$contact->id, $data)->assertRedirect();
+ $this->actingAsWithMfa($this->second)->patchJson('/management/crm/investors/'.$other->id.'/contacts/'.$contact->id, [...$data, 'phone' => '111', 'full_name' => 'SYNTHETIC stale name'])->assertUnprocessable()->assertJsonValidationErrors('version');
+ $this->assertDatabaseHas('contacts', ['id' => $contact->id, 'phone' => '222', 'email' => 'synthetic-shared@example.invalid', 'version_no' => 2]);
+ $this->get('/management/crm/investors/'.$other->id)->assertOk()->assertInertia(fn ($page) => $page->where('contacts.0.version_no', 2)->where('contacts.0.phone', '222'));
+ }
+
+ public function test_lead_and_task_edits_are_versioned_without_bypassing_the_next_action_rule(): void
+ {
+ $lead = Lead::create(['investor_id' => $this->investor->id, 'owner_user_id' => $this->first->id, 'title' => 'SYNTHETIC lead', 'status' => 'new'])->fresh();
+ $task = CrmTask::create(['lead_id' => $lead->id, 'title' => 'SYNTHETIC next action', 'status' => 'open', 'due_at' => now()->addDay(), 'assignee_user_id' => $this->first->id])->fresh();
+ $taskUrl = '/management/crm/leads/'.$lead->id.'/tasks/'.$task->id;
+ $this->patchJson($taskUrl, ['version' => 1, 'status' => 'done'])->assertUnprocessable()->assertJsonValidationErrors('status');
+ $this->patchJson($taskUrl, ['version' => 1, 'status' => 'in_progress'])->assertRedirect();
+ CrmTask::create(['lead_id' => $lead->id, 'title' => 'SYNTHETIC alternative next action', 'status' => 'open', 'due_at' => now()->addDays(2), 'assignee_user_id' => $this->first->id]);
+ $this->patchJson($taskUrl, ['version' => 1, 'status' => 'done'])->assertUnprocessable()->assertJsonValidationErrors('version');
+ $data = ['version' => 1, 'owner_user_id' => $this->first->id, 'status' => 'qualified', 'qualification_reason' => 'SYNTHETIC qualified after internal review'];
+ $this->patchJson('/management/crm/leads/'.$lead->id, $data)->assertRedirect();
+ $this->actingAsWithMfa($this->second)->patchJson('/management/crm/leads/'.$lead->id, [...$data, 'status' => 'disqualified', 'qualification_reason' => 'SYNTHETIC stale qualification'])->assertUnprocessable()->assertJsonValidationErrors('version');
+ $this->assertDatabaseHas('leads', ['id' => $lead->id, 'status' => 'qualified', 'version_no' => 2]);
+ $this->assertDatabaseHas('tasks', ['id' => $task->id, 'status' => 'in_progress', 'version_no' => 2]);
+ }
+
+ public function test_missing_version_is_an_explicit_validation_error_and_does_not_change_the_record(): void
+ {
+ $data = $this->investorData();
+ unset($data['version']);
+ $this->patchJson('/management/crm/investors/'.$this->investor->id, $data)->assertUnprocessable()->assertJsonValidationErrors('version')->assertJsonPath('errors.version.0', 'Actualize os dados para recuperar a versão deste registo antes de gravar. As suas edições foram conservadas.');
+ $this->assertDatabaseHas('investors', ['id' => $this->investor->id, 'legal_name' => 'SYNTHETIC original investor', 'version_no' => 1]);
+ }
+
+ public function test_noop_does_not_create_another_revision_or_audit_and_metadata_cannot_be_reset_by_input(): void
+ {
+ $before = $this->investor->getAttributes();
+ $url = '/management/crm/investors/'.$this->investor->id;
+ $this->patchJson($url, ['version' => 1, 'legal_name' => $this->investor->legal_name, 'investor_type' => 'domestic', 'status' => 'prospect'])->assertRedirect();
+ $this->assertSame($before, $this->investor->fresh()->getAttributes());
+ $this->assertSame(0, DB::table('audit_events')->where('entity_id', $this->investor->id)->count());
+ $this->patchJson($url, [...$this->investorData(), 'version_no' => 0])->assertRedirect();
+ $this->assertSame(2, $this->investor->fresh()->version_no);
+ }
+
+ public function test_other_existing_crm_writers_advance_the_revision_without_changing_their_authority(): void
+ {
+ PortalAudit::save($this->investor, ['status' => 'active'], $this->first->id);
+ $this->assertSame(2, $this->investor->fresh()->version_no);
+ $this->patchJson('/management/crm/investors/'.$this->investor->id, $this->investorData())->assertUnprocessable()->assertJsonValidationErrors('version');
+ }
+
+ public function test_document_edition_is_not_incremented_by_the_crm_revision_policy(): void
+ {
+ $id = (string) Str::uuid();
+ DB::table('documents')->insert(['id' => $id, 'version_no' => 7, 'source_system' => 'synthetic', 'file_name' => 'synthetic-source.txt', 'media_type' => 'text/plain', 'storage_key' => 'synthetic-no-binary-required/'.$id, 'sha256' => str_repeat('a', 64), 'status' => 'quarantined']);
+ $document = new class extends Model
+ {
+ protected $table = 'documents';
+
+ protected $guarded = [];
+
+ public $incrementing = false;
+
+ protected $keyType = 'string';
+ };
+ $document = $document->newQuery()->findOrFail($id);
+ PortalAudit::save($document, ['file_name' => 'synthetic-renamed.txt'], $this->first->id);
+ $this->assertDatabaseHas('documents', ['id' => $id, 'version_no' => 7, 'file_name' => 'synthetic-renamed.txt']);
+ }
+
+ public function test_a_valid_revision_does_not_grant_manager_authority(): void
+ {
+ $this->actingAs(User::factory()->create())->patchJson('/management/crm/investors/'.$this->investor->id, $this->investorData())->assertForbidden();
+ $this->assertDatabaseHas('investors', ['id' => $this->investor->id, 'version_no' => 1]);
+ $this->actingAs($this->second)->patchJson('/management/crm/investors/'.$this->investor->id, $this->investorData())->assertRedirect();
+ $this->assertDatabaseHas('investors', ['id' => $this->investor->id, 'version_no' => 2, 'legal_name' => 'SYNTHETIC first edit']);
+ }
+}
diff --git a/tests/Feature/CrmTaskCreationTest.php b/tests/Feature/CrmTaskCreationTest.php
new file mode 100644
index 00000000..2b12e25c
--- /dev/null
+++ b/tests/Feature/CrmTaskCreationTest.php
@@ -0,0 +1,168 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->lead = Lead::create(['title' => 'SYNTHETIC task creation lead', 'status' => 'new', 'owner_user_id' => $this->manager->id])->fresh();
+ $this->actingAsWithMfa($this->manager);
+ }
+
+ private function url(): string
+ {
+ return '/management/crm/leads/'.$this->lead->id.'/tasks';
+ }
+
+ /** @return array{client_key:string,title:string,due_at:string,assignee_user_id:int} */
+ private function command(): array
+ {
+ return ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC next action', 'due_at' => now()->addDay()->toIso8601String(), 'assignee_user_id' => $this->manager->id];
+ }
+
+ public function test_repeating_the_same_creation_does_not_create_a_second_task(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ }
+
+ public function test_retry_uses_the_original_receipt_after_deadline_expiry_and_assignee_retirement(): void
+ {
+ $other = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email, $other->email]]);
+ $command = [...$this->command(), 'assignee_user_id' => $other->id];
+ $this->post($this->url(), $command)->assertRedirect();
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ config(['portal.managers' => [$this->manager->email]]);
+ $this->travel(2)->days();
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ }
+
+ public function test_a_used_key_cannot_create_a_modified_task(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ $this->postJson($this->url(), [...$command, 'title' => 'SYNTHETIC changed'])->assertConflict();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ }
+
+ public function test_validation_does_not_consume_the_key_or_write_a_task(): void
+ {
+ $command = $this->command();
+ $this->postJson($this->url(), [...$command, 'due_at' => now()->subDay()->toIso8601String(), 'assignee_user_id' => 999999])->assertUnprocessable()->assertJsonValidationErrors(['due_at', 'assignee_user_id']);
+ $this->assertDatabaseCount('tasks', 0);
+ $this->assertDatabaseCount('audit_events', 0);
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ }
+
+ public function test_equivalent_offsets_and_whitespace_replay_the_same_canonical_values(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->post($this->url(), [...$command, 'client_key' => strtoupper($command['client_key']), 'title' => ' '.$command['title'].' ', 'due_at' => CarbonImmutable::parse($command['due_at'])->setTimezone('Africa/Maputo')->toIso8601String()])->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ }
+
+ public function test_receipts_are_scoped_to_the_current_actor_and_lead_without_raw_audit_payloads(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $other = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email, $other->email]]);
+ $this->actingAsWithMfa($other);
+ $this->post($this->url(), $command)->assertRedirect();
+ $secondLead = Lead::create(['title' => 'SYNTHETIC second', 'status' => 'new']);
+ app(CrmTaskCreation::class)->create($other, $secondLead, $command, [$this->manager->id]);
+ $this->assertDatabaseCount('tasks', 3);
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (Assert $page) => $page->component('crm/lead')
+ ->where('taskCreation.actor_id', $other->id)->where('taskCreation.lead_id', $this->lead->id)
+ ->has('taskCreation.commands', 1)->where('taskCreation.commands.0.key', $command['client_key'])
+ ->missing('taskCreation.commands.0.hash')->missing('taskCreation.commands.0.title')->missing('taskCreation.commands.0.after_data'));
+ }
+
+ public function test_replay_requires_current_management_authority_even_when_the_creation_was_accepted(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ config(['portal.managers' => []]);
+ $this->postJson($this->url(), $command)->assertForbidden();
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertForbidden();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ }
+
+ public function test_completed_and_deleted_tasks_are_not_restored_by_replay(): void
+ {
+ $command = $this->command();
+ $this->post($this->url(), $command)->assertRedirect();
+ $task = CrmTask::firstOrFail();
+ $task->update(['status' => 'done', 'version_no' => 2]);
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertSame('done', $task->fresh()->status);
+ $task->delete();
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSoftDeleted($task);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertInertia(fn (Assert $page) => $page->has('lead.tasks', 0)->has('taskCreation.commands', 1));
+ }
+
+ public function test_legacy_callers_without_a_key_keep_the_existing_creation_contract(): void
+ {
+ $command = $this->command();
+ unset($command['client_key']);
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->post($this->url(), $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 2);
+ $this->assertSame(0, DB::table('audit_events')->where('source_system', 'portal-crm-task-creation')->count());
+ }
+
+ public function test_malformed_keys_and_unapproved_assignees_are_rejected_without_writes(): void
+ {
+ $command = $this->command();
+ $this->postJson($this->url(), [...$command, 'client_key' => 'invalid'])->assertUnprocessable()->assertJsonValidationErrors('client_key');
+ $unapproved = User::factory()->create();
+ $this->postJson($this->url(), [...$command, 'assignee_user_id' => $unapproved->id])->assertUnprocessable()->assertJsonValidationErrors('assignee_user_id');
+ $this->assertDatabaseCount('tasks', 0);
+ $this->assertDatabaseCount('audit_events', 0);
+ }
+}
diff --git a/tests/Feature/CrmTaskPreparationTest.php b/tests/Feature/CrmTaskPreparationTest.php
new file mode 100644
index 00000000..e0487ee6
--- /dev/null
+++ b/tests/Feature/CrmTaskPreparationTest.php
@@ -0,0 +1,232 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->lead = Lead::create(['title' => 'SYNTHETIC preparation lead', 'status' => 'new', 'owner_user_id' => $this->manager->id])->fresh();
+ $this->actingAsWithMfa($this->manager);
+ }
+
+ private function url(): string
+ {
+ return '/management/crm/leads/'.$this->lead->id.'/task-preparation';
+ }
+
+ /** @return array */
+ private function input(): array
+ {
+ return ['version' => 0, 'operation_key' => (string) Str::uuid(), 'snapshot' => [
+ 'values' => ['title' => 'SYNTHETIC partial task', 'due_at' => '', 'assignee_user_id' => ''],
+ 'generation' => ['title' => 1, 'due_at' => 0, 'assignee_user_id' => 0], 'pending' => null,
+ ]];
+ }
+
+ public function test_partial_preparation_is_encrypted_and_recoverable_without_creating_a_task(): void
+ {
+ $input = $this->input();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('preparation.version', 1)->assertJsonPath('preparation.snapshot', $input['snapshot']);
+ $stored = DB::table('crm_task_preparations')->first();
+ $this->assertStringNotContainsString('SYNTHETIC partial task', $stored->snapshot);
+ $this->assertSame($input['snapshot'], json_decode(Crypt::decryptString($stored->snapshot), true));
+ $this->assertDatabaseCount('tasks', 0);
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-crm-task-preparation')->count());
+ $this->assertSame($input['snapshot'], app(CrmTaskPreparations::class)->view($this->manager, $this->lead)['snapshot']);
+ }
+
+ public function test_repeated_checkpoint_is_read_only_and_changed_payload_with_same_key_conflicts(): void
+ {
+ $input = $this->input();
+ $this->postJson($this->url(), $input)->assertOk();
+ $audit = DB::table('audit_events')->where('source_system', 'portal-crm-task-preparation')->count();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('preparation.version', 1);
+ $this->assertSame($audit, DB::table('audit_events')->where('source_system', 'portal-crm-task-preparation')->count());
+ $input['snapshot']['values']['title'] = 'SYNTHETIC changed';
+ $this->postJson($this->url(), $input)->assertConflict();
+ $this->assertDatabaseCount('crm_task_preparations', 1);
+ $this->assertSame(1, DB::table('crm_task_preparations')->value('version'));
+ }
+
+ public function test_another_tab_cannot_overwrite_a_newer_preparation_with_a_stale_version(): void
+ {
+ $input = $this->input();
+ $this->postJson($this->url(), $input)->assertOk();
+ $other = $this->input();
+ $other['snapshot']['values']['title'] = 'SYNTHETIC competing';
+ $this->postJson($this->url(), $other)->assertConflict();
+ $this->assertSame($input['snapshot'], app(CrmTaskPreparations::class)->view($this->manager, $this->lead)['snapshot']);
+ $other['version'] = 1;
+ $this->postJson($this->url(), $other)->assertOk()->assertJsonPath('preparation.version', 2);
+ $this->assertSame($other['snapshot'], app(CrmTaskPreparations::class)->view($this->manager, $this->lead)['snapshot']);
+ }
+
+ public function test_partial_text_and_empty_fields_survive_framework_normalisation(): void
+ {
+ $input = $this->input();
+ $input['snapshot']['values']['title'] = " SYNTHETIC\npartial ";
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('preparation.snapshot', $input['snapshot']);
+ $this->assertDatabaseCount('tasks', 0);
+ }
+
+ public function test_a_frozen_attempt_and_later_edits_survive_a_new_authenticated_session(): void
+ {
+ $input = $this->input();
+ $input['snapshot']['pending'] = ['values' => ['title' => 'SYNTHETIC original', 'due_at' => now()->addDay()->toIso8601String(), 'assignee_user_id' => (string) $this->manager->id, 'client_key' => (string) Str::uuid()],
+ 'generation' => ['title' => 1, 'due_at' => 1, 'assignee_user_id' => 0]];
+ $input['snapshot']['values']['title'] = 'SYNTHETIC later';
+ $input['snapshot']['generation']['title'] = 2;
+ $this->postJson($this->url(), $input)->assertOk();
+ $this->flushSession();
+ $this->actingAsWithMfa($this->manager->fresh());
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (AssertableInertia $page) => $page->where('taskCreation.preparation.snapshot', $input['snapshot']));
+ $this->assertDatabaseCount('tasks', 0);
+ }
+
+ public function test_preparations_are_private_to_the_current_actor_and_lead(): void
+ {
+ $input = $this->input();
+ $this->postJson($this->url(), $input)->assertOk();
+ $other = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email, $other->email]]);
+ $this->actingAsWithMfa($other);
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (AssertableInertia $page) => $page->where('taskCreation.actor_id', $other->id)->where('taskCreation.preparation.snapshot', null));
+ $this->postJson($this->url(), $this->input())->assertOk();
+ $second = Lead::create(['title' => 'SYNTHETIC another lead', 'status' => 'new']);
+ $this->assertNull(app(CrmTaskPreparations::class)->view($other, $second)['snapshot']);
+ $this->assertDatabaseCount('crm_task_preparations', 2);
+ }
+
+ public function test_current_management_authority_is_required_to_read_and_write_preparation(): void
+ {
+ $this->postJson($this->url(), $this->input())->assertOk();
+ $stored = DB::table('crm_task_preparations')->value('snapshot');
+ config(['portal.managers' => []]);
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertForbidden();
+ $this->postJson($this->url(), $this->input())->assertForbidden();
+ $this->assertSame($stored, DB::table('crm_task_preparations')->value('snapshot'));
+ }
+
+ public function test_unknown_fields_invalid_nonce_and_generation_are_not_persisted(): void
+ {
+ $input = $this->input();
+ $input['snapshot']['values']['private_extra'] = 'SYNTHETIC unwanted';
+ $this->postJson($this->url(), $input)->assertUnprocessable();
+ $input = $this->input();
+ $input['operation_key'] = 'not-a-uuid';
+ $this->postJson($this->url(), $input)->assertUnprocessable();
+ $input = $this->input();
+ $input['snapshot']['generation']['title'] = -1;
+ $this->postJson($this->url(), $input)->assertUnprocessable();
+ $this->assertDatabaseCount('crm_task_preparations', 0);
+ $this->assertDatabaseCount('tasks', 0);
+ }
+
+ public function test_unreadable_ciphertext_is_preserved_and_does_not_prevent_the_manual_task_path(): void
+ {
+ $this->postJson($this->url(), $this->input())->assertOk();
+ DB::table('crm_task_preparations')->update(['snapshot' => 'SYNTHETIC unreadable ciphertext']);
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (AssertableInertia $page) => $page->where('taskCreation.preparation.unavailable', true)->where('taskCreation.preparation.snapshot', null));
+ $input = $this->input();
+ $input['version'] = 1;
+ $this->postJson($this->url(), $input)->assertConflict();
+ $this->assertSame('SYNTHETIC unreadable ciphertext', DB::table('crm_task_preparations')->value('snapshot'));
+ $this->post('/management/crm/leads/'.$this->lead->id.'/tasks', ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC manual', 'due_at' => now()->addDay()->toIso8601String(), 'assignee_user_id' => $this->manager->id])->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ }
+
+ public function test_uninstalled_preparation_preserves_the_existing_manual_creation_contract(): void
+ {
+ Schema::rename('crm_task_preparations', 'crm_task_preparations_not_installed');
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (AssertableInertia $page) => $page->where('taskCreation.preparation.installed', false));
+ $this->postJson($this->url(), $this->input())->assertConflict();
+ $this->post('/management/crm/leads/'.$this->lead->id.'/tasks', ['title' => 'SYNTHETIC manual', 'due_at' => now()->addDay()->toIso8601String(), 'assignee_user_id' => $this->manager->id])->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ }
+
+ public function test_audit_metadata_does_not_copy_the_private_preparation(): void
+ {
+ $input = $this->input();
+ $this->postJson($this->url(), $input)->assertOk();
+ $event = DB::table('audit_events')->where('source_system', 'portal-crm-task-preparation')->first();
+ $this->assertSame(['version' => 1], json_decode($event->after_data, true));
+ $this->assertStringNotContainsString('SYNTHETIC partial task', json_encode($event, JSON_THROW_ON_ERROR));
+ }
+
+ public function test_creation_receipt_and_later_preparation_survive_a_new_session_without_duplicate_tasks(): void
+ {
+ $input = $this->input();
+ $before = $this->lead->getAttributes();
+ $command = ['title' => 'SYNTHETIC original task', 'due_at' => now()->addYear()->toIso8601String(), 'assignee_user_id' => (string) $this->manager->id, 'client_key' => (string) Str::uuid()];
+ $input['snapshot']['pending'] = ['values' => $command, 'generation' => ['title' => 1, 'due_at' => 1, 'assignee_user_id' => 0]];
+ $input['snapshot']['values']['title'] = 'SYNTHETIC next draft';
+ $input['snapshot']['generation']['title'] = 2;
+ $this->postJson($this->url(), $input)->assertOk();
+ $taskUrl = '/management/crm/leads/'.$this->lead->id.'/tasks';
+ $this->post($taskUrl, $command)->assertRedirect();
+ $task = DB::table('tasks')->first();
+ $this->flushSession();
+ $this->actingAsWithMfa($this->manager->fresh());
+ $this->get('/management/crm/leads/'.$this->lead->id)->assertOk()->assertInertia(fn (AssertableInertia $page) => $page
+ ->where('taskCreation.preparation.snapshot', $input['snapshot'])->has('taskCreation.commands', 1)
+ ->where('taskCreation.commands.0.key', $command['client_key'])->where('taskCreation.commands.0.task_id', $task->id));
+ $events = DB::table('audit_events')->where('entity_type', 'tasks')->count();
+ $this->post($taskUrl, $command)->assertRedirect();
+ $this->assertDatabaseCount('tasks', 1);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'tasks')->count());
+ $this->assertSame($before, $this->lead->fresh()->getAttributes());
+ }
+
+ public function test_a_changed_access_revision_rejects_the_old_session_without_overwriting_preparation(): void
+ {
+ $this->postJson($this->url(), $this->input())->assertOk();
+ $stored = DB::table('crm_task_preparations')->value('snapshot');
+ DB::table('users')->where('id', $this->manager->id)->increment('portal_access_revision');
+ $input = $this->input();
+ $input['version'] = 1;
+ $this->postJson($this->url(), $input)->assertUnauthorized();
+ $this->assertSame($stored, DB::table('crm_task_preparations')->value('snapshot'));
+ $this->assertDatabaseCount('tasks', 0);
+ }
+
+ public function test_accepted_integer_strings_and_uppercase_attempt_keys_have_a_canonical_json_projection(): void
+ {
+ $input = $this->input();
+ $key = (string) Str::uuid();
+ $input['snapshot']['generation']['title'] = '2';
+ $input['snapshot']['pending'] = ['values' => ['title' => 'SYNTHETIC pending', 'due_at' => now()->addYear()->toIso8601String(), 'assignee_user_id' => (string) $this->manager->id, 'client_key' => strtoupper($key)],
+ 'generation' => ['title' => '1', 'due_at' => 0, 'assignee_user_id' => 0]];
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('preparation.snapshot.generation.title', 2)
+ ->assertJsonPath('preparation.snapshot.pending.generation.title', 1)->assertJsonPath('preparation.snapshot.pending.values.client_key', $key);
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('preparation.version', 1);
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-crm-task-preparation')->count());
+ $this->assertDatabaseCount('tasks', 0);
+ }
+}
diff --git a/tests/Feature/DashboardWorkQueueTest.php b/tests/Feature/DashboardWorkQueueTest.php
new file mode 100644
index 00000000..611b2b81
--- /dev/null
+++ b/tests/Feature/DashboardWorkQueueTest.php
@@ -0,0 +1,275 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->travelTo(now()->setDate(2026, 11, 3)->setTime(10, 0));
+ $this->manager = User::factory()->create();
+ $this->other = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'portal.profile_access_enabled' => true, 'investor-path.enabled' => false, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ }
+
+ private function interest(User $actor, array $changes = []): InterestRequest
+ {
+ return InterestRequest::create(['reference' => 'SYNTHETIC-'.Str::uuid(), 'full_name' => 'SYNTHETIC private contact', 'email' => 'synthetic-private@example.invalid',
+ 'investor_type' => 'empresa', 'message' => 'SYNTHETIC dashboard queue, not an active investor request.', 'country' => 'MZ', 'sector_interest' => 'Agricultura', 'privacy_consent' => true, 'assigned_to' => $actor->id, 'status' => 'received',
+ 'next_action' => 'SYNTHETIC assigned follow-up', 'next_action_due_at' => now()->subHour(), ...$changes]);
+ }
+
+ /** @return array{id:string,case_id:string} */
+ private function deskRequest(User $analyst, array $changes = [], bool $closed = false): array
+ {
+ $desk = app(VirtualDesk::class);
+ $this->edition ??= app(DeskServiceEditor::class)->publish($this->manager, 'project-change', ['base_version' => 0, 'definition' => config('virtual-desk.services.project-change'), 'reason' => 'SYNTHETIC dashboard queue fixture', 'confirm' => true])->id;
+ $case = $desk->createCase($this->other, ['title' => 'SYNTHETIC assigned dossier', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true]);
+ $request = $desk->createRequest($this->other, $case->id, $this->edition, (string) Str::uuid());
+ if (($changes['status'] ?? 'reviewing') !== 'draft') {
+ $desk->save($this->other, $request->id, ['version' => 1, 'payload' => ['title' => 'SYNTHETIC queue project', 'description' => 'SYNTHETIC private preparation', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC internal change'], 'consent' => true], true);
+ }
+ // Queue fixture only: owner close/reopen and submission are exercised by their own accepted HTTP suites.
+ DB::table('desk_requests')->where('id', $request->id)->update(['analyst_id' => $analyst->id, 'status' => 'reviewing', 'due_at' => now()->subHour(), ...$changes]);
+ if ($closed) {
+ DB::table('desk_cases')->where('id', $case->id)->update(['closed_at' => now()]);
+ }
+
+ return ['id' => $request->id, 'case_id' => $case->id];
+ }
+
+ private function task(User $actor, array $changes = []): CrmTask
+ {
+ $lead = Lead::create(['title' => 'SYNTHETIC assigned lead', 'owner_user_id' => $actor->id, 'status' => 'new']);
+
+ return CrmTask::create(['lead_id' => $lead->id, 'title' => 'SYNTHETIC assigned CRM task', 'assignee_user_id' => $actor->id, 'status' => 'open', 'due_at' => now()->subHour(), ...$changes]);
+ }
+
+ private function queue(string $url = '/dashboard'): ?array
+ {
+ return $this->get($url)->assertOk()->viewData('page')['props']['workQueue'];
+ }
+
+ public function test_public_investor_guest_and_unverified_actor_do_not_gain_operational_data(): void
+ {
+ $this->interest($this->manager);
+ $this->task($this->manager);
+ $this->actingAs($this->other)->get('/dashboard')->assertInertia(fn ($page) => $page->where('workQueue', null)->where('summary', null));
+ $this->get('/management/crm/leads')->assertForbidden();
+ $unverified = User::factory()->unverified()->create();
+ $this->actingAs($unverified)->get('/dashboard')->assertRedirect('/email/verify');
+ auth()->forgetGuards();
+ $this->flushSession();
+ $this->get('/dashboard')->assertRedirect('/login');
+ }
+
+ public function test_assigned_interest_operator_sees_only_active_personal_records_and_real_destination(): void
+ {
+ $operator = User::factory()->create();
+ $first = $this->interest($operator);
+ $this->interest($operator, ['next_action_due_at' => now()->addDay()]);
+ $this->interest($operator, ['next_action_due_at' => null, 'next_action' => null]);
+ $other = $this->interest($this->other);
+ foreach (['closed', 'cancelled', 'refused', 'converted'] as $status) {
+ $this->interest($operator, ['status' => $status]);
+ }
+ $this->interest($operator)->delete();
+ $this->actingAsWithMfa($operator);
+ $queue = $this->queue();
+ $this->assertSame(['interests'], array_keys($queue['groups']));
+ $group = $queue['groups']['interests'];
+ $this->assertSame(3, $group['total']);
+ $this->assertSame(1, $group['overdue']);
+ $this->assertSame((string) $first->id, $group['items'][0]['id']);
+ $this->assertNull($group['items'][2]['due_at']);
+ $this->assertSame('Acompanhar manifestação', $group['items'][2]['title']);
+ $this->get($group['items'][0]['href'])->assertOk();
+ $this->get('/management/interests/'.$other->id)->assertForbidden();
+ $this->assertStringNotContainsString('synthetic-private@example.invalid', json_encode($queue));
+ }
+
+ public function test_personal_groups_are_separate_and_dashboard_does_not_mutate_workflow_or_audit(): void
+ {
+ $interest = $this->interest($this->manager);
+ $request = $this->deskRequest($this->manager);
+ $task = $this->task($this->manager);
+ $this->interest($this->other);
+ $this->deskRequest($this->other);
+ $this->task($this->other);
+ $this->actingAsWithMfa($this->manager);
+ $before = [DB::table('audit_events')->count(), DB::table('desk_events')->count(), DB::table('desk_notifications')->count(), $interest->fresh()->getAttributes(), $task->fresh()->getAttributes(), (array) DB::table('desk_requests')->find($request['id'])];
+ $queue = $this->queue();
+ foreach (['interests', 'desk', 'crm_tasks'] as $kind) {
+ $this->assertSame(1, $queue['groups'][$kind]['total']);
+ $this->assertSame(1, $queue['groups'][$kind]['overdue']);
+ }
+ $after = [DB::table('audit_events')->count(), DB::table('desk_events')->count(), DB::table('desk_notifications')->count(), $interest->fresh()->getAttributes(), $task->fresh()->getAttributes(), (array) DB::table('desk_requests')->find($request['id'])];
+ $this->assertSame($before, $after);
+ $this->getJson($queue['groups']['desk']['items'][0]['href'])->assertOk()->assertJsonPath('request.id', $request['id']);
+ $href = $queue['groups']['crm_tasks']['items'][0]['href'];
+ $this->assertStringEndsWith('#crm-task-'.$task->id, $href);
+ $this->get(strtok($href, '#'))->assertOk()->assertInertia(fn ($page) => $page->where('lead.id', $task->lead_id));
+ }
+
+ public function test_closed_dossiers_and_finished_deleted_or_unassigned_records_leave_the_active_queue(): void
+ {
+ $closed = $this->deskRequest($this->manager);
+ $this->task($this->manager, ['desk_case_id' => $closed['case_id'], 'accepted_by' => $this->other->id, 'accepted_at' => now(), 'guidance_key' => 'SYNTHETIC-dashboard', 'data_classification' => 'confidential', 'external_sync_status' => 'pending_authorization']);
+ DB::table('desk_cases')->where('id', $closed['case_id'])->update(['closed_at' => now()]);
+ foreach (['draft', 'closed', 'cancelled'] as $status) {
+ $this->deskRequest($this->manager, ['status' => $status]);
+ }
+ $this->deskRequest($this->manager, ['analyst_id' => null]);
+ foreach (['done', 'cancelled'] as $status) {
+ $this->task($this->manager, ['status' => $status]);
+ }
+ $this->task($this->manager)->delete();
+ $deletedLead = $this->task($this->manager);
+ Lead::findOrFail($deletedLead->lead_id)->delete();
+ $active = $this->task($this->manager, ['due_at' => null]);
+ $this->actingAsWithMfa($this->manager);
+ $queue = $this->queue();
+ $this->assertSame(0, $queue['groups']['desk']['total']);
+ $this->assertSame(1, $queue['groups']['crm_tasks']['total']);
+ $this->assertSame(0, $queue['groups']['crm_tasks']['overdue']);
+ $this->assertSame($active->id, $queue['groups']['crm_tasks']['items'][0]['id']);
+ $this->assertDatabaseHas('desk_requests', ['id' => $closed['id'], 'status' => 'reviewing']);
+ }
+
+ public function test_assigned_desk_consultation_does_not_require_unrelated_management_privileges_and_revocation_is_immediate(): void
+ {
+ $analyst = User::factory()->create();
+ $request = $this->deskRequest($analyst);
+ $this->interest($analyst); // No confirmed MFA: detail authority for interests is still required.
+ $this->actingAs($analyst);
+ $queue = $this->queue();
+ $this->assertSame(['desk'], array_keys($queue['groups']));
+ $this->getJson($queue['groups']['desk']['items'][0]['href'])->assertOk();
+ DB::table('desk_requests')->where('id', $request['id'])->update(['analyst_id' => $this->manager->id]);
+ $this->assertNull($this->queue());
+ $this->getJson('/balcao-virtual/pedidos/'.$request['id'])->assertForbidden();
+ }
+
+ public function test_independent_pagination_covers_every_row_once_and_uses_full_group_totals(): void
+ {
+ for ($i = 0; $i < 13; $i++) {
+ $this->interest($this->manager);
+ }
+ for ($i = 0; $i < 6; $i++) {
+ $this->deskRequest($this->manager);
+ $this->task($this->manager);
+ }
+ $this->actingAsWithMfa($this->manager);
+ $queue = $this->queue('/dashboard?desk_page=2&crm_tasks_page=2');
+ $ids = [];
+ for ($page = 1; $page <= 3; $page++) {
+ $group = $queue['groups']['interests'];
+ $this->assertSame($page, $group['page']);
+ $this->assertSame(13, $group['total']);
+ $this->assertSame(13, $group['overdue']);
+ $ids = [...$ids, ...array_column($group['items'], 'id')];
+ $this->assertSame(2, $queue['groups']['desk']['page']);
+ $this->assertSame(2, $queue['groups']['crm_tasks']['page']);
+ if ($group['next']) {
+ $queue = $this->queue($group['next']);
+ }
+ }
+ $this->assertCount(13, array_unique($ids));
+ $this->assertNull($group['next']);
+ $this->assertSame($ids, array_map('strval', InterestRequest::orderBy('id')->pluck('id')->all()));
+ $this->assertSame(1, count($queue['groups']['desk']['items']));
+ }
+
+ public function test_assignment_changes_recover_stale_pages_and_deadline_equal_to_now_is_not_overdue(): void
+ {
+ $this->interest($this->manager, ['next_action_due_at' => now()]);
+ $this->actingAsWithMfa($this->manager);
+ $queue = $this->queue('/dashboard?interests_page=99');
+ $this->assertSame(1, $queue['groups']['interests']['page']);
+ $this->assertSame(0, $queue['groups']['interests']['overdue']);
+ $this->assertFalse($queue['groups']['interests']['items'][0]['overdue']);
+ InterestRequest::query()->update(['assigned_to' => $this->other->id]);
+ $queue = $this->queue('/dashboard?interests_page=99');
+ $this->assertSame(0, $queue['groups']['interests']['total']);
+ $this->assertSame(1, $queue['groups']['interests']['page']);
+ }
+
+ public function test_mfa_expiration_auditor_restriction_and_removed_manager_are_not_bypassed(): void
+ {
+ $operator = User::factory()->create();
+ $this->interest($operator);
+ $this->actingAsWithMfa($operator);
+ $this->assertNotNull($this->queue());
+ $this->withSession(['portal.mfa_at' => time() - 901]);
+ $this->assertNull($this->queue());
+ $this->interest($this->manager);
+ $this->task($this->manager);
+ $this->actingAsWithMfa($this->manager);
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->other, ['user_id' => $this->manager->id, 'role' => 'auditor', 'opportunity_types' => [], 'responsibilities' => []]);
+ $this->get('/dashboard')->assertInertia(fn ($page) => $page->where('workQueue', null)->where('summary', null));
+ $this->get('/management/crm/leads')->assertForbidden();
+ config(['portal.managers' => []]);
+ $this->get('/dashboard')->assertInertia(fn ($page) => $page->where('summary', null)->where('workQueue', null));
+ }
+
+ public function test_unlinked_crm_still_works_when_the_optional_desk_is_unavailable(): void
+ {
+ $this->task($this->manager);
+ $this->actingAs($this->manager);
+ DB::statement('ALTER TABLE desk_cases RENAME TO desk_cases_qa_unavailable');
+ try {
+ $queue = $this->queue();
+ $this->assertArrayNotHasKey('desk', $queue['groups']);
+ $this->assertSame(1, $queue['groups']['crm_tasks']['total']);
+ $this->get(strtok($queue['groups']['crm_tasks']['items'][0]['href'], '#'))->assertOk();
+ } finally {
+ DB::statement('ALTER TABLE desk_cases_qa_unavailable RENAME TO desk_cases');
+ }
+ }
+
+ public function test_removing_manager_configuration_removes_crm_queue_and_dashboard_summary_independently_of_auditor_status(): void
+ {
+ $this->task($this->manager);
+ $this->actingAs($this->manager);
+ $this->assertSame(1, $this->queue()['groups']['crm_tasks']['total']);
+ config(['portal.managers' => []]);
+ $this->get('/dashboard')->assertInertia(fn ($page) => $page->where('summary', null)->where('workQueue', null));
+ $this->get('/management/crm/leads')->assertForbidden();
+ Http::assertNothingSent();
+ Mail::assertNothingSent();
+ }
+
+ public function test_invalid_pagination_is_rejected_without_querying_an_arbitrary_scope(): void
+ {
+ $this->actingAs($this->manager)->getJson('/dashboard?desk_page=-1')->assertUnprocessable()->assertJsonValidationErrors('desk_page');
+ $this->getJson('/dashboard?crm_tasks_page=other')->assertUnprocessable()->assertJsonValidationErrors('crm_tasks_page');
+ }
+}
diff --git a/tests/Feature/DeskAttachmentFieldsTest.php b/tests/Feature/DeskAttachmentFieldsTest.php
new file mode 100644
index 00000000..7202c20d
--- /dev/null
+++ b/tests/Feature/DeskAttachmentFieldsTest.php
@@ -0,0 +1,409 @@
+withoutVite();
+ Storage::fake('local');
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email]]);
+ $this->edition = $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', $this->publication())->assertCreated()->json('id');
+ $this->caseId = $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC attachments', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->id = $this->newRequest();
+ }
+
+ private function publication(int $base = 0): array
+ {
+ $definition = config('virtual-desk.services.project-change');
+ $definition['fields'] = [...$definition['fields'],
+ 'branch' => ['label' => 'SYNTHETIC branch', 'type' => 'select', 'required' => false, 'options' => ['yes' => 'Yes', 'no' => 'No']],
+ 'support' => ['label' => 'SYNTHETIC required support', 'type' => 'attachment', 'required' => true, 'mime_types' => ['text/plain'], 'max_size_kb' => 2, 'max_files' => 2, 'when' => ['field' => 'branch', 'equals' => 'yes']],
+ 'optional_support' => ['label' => 'SYNTHETIC optional support', 'type' => 'attachment', 'required' => false, 'mime_types' => ['text/plain'], 'max_size_kb' => 2, 'max_files' => 1],
+ ];
+
+ return ['base_version' => $base, 'definition' => $definition, 'confirm' => true, 'reason' => 'SYNTHETIC attachment field QA, not an actual publication.'];
+ }
+
+ private function newRequest(): string
+ {
+ return $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/pedidos', ['service_version_id' => $this->edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function answers(array $support = []): array
+ {
+ return ['title' => 'SYNTHETIC submission', 'description' => 'SYNTHETIC complete private description', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC change', 'branch' => 'yes', 'support' => $support];
+ }
+
+ private function upload(string $bytes = 'SYNTHETIC original bytes', ?string $requestId = null, ?string $field = 'support'): array
+ {
+ return $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => DB::table('desk_cases')->where('id', $this->caseId)->value('version'), 'request_id' => $requestId ?? $this->id, 'field_key' => $field,
+ 'file' => UploadedFile::fake()->createWithContent('synthetic-proof.txt', $bytes), 'source_reference' => 'SYNTHETIC source only', 'category' => 'SYNTHETIC evidence', 'consent' => true], ['Accept' => 'application/json'])->assertOk()->json();
+ }
+
+ private function clean(string $link): \stdClass
+ {
+ $id = DB::table('desk_documents')->where('id', $link)->value('document_id');
+ $document = DB::table('documents')->where('id', $id)->first();
+ DB::table('documents')->where('id', $id)->update(['status' => 'active', 'malware_scan_status' => 'clean', 'malware_scanned_sha256' => trim($document->sha256)]);
+
+ return DB::table('documents')->where('id', $id)->first();
+ }
+
+ private function save(array $payload, int $version = 1, bool $submit = true): TestResponse
+ {
+ return $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => $version, 'payload' => $payload, 'submit' => $submit, 'consent' => $submit]);
+ }
+
+ public function test_required_attachment_pending_scan_draft_and_checkpoint_are_preserved_but_submission_requires_a_usable_original(): void
+ {
+ $this->save($this->answers())->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $uploaded = $this->upload();
+ $link = $uploaded['link_id'];
+ $payload = $this->answers([$link]);
+ $this->assertCount(1, $uploaded['documents']);
+ $this->assertSame(2, $uploaded['case_version']);
+ $this->save($payload, 1, false)->assertOk();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->id.'/rascunho', ['version' => 0, 'request_version' => 2, 'operation_key' => (string) Str::uuid(), 'payload' => $payload, 'edited_keys' => []])->assertOk();
+ $this->save($payload, 2)->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $document = $this->clean($link);
+ $this->save($payload, 2)->assertOk()->assertJsonPath('status', 'submitted');
+ $snapshot = app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $this->id)->value('submitted_snapshot'));
+ $this->assertTrue($snapshot['field_attachments']['support']['applicable']);
+ $this->assertTrue($snapshot['field_attachments']['support']['files'][0]['usable_at_submission']);
+ $this->assertSame(trim($document->sha256), $snapshot['field_attachments']['support']['files'][0]['sha256']);
+ $this->assertSame($this->edition, $snapshot['field_attachments']['support']['service_version_id']);
+ $this->get('/balcao-virtual/pedidos/'.$this->id.'/recibo?format=html')->assertOk()->assertSee('synthetic-proof.txt')->assertSee('Limites desta versão: 2 KB');
+ $this->actingAs(User::factory()->create())->get('/balcao-virtual/pedidos/'.$this->id.'/recibo?format=html')->assertForbidden();
+ }
+
+ public function test_uploaded_and_reused_files_must_fit_the_pinned_field_limits(): void
+ {
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'request_id' => $this->id, 'field_key' => 'support', 'file' => UploadedFile::fake()->createWithContent('oversized.txt', str_repeat('SYNTHETIC ', 400)), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertUnprocessable()->assertJsonValidationErrors('file');
+ $png = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=');
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'request_id' => $this->id, 'field_key' => 'support', 'file' => UploadedFile::fake()->createWithContent('synthetic.png', $png), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertUnprocessable()->assertJsonValidationErrors('file');
+ $this->assertDatabaseCount('documents', 0);
+ $this->assertSame([], Storage::disk('local')->allFiles());
+ $upload = $this->upload(str_repeat('SYNTHETIC ', 400), null, null);
+ $docId = $upload['documents'][0]['document_id'];
+ $this->save($this->answers([$upload['link_id']]), 1, false)->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'request_id' => $this->id, 'field_key' => 'support', 'document_id' => $docId, 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors('document_id');
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 1);
+ }
+
+ public function test_selection_rejects_scalar_duplicate_unknown_and_excessive_references(): void
+ {
+ $one = $this->upload('SYNTHETIC one')['link_id'];
+ $two = $this->upload('SYNTHETIC two')['link_id'];
+ $three = $this->upload('SYNTHETIC three')['link_id'];
+ foreach ([$one, [$one, $one], [(string) Str::uuid()], [$one, $two, $three]] as $invalid) {
+ $this->save([...$this->answers(), 'support' => $invalid], 1, false)->assertUnprocessable();
+ }
+ $this->clean($one);
+ $this->clean($two);
+ $this->save($this->answers([$two, $one]))->assertOk();
+ $before = DB::table('desk_requests')->where('id', $this->id)->first();
+ $this->save($this->answers([$one, $two]))->assertOk();
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $this->id)->first());
+ }
+
+ public function test_same_binary_can_be_linked_to_two_requests_without_copying_or_widening_the_previous_scope(): void
+ {
+ $one = $this->upload();
+ $other = $this->newRequest();
+ $two = $this->upload('SYNTHETIC original bytes', $other);
+ $this->assertNotSame($one['link_id'], $two['link_id']);
+ $this->assertSame($one['documents'][0]['document_id'], $two['documents'][0]['document_id']);
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 2);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ $this->assertDatabaseHas('desk_documents', ['id' => $one['link_id'], 'request_id' => $this->id]);
+ $this->assertDatabaseHas('desk_documents', ['id' => $two['link_id'], 'request_id' => $other]);
+ $this->save($this->answers([$two['link_id']]), 1, false)->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $version = DB::table('desk_cases')->where('id', $this->caseId)->value('version');
+ $repeat = $this->upload();
+ $this->assertSame($one['link_id'], $repeat['link_id']);
+ $this->assertSame($version, $repeat['case_version']);
+ $this->assertDatabaseCount('desk_documents', 2);
+ }
+
+ public function test_authorised_reuse_uses_the_existing_reference_and_keeps_reviewer_access_within_the_new_link_scope(): void
+ {
+ $other = $this->newRequest();
+ $original = $this->upload('SYNTHETIC original bytes', $other);
+ $document = $this->clean($original['link_id']);
+ $response = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => $original['case_version'], 'request_id' => $this->id, 'field_key' => 'support', 'document_id' => $document->id, 'consent' => true])->assertOk();
+ $link = $response->json('link_id');
+ $this->assertNotSame($original['link_id'], $link);
+ $this->assertDatabaseHas('desk_documents', ['id' => $link, 'source_reference' => 'SYNTHETIC source only', 'request_id' => $this->id]);
+ $analyst = User::factory()->create();
+ DB::table('desk_requests')->where('id', $this->id)->update(['analyst_id' => $analyst->id]);
+ $this->actingAs($analyst)->getJson('/balcao-virtual/pedidos/'.$this->id)->assertOk()->assertJsonCount(1, 'documents')->assertJsonCount(0, 'reusableDocuments');
+ $this->get('/balcao-virtual/dossiers/'.$this->caseId.'/documentos/'.$link)->assertOk();
+ $this->get('/balcao-virtual/dossiers/'.$this->caseId.'/documentos/'.$original['link_id'])->assertForbidden();
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => $response->json('case_version'), 'request_id' => $this->id, 'field_key' => 'support', 'document_id' => $document->id, 'consent' => true])->assertForbidden();
+ }
+
+ public function test_global_support_is_reused_by_multiple_questions_without_new_upload_or_source_entry(): void
+ {
+ $global = $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'category' => 'SYNTHETIC global', 'file' => UploadedFile::fake()->createWithContent('synthetic-global.txt', 'SYNTHETIC shared bytes'), 'source_reference' => 'SYNTHETIC shared source', 'consent' => true], ['Accept' => 'application/json'])->assertOk()->json();
+ $this->clean($global['link_id']);
+ $this->save([...$this->answers([$global['link_id']]), 'optional_support' => [$global['link_id']]])->assertOk();
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 1);
+ $snapshot = app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $this->id)->value('submitted_snapshot'));
+ $this->assertSame($snapshot['field_attachments']['support']['files'], $snapshot['field_attachments']['optional_support']['files']);
+ }
+
+ public function test_inactive_answers_are_preserved_without_becoming_required_or_claiming_applicable_evidence(): void
+ {
+ $unavailable = $this->upload(str_repeat('SYNTHETIC ', 400), null, null)['link_id'];
+ $this->save([...$this->answers([$unavailable]), 'branch' => 'no'])->assertOk();
+ $snapshot = app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $this->id)->value('submitted_snapshot'));
+ $this->assertFalse($snapshot['field_attachments']['support']['applicable']);
+ $this->assertFalse($snapshot['field_attachments']['support']['files'][0]['usable_at_submission']);
+ $this->get('/balcao-virtual/pedidos/'.$this->id.'/recibo?format=html')->assertOk()->assertSee('Resposta conservada de pergunta não aplicável');
+ }
+
+ public function test_tampered_missing_and_inconsistent_originals_cannot_be_submitted(): void
+ {
+ $link = $this->upload()['link_id'];
+ $document = $this->clean($link);
+ $original = Storage::disk('local')->get($document->storage_key);
+ Storage::disk('local')->put($document->storage_key, 'SYNTHETIC changed bytes');
+ $this->save($this->answers([$link]))->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ Storage::disk('local')->delete($document->storage_key);
+ $this->save($this->answers([$link]))->assertUnprocessable();
+ Storage::disk('local')->put($document->storage_key, $original);
+ DB::table('documents')->where('id', $document->id)->update(['size_bytes' => 1]);
+ $this->save($this->answers([$link]))->assertUnprocessable();
+ $this->assertDatabaseHas('desk_requests', ['id' => $this->id, 'version' => 1, 'submitted_snapshot' => null]);
+ }
+
+ public function test_new_definition_does_not_change_old_limits_answers_or_receipt(): void
+ {
+ $one = $this->upload('SYNTHETIC one')['link_id'];
+ $two = $this->upload('SYNTHETIC two')['link_id'];
+ $this->clean($one);
+ $this->clean($two);
+ $this->save($this->answers([$one, $two]))->assertOk();
+ $before = DB::table('desk_requests')->where('id', $this->id)->first();
+ $input = $this->publication(1);
+ $input['definition']['fields']['support']['max_files'] = 1;
+ $input['definition']['fields']['support']['mime_types'] = ['application/pdf'];
+ $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', $input)->assertCreated();
+ $this->actingAs($this->owner)->getJson('/balcao-virtual/pedidos/'.$this->id)->assertOk()->assertJsonPath('definition.fields.support.max_files', 2)->assertJsonPath('definition.fields.support.mime_types', ['text/plain']);
+ $this->get('/balcao-virtual/pedidos/'.$this->id.'/recibo?format=html')->assertOk()->assertSee('2 ficheiro(s).');
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $this->id)->first());
+ }
+
+ public function test_returned_field_scope_and_closed_or_submitted_state_are_enforced_for_uploads(): void
+ {
+ $link = $this->upload()['link_id'];
+ $this->clean($link);
+ $this->save($this->answers([$link]))->assertOk();
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'request_id' => $this->id, 'field_key' => 'support', 'file' => UploadedFile::fake()->createWithContent('new.txt', 'SYNTHETIC new'), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertConflict();
+ app(VirtualDesk::class)->transition($this->manager, $this->id, ['version' => 2, 'status' => 'returned', 'reason' => 'SYNTHETIC support only', 'editable_fields' => ['support']]);
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'request_id' => $this->id, 'field_key' => 'optional_support', 'file' => UploadedFile::fake()->createWithContent('new.txt', 'SYNTHETIC new'), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertUnprocessable()->assertJsonValidationErrors('field_key');
+ $new = $this->upload('SYNTHETIC replacement')['link_id'];
+ $this->clean($new);
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 3, 'payload' => $this->answers([$new]), 'submit' => true, 'consent' => true, 'reason' => 'SYNTHETIC corrected support'])->assertOk();
+ $this->assertDatabaseCount('documents', 2);
+ $this->assertDatabaseCount('desk_documents', 2);
+ }
+
+ public function test_definition_rejects_missing_or_inappropriate_file_limits_and_rollback_preserves_scoped_uses(): void
+ {
+ $input = $this->publication(1);
+ foreach ([['max_size_kb' => 0], ['max_size_kb' => 10241], ['max_files' => 0], ['mime_types' => []], ['mime_types' => ['text/html']]] as $invalid) {
+ $bad = $input;
+ $bad['definition']['fields']['support'] = [...$bad['definition']['fields']['support'], ...$invalid];
+ $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', $bad)->assertUnprocessable();
+ }
+ $bad = $input;
+ unset($bad['definition']['fields']['support']['max_files']);
+ $this->putJson('/management/balcao/servicos/project-change', $bad)->assertUnprocessable();
+ $bad = $input;
+ $bad['definition']['fields']['title']['max_files'] = 1;
+ $this->putJson('/management/balcao/servicos/project-change', $bad)->assertUnprocessable();
+ $this->actingAs($this->owner);
+ $this->upload();
+ $other = $this->newRequest();
+ $this->upload('SYNTHETIC original bytes', $other);
+ $migration = require database_path('migrations/2026_11_03_050000_scope_desk_document_links.php');
+ try {
+ $migration->down();
+ $this->fail('Scoped links must not be destroyed.');
+ } catch (\RuntimeException $error) {
+ $this->assertStringContainsString('Preserve', $error->getMessage());
+ }
+ $this->assertDatabaseCount('desk_documents', 2);
+ }
+
+ public function test_organisation_representative_can_reuse_an_already_authorised_case_document_without_being_its_uploader(): void
+ {
+ $org = (string) Str::uuid();
+ $officer = User::factory()->create();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC document org', 'organization_type' => 'private']);
+ foreach ([[$this->owner, 'admin'], [$officer, 'officer']] as [$actor,$role]) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $actor->id, 'role' => $role]);
+ }
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['organization_id' => $org]);
+ $first = $this->upload();
+ $other = $this->newRequest();
+ $this->actingAs($officer)->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => $first['case_version'], 'request_id' => $other, 'field_key' => 'support', 'document_id' => $first['documents'][0]['document_id'], 'consent' => true])->assertOk();
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseHas('desk_documents', ['request_id' => $other, 'linked_by' => $officer->id, 'source_reference' => 'SYNTHETIC source only']);
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $officer->id)->update(['deleted_at' => now()]);
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 3, 'request_id' => $other, 'field_key' => 'support', 'document_id' => $first['documents'][0]['document_id'], 'consent' => true])->assertForbidden();
+ }
+
+ public function test_two_link_aliases_cannot_count_as_two_documents_in_the_same_question(): void
+ {
+ $first = $this->upload();
+ $global = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => $first['case_version'], 'document_id' => $first['documents'][0]['document_id'], 'category' => 'SYNTHETIC dossier use', 'consent' => true])->assertOk()->json();
+ $this->save($this->answers([$first['link_id'], $global['link_id']]), 1, false)->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 2);
+ }
+
+ public function test_missing_scope_migration_is_a_specific_dependency_without_removing_manual_drafts(): void
+ {
+ DB::statement('ALTER INDEX desk_documents_scope_unique RENAME TO desk_documents_scope_qa_absent');
+ try {
+ $input = $this->publication(1);
+ $input['definition']['title'] = 'SYNTHETIC changed title';
+ $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', $input)->assertUnprocessable();
+ $this->actingAs($this->owner);
+ $this->save(['title' => 'SYNTHETIC still editable'], 1, false)->assertOk();
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'request_id' => $this->id, 'field_key' => 'support', 'file' => UploadedFile::fake()->createWithContent('new.txt', 'SYNTHETIC'), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertConflict();
+ } finally {
+ DB::statement('ALTER INDEX desk_documents_scope_qa_absent RENAME TO desk_documents_scope_unique');
+ }
+ $this->assertDatabaseCount('documents', 0);
+ }
+
+ public function test_encrypted_original_can_be_submitted_and_reviewed_with_the_shared_integrity_rules(): void
+ {
+ $link = $this->upload()['link_id'];
+ $document = $this->clean($link);
+ $bytes = Storage::disk('local')->get($document->storage_key);
+ Storage::disk('local')->put($document->storage_key, Crypt::encryptString($bytes));
+ DB::table('documents')->where('id', $document->id)->update(['storage_encryption' => 'laravel']);
+ $this->save($this->answers([$link]))->assertOk();
+ $this->actingAs($this->manager)->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos/'.$link.'/conferencia', ['version' => 2, 'request_id' => $this->id, 'outcome' => 'internal_verified', 'what_checked' => 'SYNTHETIC original bytes and scope', 'evidence' => 'SYNTHETIC review only', 'supports' => []])->assertOk();
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'document_reviewed')->count());
+ Storage::disk('local')->put($document->storage_key, 'SYNTHETIC corrupt ciphertext');
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos/'.$link.'/conferencia', ['version' => 3, 'request_id' => $this->id, 'outcome' => 'internal_verified', 'what_checked' => 'SYNTHETIC repeat', 'evidence' => 'SYNTHETIC repeat', 'supports' => []])->assertUnprocessable();
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'document_reviewed')->count());
+ }
+
+ public function test_attachment_questions_with_financial_identifiers_do_not_become_numeric_answers_or_financing_questions(): void
+ {
+ $fields = [];
+ $payload = [];
+ foreach (['investment_amount', 'own_finance', 'other_finance'] as $key) {
+ $fields[$key] = ['label' => 'SYNTHETIC evidence', 'type' => 'attachment', 'required' => false, 'mime_types' => ['text/plain'], 'max_files' => 1, 'max_size_kb' => 2];
+ $payload[$key] = [(string) Str::uuid()];
+ }
+ $findings = app(VirtualDesk::class)->findings($payload, ['fields' => $fields]);
+ $this->assertNotContains('finance_unknown', array_column($findings, 'code'));
+ $this->assertNotContains('finance_difference', array_column($findings, 'code'));
+ }
+
+ public function test_unknown_legacy_file_metadata_is_measured_without_reupload_or_rewriting_the_original_record(): void
+ {
+ $link = $this->upload()['link_id'];
+ $document = $this->clean($link);
+ DB::table('documents')->where('id', $document->id)->update(['media_type' => '', 'size_bytes' => null]);
+ $this->save($this->answers([$link]))->assertOk();
+ $snapshot = app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $this->id)->value('submitted_snapshot'));
+ $file = $snapshot['field_attachments']['support']['files'][0];
+ $this->assertSame('text/plain', $file['media_type']);
+ $this->assertSame($document->size_bytes, $file['size_bytes']);
+ $this->assertTrue($file['metadata_measured']);
+ $this->assertSame('', $file['recorded_media_type']);
+ $this->assertNull($file['recorded_size_bytes']);
+ $this->assertDatabaseHas('documents', ['id' => $document->id, 'media_type' => '', 'size_bytes' => null]);
+ $this->assertDatabaseCount('documents', 1);
+ }
+
+ public function test_actual_file_format_cannot_be_replaced_by_a_misleading_registered_mime_type(): void
+ {
+ $link = $this->upload()['link_id'];
+ $document = $this->clean($link);
+ DB::table('documents')->where('id', $document->id)->update(['media_type' => 'application/pdf']);
+ $input = $this->publication(1);
+ $input['definition']['fields']['support']['mime_types'] = ['application/pdf'];
+ $this->edition = $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', $input)->assertCreated()->json('id');
+ $this->actingAs($this->owner);
+ $this->id = $this->newRequest();
+ $result = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'request_id' => $this->id, 'field_key' => 'support', 'document_id' => $document->id, 'consent' => true])->assertOk();
+ $this->save($this->answers([$result->json('link_id')]))->assertUnprocessable()->assertJsonValidationErrors('payload.support');
+ $this->assertDatabaseHas('desk_requests', ['id' => $this->id, 'version' => 1, 'submitted_snapshot' => null]);
+ }
+
+ public function test_owner_reuse_picker_preserves_the_chosen_source_and_declared_dates_without_exposing_other_request_inventory_to_reviewers(): void
+ {
+ $second = $this->newRequest();
+ $fromB = $this->upload('SYNTHETIC reused original', $second);
+ $third = $this->newRequest();
+ $fromC = $this->upload('SYNTHETIC reused original', $third);
+ DB::table('desk_documents')->where('id', $fromB['link_id'])->update(['source_reference' => 'SYNTHETIC ref B', 'stage' => 'E1', 'valid_until' => '2027-01-02']);
+ DB::table('desk_documents')->where('id', $fromC['link_id'])->update(['source_reference' => 'SYNTHETIC ref C', 'stage' => 'E2', 'valid_until' => '2028-03-04']);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->id)->assertOk()->assertJsonCount(0, 'documents')->assertJsonCount(2, 'reusableDocuments');
+ $version = DB::table('desk_cases')->where('id', $this->caseId)->value('version');
+ $body = ['version' => $version, 'request_id' => $this->id, 'field_key' => 'support', 'document_id' => $fromB['documents'][0]['document_id'], 'reuse_link_id' => $fromB['link_id'], 'consent' => true];
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', [...$body, 'reuse_link_id' => (string) Str::uuid()])->assertForbidden();
+ $result = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', $body)->assertOk();
+ $link = $result->json('link_id');
+ $this->assertDatabaseHas('desk_documents', ['id' => $link, 'request_id' => $this->id, 'source_reference' => 'SYNTHETIC ref B', 'valid_until' => '2027-01-02', 'stage' => 'E10']);
+ $event = DB::table('desk_events')->where('request_id', $this->id)->where('action', 'document_linked')->orderByDesc('event_order')->first();
+ $trace = app(VirtualDesk::class)->decode($event->payload);
+ $this->assertSame($fromB['link_id'], $trace['source_link_id']);
+ $this->assertSame('E1', $trace['reused_source']['stage']);
+ $this->assertArrayNotHasKey('request_id', $trace['reused_source']);
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 3);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ }
+
+ public function test_closed_dossier_keeps_request_readable_without_offering_edits_or_document_reuse(): void
+ {
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['closed_at' => now()]);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->id)->assertOk()->assertJsonPath('request.status', 'draft')->assertJsonPath('fieldsEditable', false)->assertJsonCount(0, 'reusableDocuments');
+ $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'request_id' => $this->id, 'field_key' => 'support', 'file' => UploadedFile::fake()->createWithContent('synthetic.txt', 'SYNTHETIC'), 'source_reference' => 'SYNTHETIC', 'consent' => true], ['Accept' => 'application/json'])->assertConflict();
+ $this->assertDatabaseCount('documents', 0);
+ $this->assertSame([], Storage::disk('local')->allFiles());
+ }
+}
diff --git a/tests/Feature/DeskCaseStateTest.php b/tests/Feature/DeskCaseStateTest.php
new file mode 100644
index 00000000..cb717963
--- /dev/null
+++ b/tests/Feature/DeskCaseStateTest.php
@@ -0,0 +1,132 @@
+withoutVite();
+ $this->owner = User::factory()->create();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false]);
+ $edition = $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', ['base_version' => 0, 'definition' => config('virtual-desk.services.project-change'), 'confirm' => true, 'reason' => 'SYNTHETIC owner lifecycle QA'])->assertCreated()->json('id');
+ $this->caseId = $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC owned dossier', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->requestId = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/pedidos', ['service_version_id' => $edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function operation(string $state, int $version): array
+ {
+ return ['state' => $state, 'version' => $version, 'reason' => 'SYNTHETIC owner decision '.$state, 'client_key' => (string) Str::uuid()];
+ }
+
+ private function change(array $input): TestResponse
+ {
+ return $this->putJson('/balcao-virtual/dossiers/'.$this->caseId.'/estado', $input);
+ }
+
+ public function test_owner_closes_and_reopens_without_changing_payload_workflow_or_child_states(): void
+ {
+ $task = CrmTask::create(['desk_case_id' => $this->caseId, 'guidance_key' => 'synthetic_open_task', 'title' => 'SYNTHETIC accepted task', 'status' => 'open', 'accepted_by' => $this->owner->id, 'accepted_at' => now(), 'assignee_user_id' => $this->owner->id, 'external_sync_status' => 'pending_authorization', 'data_classification' => 'confidential']);
+ $payment = (string) Str::uuid();
+ DB::table('desk_payments')->insert(['id' => $payment, 'request_id' => $this->requestId, 'reference' => 'SYNTHETIC-PENDING', 'amount' => '25.50', 'currency' => 'MZN', 'source_reference' => 'SYNTHETIC pending declaration', 'status' => 'pending']);
+ $before = DB::table('desk_cases')->where('id', $this->caseId)->first();
+ $request = (array) DB::table('desk_requests')->where('id', $this->requestId)->first();
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId)->assertOk()->assertJsonPath('canChangeState', true)->assertJsonPath('activity.open_requests', 1)->assertJsonPath('activity.open_tasks', 1)->assertJsonPath('activity.pending_payments', 1);
+ $this->change($this->operation('closed', 1))->assertOk()->assertJsonPath('version', 2)->assertJsonPath('replayed', false);
+ $closed = DB::table('desk_cases')->where('id', $this->caseId)->first();
+ $this->assertNotNull($closed->closed_at);
+ $this->assertSame($before->payload, $closed->payload);
+ $this->assertSame($before->workflow, $closed->workflow);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('operationsEditable', false)->assertJsonPath('request.status', 'draft');
+ $this->change($this->operation('open', 2))->assertOk()->assertJsonPath('version', 3)->assertJsonPath('closed_at', null);
+ $this->assertSame($request, (array) DB::table('desk_requests')->where('id', $this->requestId)->first());
+ $this->assertDatabaseHas('tasks', ['id' => $task->id, 'status' => 'open', 'version_no' => 1]);
+ $this->assertDatabaseHas('desk_payments', ['id' => $payment, 'status' => 'pending', 'amount' => '25.50', 'version' => 1]);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('fieldsEditable', true);
+ }
+
+ public function test_manager_or_other_organization_writer_is_not_the_registered_owner(): void
+ {
+ $this->actingAs($this->manager)->change($this->operation('closed', 1))->assertForbidden();
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC owner organization', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['organization_id' => $org]);
+ foreach ([$this->owner, $this->manager] as $member) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $member->id, 'role' => 'admin']);
+ }
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId)->assertOk()->assertJsonPath('canWrite', true)->assertJsonPath('canChangeState', false);
+ $this->change($this->operation('closed', 1))->assertForbidden();
+ $this->actingAs($this->owner)->change($this->operation('closed', 1))->assertOk();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->owner->id)->update(['deleted_at' => now()]);
+ $this->change($this->operation('open', 2))->assertForbidden();
+ $this->assertDatabaseHas('desk_cases', ['id' => $this->caseId, 'version' => 2]);
+ }
+
+ public function test_exact_retry_is_idempotent_and_old_close_retry_does_not_reverse_a_later_reopening(): void
+ {
+ $close = $this->operation('closed', 1);
+ $this->change($close)->assertOk();
+ $this->change([...$close, 'version' => '1'])->assertOk()->assertJsonPath('version', 2)->assertJsonPath('replayed', true);
+ $this->change([...$close, 'reason' => 'SYNTHETIC changed operation'])->assertConflict();
+ $this->change($this->operation('open', 2))->assertOk();
+ $this->change($close)->assertOk()->assertJsonPath('version', 3)->assertJsonPath('closed_at', null)->assertJsonPath('replayed', true);
+ $this->assertSame(2, DB::table('desk_events')->where('action', 'case_state_changed')->count());
+ }
+
+ public function test_stale_version_missing_reason_or_same_state_cannot_change_the_dossier(): void
+ {
+ $this->change($this->operation('open', 1))->assertConflict();
+ $this->change([...$this->operation('closed', 1), 'reason' => ''])->assertUnprocessable()->assertJsonValidationErrors('reason');
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/etapas', ['version' => 1, 'stage' => 'E0', 'status' => 'preparing', 'reason' => 'SYNTHETIC intervening change'])->assertOk();
+ $this->change($this->operation('closed', 1))->assertConflict();
+ $this->assertDatabaseHas('desk_cases', ['id' => $this->caseId, 'closed_at' => null, 'version' => 2]);
+ }
+
+ public function test_reopening_does_not_reopen_a_cancelled_request_and_records_owner_reason_and_summary(): void
+ {
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 1, 'status' => 'cancelled', 'reason' => 'SYNTHETIC request cancellation'])->assertOk();
+ $this->change($this->operation('closed', 1))->assertOk();
+ $this->change($this->operation('open', 2))->assertOk();
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('request.status', 'cancelled')->assertJsonPath('operationsEditable', false);
+ $event = DB::table('desk_events')->where('case_id', $this->caseId)->where('action', 'case_state_changed')->orderBy('event_order')->first();
+ $data = app(VirtualDesk::class)->decode($event->payload);
+ $this->assertSame($this->owner->id, (int) $event->actor_id);
+ $this->assertSame('SYNTHETIC owner decision closed', $data['reason']);
+ $this->assertSame(0, $data['activity']['open_requests']);
+ $this->assertNull($data['before']['closed_at']);
+ $this->assertNotNull($data['after']['closed_at']);
+ }
+
+ public function test_unknown_optional_task_count_is_not_reported_as_zero(): void
+ {
+ DB::statement('ALTER TABLE tasks RENAME TO tasks_qa_unavailable');
+ try {
+ $activity = app(VirtualDesk::class)->caseActivity(DB::table('desk_cases')->where('id', $this->caseId)->first());
+ $this->assertNull($activity['open_tasks']);
+ $this->assertSame(1, $activity['open_requests']);
+ } finally {
+ DB::statement('ALTER TABLE tasks_qa_unavailable RENAME TO tasks');
+ }
+ }
+}
diff --git a/tests/Feature/DeskClosedLifecycleTest.php b/tests/Feature/DeskClosedLifecycleTest.php
new file mode 100644
index 00000000..fecde516
--- /dev/null
+++ b/tests/Feature/DeskClosedLifecycleTest.php
@@ -0,0 +1,164 @@
+withoutVite();
+ Http::fake();
+ $this->owner = User::factory()->create();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false]);
+ $edition = $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', ['base_version' => 0, 'definition' => config('virtual-desk.services.project-change'), 'reason' => 'SYNTHETIC lifecycle QA', 'confirm' => true])->assertCreated()->json('id');
+ $this->caseId = $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC closed dossier', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->requestId = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/pedidos', ['service_version_id' => $edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function submit(): void
+ {
+ $this->putJson('/balcao-virtual/pedidos/'.$this->requestId, ['version' => 1, 'payload' => ['title' => 'SYNTHETIC project', 'description' => 'SYNTHETIC private preparation', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC change'], 'submit' => true, 'consent' => true])->assertOk();
+ }
+
+ private function closeFixture(): array
+ {
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['closed_at' => now()]);
+
+ return ['request' => (array) DB::table('desk_requests')->where('id', $this->requestId)->first(), 'case' => (array) DB::table('desk_cases')->where('id', $this->caseId)->first(), 'events' => DB::table('desk_events')->count(), 'notifications' => DB::table('desk_notifications')->count(), 'messages' => DB::table('desk_messages')->count()];
+ }
+
+ private function assertUnchanged(array $before): void
+ {
+ $this->assertSame($before['request'], (array) DB::table('desk_requests')->where('id', $this->requestId)->first());
+ $this->assertSame($before['case'], (array) DB::table('desk_cases')->where('id', $this->caseId)->first());
+ foreach (['events' => 'desk_events', 'notifications' => 'desk_notifications', 'messages' => 'desk_messages'] as $key => $table) {
+ $this->assertSame($before[$key], DB::table($table)->count());
+ }
+ }
+
+ public function test_closed_dossier_rejects_request_transition_without_changing_its_history(): void
+ {
+ $this->submit();
+ $before = $this->closeFixture();
+ $this->actingAs($this->manager)->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 2, 'status' => 'reviewing', 'reason' => 'SYNTHETIC review attempt'])->assertConflict();
+ $this->assertUnchanged($before);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('operationsEditable', false)->assertJsonCount(0, 'transitions');
+ }
+
+ public function test_closed_dossier_rejects_stage_changes_but_keeps_workflow_readable(): void
+ {
+ $before = $this->closeFixture();
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/etapas', ['version' => 1, 'stage' => 'E0', 'status' => 'preparing', 'reason' => 'SYNTHETIC preparation attempt'])->assertConflict();
+ $this->assertUnchanged($before);
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId)->assertOk()->assertJsonPath('canWrite', false)->assertJsonStructure(['case' => ['workflow', 'closed_at']]);
+ }
+
+ public function test_closed_dossier_is_excluded_from_triage_and_rejects_assignment(): void
+ {
+ $this->submit();
+ $before = $this->closeFixture();
+ $this->actingAsWithMfa($this->manager)->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/responsavel', ['version' => 2, 'analyst_id' => $this->manager->id, 'reason' => 'SYNTHETIC assignment attempt'])->assertConflict();
+ $this->assertUnchanged($before);
+ $this->getJson('/management/balcao/atribuicoes')->assertOk()->assertJsonCount(0, 'requests');
+ }
+
+ public function test_closed_dossier_refuses_messages_even_if_its_request_is_still_open(): void
+ {
+ $this->submit();
+ $before = $this->closeFixture();
+ foreach ([$this->owner, $this->manager] as $actor) {
+ $this->actingAs($actor)->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/mensagens', ['body' => 'SYNTHETIC message attempt', 'client_key' => (string) Str::uuid()])->assertConflict();
+ }
+ $this->assertUnchanged($before);
+ }
+
+ public function test_closed_dossier_refuses_task_updates_and_guidance_remains_readable_without_write_actions(): void
+ {
+ $view = $this->getJson('/balcao-virtual/dossiers/'.$this->caseId.'/orientacao')->assertOk()->json();
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/recomendacoes', ['code' => 'support_preparation', 'context_hash' => $view['fingerprint'], 'decision' => 'accepted', 'reason' => 'SYNTHETIC preparation intent'])->assertOk();
+ $task = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/tarefas', ['code' => 'support_preparation', 'context_hash' => $view['fingerprint'], 'consent' => true, 'due_at' => now()->addDays(2)->toIso8601String()])->assertCreated()->json('id');
+ $before = $this->closeFixture();
+ foreach ([$this->owner, $this->manager] as $actor) {
+ $this->actingAs($actor)->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/tarefas/'.$task, ['version' => 1, 'status' => 'done', 'reason' => 'SYNTHETIC task update attempt'])->assertConflict();
+ }
+ $this->assertDatabaseHas('tasks', ['id' => $task, 'status' => 'open', 'version_no' => 1]);
+ $this->assertUnchanged($before);
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId.'/orientacao')->assertOk()->assertJsonPath('can_write', false)->assertJsonPath('can_update_tasks', false)->assertJsonCount(1, 'tasks');
+ }
+
+ public function test_open_dossier_keeps_existing_transition_assignment_message_and_task_permissions(): void
+ {
+ $this->submit();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 2, 'status' => 'reviewing', 'reason' => 'SYNTHETIC self-review'])->assertForbidden();
+ $this->actingAsWithMfa($this->manager)->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/responsavel', ['version' => 2, 'analyst_id' => $this->manager->id, 'reason' => 'SYNTHETIC permitted assignment'])->assertOk();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 3, 'status' => 'reviewing', 'reason' => 'SYNTHETIC permitted review'])->assertOk();
+ $this->actingAs($this->owner)->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/mensagens', ['body' => 'SYNTHETIC permitted message', 'client_key' => (string) Str::uuid()])->assertOk();
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId.'/orientacao')->assertOk()->assertJsonPath('can_write', true)->assertJsonPath('can_update_tasks', true);
+ $this->actingAs(User::factory()->create())->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertForbidden();
+ }
+
+ public function test_draft_cancellation_preserves_payload_documents_and_case_and_cannot_cancel_a_submitted_request(): void
+ {
+ $before = DB::table('desk_requests')->where('id', $this->requestId)->first();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 1, 'status' => 'cancelled', 'reason' => 'SYNTHETIC deliberate cancellation'])->assertOk()->assertJsonPath('status', 'cancelled');
+ $after = DB::table('desk_requests')->where('id', $this->requestId)->first();
+ $this->assertSame($before->payload, $after->payload);
+ $this->assertSame($before->submitted_snapshot, $after->submitted_snapshot);
+ $this->assertDatabaseHas('desk_cases', ['id' => $this->caseId, 'closed_at' => null]);
+ $this->assertNotNull($after->closed_at);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('operationsEditable', false);
+ $edition = DB::table('desk_requests')->where('id', $this->requestId)->value('service_version_id');
+ $this->requestId = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/pedidos', ['service_version_id' => $edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ $this->submit();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/estado', ['version' => 2, 'status' => 'cancelled', 'reason' => 'SYNTHETIC submitted cancellation attempt'])->assertForbidden();
+ $this->assertDatabaseHas('desk_requests', ['id' => $this->requestId, 'status' => 'submitted', 'version' => 2]);
+ }
+
+ public function test_dual_linked_crm_task_observes_dossier_closure_without_changing_crm_authority(): void
+ {
+ $lead = Lead::create(['title' => 'SYNTHETIC dual-linked lead', 'status' => 'disqualified', 'owner_user_id' => $this->manager->id]);
+ $task = CrmTask::create(['lead_id' => $lead->id, 'desk_case_id' => $this->caseId, 'guidance_key' => 'synthetic_dual_link', 'title' => 'SYNTHETIC existing linked task', 'status' => 'open', 'assignee_user_id' => $this->manager->id, 'accepted_by' => $this->owner->id, 'accepted_at' => now(), 'external_sync_status' => 'pending_authorization', 'data_classification' => 'confidential']);
+ $url = '/management/crm/leads/'.$lead->id.'/tasks/'.$task->id;
+ $this->actingAsWithMfa($this->manager)->patch($url, ['version' => $task->fresh()->getAttribute('version_no'), 'status' => 'in_progress'])->assertRedirect();
+ $this->assertDatabaseHas('tasks', ['id' => $task->id, 'status' => 'in_progress']);
+ $this->closeFixture();
+ $this->patchJson($url, ['version' => $task->fresh()->getAttribute('version_no'), 'status' => 'done'])->assertConflict();
+ $this->assertDatabaseHas('tasks', ['id' => $task->id, 'status' => 'in_progress']);
+ $this->get('/management/crm/leads/'.$lead->id)->assertOk()->assertInertia(fn ($page) => $page->where('lead.tasks.0.can_update', false));
+ }
+
+ public function test_crm_without_linked_tasks_does_not_require_an_installed_desk(): void
+ {
+ $lead = Lead::create(['title' => 'SYNTHETIC standalone CRM', 'status' => 'disqualified', 'owner_user_id' => $this->manager->id]);
+ $this->actingAsWithMfa($this->manager);
+ DB::statement('ALTER TABLE desk_cases RENAME TO desk_cases_qa_unavailable');
+ try {
+ $this->get('/management/crm/leads/'.$lead->id)->assertOk()->assertInertia(fn ($page) => $page->where('lead.title', 'SYNTHETIC standalone CRM'));
+ } finally {
+ DB::statement('ALTER TABLE desk_cases_qa_unavailable RENAME TO desk_cases');
+ }
+ }
+}
diff --git a/tests/Feature/DeskDocumentReuseTest.php b/tests/Feature/DeskDocumentReuseTest.php
new file mode 100644
index 00000000..f36c04bc
--- /dev/null
+++ b/tests/Feature/DeskDocumentReuseTest.php
@@ -0,0 +1,166 @@
+withoutVite();
+ Storage::fake('local');
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->actingAs($this->owner);
+ $this->caseId = $this->makeCase('SYNTHETIC destination');
+ }
+
+ private function makeCase(string $title): string
+ {
+ return $this->postJson('/balcao-virtual/dossiers', ['title' => $title, 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ private function upload(string $case, string $name = 'synthetic-source.txt'): array
+ {
+ return $this->post('/balcao-virtual/dossiers/'.$case.'/documentos', ['version' => DB::table('desk_cases')->where('id', $case)->value('version'), 'file' => UploadedFile::fake()->createWithContent($name, 'SYNTHETIC '.$name), 'category' => 'project_evidence', 'source_reference' => 'SYNTHETIC source '.$name, 'consent' => true], ['Accept' => 'application/json'])->assertOk()->json();
+ }
+
+ private function catalogue(string $query = ''): TestResponse
+ {
+ return $this->getJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos-disponiveis'.$query);
+ }
+
+ public function test_personal_source_is_searchable_and_reused_without_reentering_reference_dates_or_copying_original(): void
+ {
+ $source = $this->makeCase('SYNTHETIC previous dossier');
+ $upload = $this->upload($source);
+ DB::table('desk_documents')->where('id', $upload['link_id'])->update(['stage' => 'E2', 'valid_until' => '2028-02-03']);
+ $this->catalogue('?q=previous')->assertOk()->assertJsonCount(1, 'documents')->assertJsonPath('documents.0.id', $upload['link_id'])->assertJsonPath('documents.0.valid_until', '2028-02-03')->assertHeader('Cache-Control', 'no-store, private');
+ $document = $upload['documents'][0]['document_id'];
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'document_id' => $document, 'reuse_link_id' => $upload['link_id'], 'category' => 'resource_evidence', 'consent' => true])->assertOk();
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('desk_documents', 2);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ $this->assertDatabaseHas('desk_documents', ['case_id' => $this->caseId, 'document_id' => $document, 'source_reference' => 'SYNTHETIC source synthetic-source.txt', 'stage' => 'E2', 'valid_until' => '2028-02-03']);
+ $this->assertDatabaseHas('desk_cases', ['id' => $source, 'version' => 2]);
+ }
+
+ public function test_catalogue_matches_existing_authority_and_hides_another_dossiers_private_source_from_its_uploader(): void
+ {
+ $source = $this->makeCase('SYNTHETIC secret organization context');
+ $upload = $this->upload($source);
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC organization', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $source)->update(['organization_id' => $org]);
+ $this->catalogue()->assertOk()->assertJsonCount(1, 'documents')->assertJsonPath('documents.0.id', null)->assertJsonPath('documents.0.source_reference', null)->assertJsonPath('documents.0.origin_label', null);
+ $this->catalogue('?q=secret')->assertOk()->assertJsonCount(0, 'documents');
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'document_id' => $upload['documents'][0]['document_id'], 'reuse_link_id' => $upload['link_id'], 'category' => 'project_evidence', 'consent' => true])->assertForbidden();
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 1, 'document_id' => $upload['documents'][0]['document_id'], 'category' => 'project_evidence', 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors('source_reference');
+ $other = User::factory()->create();
+ config(['portal.managers' => [$other->email]]);
+ $this->actingAs($other);
+ $this->catalogue()->assertForbidden();
+ }
+
+ public function test_current_organization_files_are_reusable_but_revoked_members_cannot_keep_using_the_catalogue(): void
+ {
+ $upload = $this->upload($this->caseId);
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC collaboration', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['organization_id' => $org]);
+ $colleague = User::factory()->create();
+ $membership = (string) Str::uuid();
+ DB::table('memberships')->insert(['id' => $membership, 'organization_id' => $org, 'user_id' => $colleague->id, 'role' => 'officer']);
+ $this->actingAs($colleague);
+ $this->catalogue()->assertOk()->assertJsonPath('documents.0.id', $upload['link_id']);
+ DB::table('memberships')->where('id', $membership)->update(['role' => 'viewer']);
+ $this->catalogue()->assertForbidden();
+ DB::table('memberships')->where('id', $membership)->update(['role' => 'officer', 'deleted_at' => now()]);
+ $this->catalogue()->assertForbidden();
+ }
+
+ public function test_unlinked_uploads_are_available_without_invented_provenance_and_foreign_or_deleted_uploads_are_absent(): void
+ {
+ $upload = $this->upload($this->caseId);
+ DB::table('desk_documents')->where('id', $upload['link_id'])->delete();
+ $this->catalogue()->assertOk()->assertJsonCount(1, 'documents')->assertJsonPath('documents.0.id', null)->assertJsonPath('documents.0.source_reference', null);
+ $document = $upload['documents'][0]['document_id'];
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'document_id' => $document, 'category' => 'project_evidence', 'source_reference' => 'SYNTHETIC supplied missing reference', 'consent' => true])->assertOk();
+ DB::table('documents')->where('id', $document)->update(['deleted_at' => now()]);
+ $this->catalogue()->assertOk()->assertJsonCount(0, 'documents');
+ $this->actingAs(User::factory()->create());
+ $foreign = $this->makeCase('SYNTHETIC foreign');
+ $this->upload($foreign, 'private-foreign.txt');
+ $this->actingAs($this->owner);
+ $this->catalogue()->assertOk()->assertJsonCount(0, 'documents');
+ }
+
+ public function test_opportunity_source_authority_is_checked_in_catalogue_and_attachment_even_for_uploader(): void
+ {
+ $upload = $this->upload($this->caseId);
+ $document = $upload['documents'][0]['document_id'];
+ DB::table('documents')->where('id', $document)->update(['source_system' => 'opportunity-resources']);
+ $this->catalogue()->assertOk()->assertJsonCount(0, 'documents');
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'document_id' => $document, 'category' => 'project_evidence', 'consent' => true])->assertForbidden();
+ $this->assertDatabaseHas('desk_cases', ['id' => $this->caseId, 'version' => 2]);
+ }
+
+ public function test_literal_search_pagination_and_invalid_input_do_not_expand_scope(): void
+ {
+ $upload = $this->upload($this->caseId, 'SYNTHETIC %_ literal.txt');
+ $row = (array) DB::table('documents')->where('id', $upload['documents'][0]['document_id'])->first();
+ for ($i = 0; $i < 27; $i++) {
+ $copy = (string) Str::uuid();
+ $key = 'synthetic-catalogue/'.$copy;
+ Storage::disk('local')->put($key, Storage::disk('local')->get($row['storage_key']));
+ DB::table('documents')->insert([...$row, 'id' => $copy, 'storage_key' => $key, 'file_name' => sprintf('SYNTHETIC paged %02d.txt', $i)]);
+ }
+ $this->catalogue('?q='.urlencode('%_'))->assertOk()->assertJsonCount(1, 'documents')->assertJsonPath('documents.0.file_name', 'SYNTHETIC %_ literal.txt');
+ $first = $this->catalogue('?q=paged')->assertOk()->assertJsonCount(25, 'documents')->assertJsonPath('next_offset', 25)->json('documents');
+ $last = $this->catalogue('?q=paged&offset=25')->assertOk()->assertJsonCount(2, 'documents')->assertJsonPath('next_offset', null)->json('documents');
+ $this->assertCount(27, array_unique(array_column([...$first, ...$last], 'document_id')));
+ $this->catalogue('?offset=-1')->assertUnprocessable();
+ $this->catalogue('?q='.str_repeat('x', 121))->assertUnprocessable();
+ }
+
+ public function test_selected_stage_link_preserves_its_exact_provenance_and_legacy_document_id_still_works(): void
+ {
+ $upload = $this->upload($this->caseId);
+ $other = $this->makeCase('SYNTHETIC other source');
+ $foreign = $this->upload($other, 'foreign-link.txt');
+ $body = ['version' => 2, 'stage' => 'E0', 'status' => 'preparing', 'reason' => 'SYNTHETIC exact support', 'document_link_id' => $upload['link_id']];
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/etapas', [...$body, 'document_link_id' => $foreign['link_id']])->assertUnprocessable();
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/etapas', $body)->assertOk();
+ $case = DB::table('desk_cases')->where('id', $this->caseId)->first();
+ $snapshot = json_decode($case->workflow, true)['E0'];
+ $this->assertSame($upload['link_id'], $snapshot['document_link_id']);
+ $this->assertSame($upload['documents'][0]['document_id'], $snapshot['document_id']);
+ $this->assertSame('SYNTHETIC source synthetic-source.txt', $snapshot['document_source']['source_reference']);
+ $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/etapas', ['version' => 3, 'stage' => 'E0', 'status' => 'preparing', 'reason' => 'SYNTHETIC legacy client', 'document_id' => $upload['documents'][0]['document_id']])->assertOk();
+ }
+
+ public function test_closed_dossiers_remain_readable_without_upload_or_catalogue_and_anonymous_access_is_refused(): void
+ {
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['closed_at' => now()]);
+ $this->getJson('/balcao-virtual/dossiers/'.$this->caseId)->assertOk()->assertJsonPath('canWrite', false);
+ $this->catalogue()->assertConflict();
+ auth()->logout();
+ $this->catalogue()->assertUnauthorized();
+ }
+}
diff --git a/tests/Feature/DeskPaymentEvidenceTest.php b/tests/Feature/DeskPaymentEvidenceTest.php
new file mode 100644
index 00000000..6f779acb
--- /dev/null
+++ b/tests/Feature/DeskPaymentEvidenceTest.php
@@ -0,0 +1,213 @@
+withoutVite();
+ Queue::fake();
+ Storage::fake('local');
+ $this->owner = User::factory()->create();
+ $this->reviewer = User::factory()->create();
+ config(['portal.managers' => [$this->reviewer->email]]);
+ $this->edition = $this->actingAs($this->reviewer)->putJson('/management/balcao/servicos/project-change', ['base_version' => 0, 'definition' => config('virtual-desk.services.project-change'), 'reason' => 'SYNTHETIC payment evidence QA', 'confirm' => true])->assertCreated()->json('id');
+ $this->caseId = $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC payment dossier', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->requestId = $this->newRequest();
+ }
+
+ private function newRequest(): string
+ {
+ return $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/pedidos', ['service_version_id' => $this->edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function upload(?string $request = null, string $name = 'synthetic-proof.txt'): array
+ {
+ return $this->post('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => DB::table('desk_cases')->where('id', $this->caseId)->value('version'), 'request_id' => $request, 'file' => UploadedFile::fake()->createWithContent($name, 'SYNTHETIC '.$name), 'category' => 'proof', 'source_reference' => 'SYNTHETIC documentary origin', 'consent' => true], ['Accept' => 'application/json'])->assertOk()->json();
+ }
+
+ private function declare(array $changes = []): string
+ {
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos', [...$this->declaration(), ...$changes])->assertOk();
+
+ return DB::table('desk_payments')->where('request_id', $this->requestId)->value('id');
+ }
+
+ private function declaration(): array
+ {
+ return ['reference' => 'SYNTHETIC-REFERENCE-1', 'amount' => '25.50', 'currency' => 'MZN', 'source_reference' => 'SYNTHETIC amount and purpose, not a fee', 'consent' => true];
+ }
+
+ private function operation(string $link, int $version = 1): array
+ {
+ return ['version' => $version, 'document_link_id' => $link, 'reason' => 'SYNTHETIC new documentary evidence', 'consent' => true, 'client_key' => (string) Str::uuid()];
+ }
+
+ private function attach(string $payment, array $data): TestResponse
+ {
+ return $this->putJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos/'.$payment.'/comprovativo', $data);
+ }
+
+ private function clean(string $document): void
+ {
+ $hash = DB::table('documents')->where('id', $document)->value('sha256');
+ DB::table('documents')->where('id', $document)->update(['status' => 'active', 'malware_scan_status' => 'clean', 'malware_scanned_sha256' => trim($hash)]);
+ }
+
+ private function review(string $payment, int $version, string $status = 'internal_verified'): TestResponse
+ {
+ return $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos/'.$payment.'/conferencia', ['version' => $version, 'status' => $status, 'reason' => 'SYNTHETIC internal review only', 'evidence' => 'SYNTHETIC evidence, not a bank confirmation']);
+ }
+
+ public function test_pending_reference_can_receive_a_proof_without_a_second_declaration_or_changing_financial_facts(): void
+ {
+ $payment = $this->declare();
+ $uploaded = $this->upload();
+ $before = DB::table('desk_requests')->where('id', $this->requestId)->first();
+ $this->attach($payment, [...$this->operation($uploaded['link_id']), 'amount' => '999.00'])->assertOk();
+ $this->assertDatabaseCount('desk_payments', 1);
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ $this->assertDatabaseHas('desk_payments', ['id' => $payment, 'reference' => 'SYNTHETIC-REFERENCE-1', 'amount' => '25.50', 'currency' => 'MZN', 'source_reference' => 'SYNTHETIC amount and purpose, not a fee', 'status' => 'pending', 'version' => 2, 'verified_by' => null]);
+ $after = DB::table('desk_requests')->where('id', $this->requestId)->first();
+ $this->assertSame($before->payload, $after->payload);
+ $this->assertSame($before->version, $after->version);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('payments.0.document_evidence.link_id', $uploaded['link_id'])->assertJsonPath('payments.0.document_evidence.source_reference', 'SYNTHETIC documentary origin');
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'payment_declared')->count());
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'payment_document_linked')->count());
+ }
+
+ public function test_replay_is_idempotent_and_changed_operation_or_stale_version_does_not_overwrite_evidence(): void
+ {
+ $payment = $this->declare();
+ $uploaded = $this->upload();
+ $operation = $this->operation($uploaded['link_id']);
+ $this->attach($payment, $operation)->assertOk();
+ $this->attach($payment, [...$operation, 'version' => '1', 'consent' => '1'])->assertOk();
+ $this->attach($payment, [...$operation, 'reason' => 'SYNTHETIC changed operation'])->assertConflict();
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertConflict();
+ $this->assertDatabaseHas('desk_payments', ['id' => $payment, 'version' => 2]);
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'payment_document_linked')->count());
+ }
+
+ public function test_selected_alias_is_frozen_and_another_requests_private_link_cannot_support_this_payment(): void
+ {
+ $other = $this->newRequest();
+ $uploaded = $this->upload($other);
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos', [...$this->declaration(), 'document_link_id' => $uploaded['link_id']])->assertUnprocessable();
+ $document = $uploaded['documents'][0]['document_id'];
+ $global = $this->postJson('/balcao-virtual/dossiers/'.$this->caseId.'/documentos', ['version' => 2, 'document_id' => $document, 'category' => 'proof', 'source_reference' => 'SYNTHETIC selected global source', 'valid_until' => '2028-02-03', 'consent' => true])->assertOk()->json('link_id');
+ $payment = $this->declare(['document_link_id' => $global]);
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos', [...$this->declaration(), 'document_link_id' => $global])->assertOk();
+ DB::table('desk_documents')->where('id', $global)->update(['source_reference' => 'SYNTHETIC later edit', 'valid_until' => '2029-01-01']);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('payments.0.document_evidence.link_id', $global)->assertJsonPath('payments.0.document_evidence.source_reference', 'SYNTHETIC selected global source')->assertJsonPath('payments.0.document_evidence.valid_until', '2028-02-03');
+ $this->assertDatabaseHas('desk_payments', ['id' => $payment, 'document_id' => $document, 'version' => 1]);
+ }
+
+ public function test_issue_can_receive_corrected_support_but_a_verified_record_cannot_be_silently_replaced(): void
+ {
+ $uploaded = $this->upload();
+ $this->clean($uploaded['documents'][0]['document_id']);
+ $payment = $this->declare(['document_link_id' => $uploaded['link_id']]);
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 1)->assertOk();
+ $this->actingAs($this->owner);
+ $this->attach($payment, $this->operation($uploaded['link_id'], 2))->assertConflict();
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 2, 'internal_issue')->assertOk();
+ $this->actingAs($this->owner);
+ $new = $this->upload(null, 'synthetic-corrected.txt');
+ $this->attach($payment, $this->operation($new['link_id'], 3))->assertOk();
+ $this->assertDatabaseHas('desk_payments', ['id' => $payment, 'status' => 'pending', 'version' => 4, 'verified_by' => null, 'reason' => null, 'amount' => '25.50']);
+ $this->assertSame(2, DB::table('desk_events')->where('action', 'payment_reviewed')->count());
+ $event = DB::table('desk_events')->where('action', 'payment_document_linked')->first();
+ $history = app(VirtualDesk::class)->decode($event->payload);
+ $this->assertSame($uploaded['link_id'], $history['previous_document_evidence']['link_id']);
+ }
+
+ public function test_pending_scan_and_changed_original_are_not_verified_against_the_old_snapshot(): void
+ {
+ $uploaded = $this->upload();
+ $document = $uploaded['documents'][0]['document_id'];
+ $payment = $this->declare(['document_link_id' => $uploaded['link_id']]);
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 1)->assertUnprocessable();
+ $row = DB::table('documents')->where('id', $document)->first();
+ $bytes = 'SYNTHETIC replaced original';
+ Storage::disk('local')->put($row->storage_key, $bytes);
+ DB::table('documents')->where('id', $document)->update(['sha256' => hash('sha256', $bytes), 'size_bytes' => strlen($bytes), 'version_no' => 2]);
+ $this->clean($document);
+ $this->review($payment, 1)->assertUnprocessable();
+ $this->actingAs($this->owner);
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertOk();
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 2)->assertOk();
+ }
+
+ public function test_legacy_payment_without_association_metadata_is_readable_and_keeps_its_historical_unknowns(): void
+ {
+ $uploaded = $this->upload();
+ $document = $uploaded['documents'][0]['document_id'];
+ $payment = (string) Str::uuid();
+ DB::table('desk_payments')->insert(['id' => $payment, 'request_id' => $this->requestId, 'reference' => 'SYNTHETIC-REFERENCE-1', 'amount' => '25.50', 'currency' => 'MZN', 'source_reference' => $this->declaration()['source_reference'], 'document_id' => $document, 'status' => 'pending']);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('payments.0.document_evidence', null);
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos', [...$this->declaration(), 'document_id' => $document])->assertOk();
+ $this->assertSame(0, DB::table('desk_events')->where('action', 'payment_declared')->count());
+ $this->clean($document);
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 1)->assertOk();
+ }
+
+ public function test_only_the_effective_owner_can_attach_evidence_and_review_remains_independent(): void
+ {
+ $uploaded = $this->upload();
+ $payment = $this->declare();
+ $this->review($payment, 1, 'internal_issue')->assertForbidden();
+ $this->actingAs($this->reviewer);
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertForbidden();
+ $this->actingAs(User::factory()->create());
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertForbidden();
+ $this->actingAs($this->owner);
+ $this->attach($payment, $this->operation((string) Str::uuid()))->assertUnprocessable();
+ DB::table('documents')->where('id', $uploaded['documents'][0]['document_id'])->update(['source_system' => 'opportunity-resources']);
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertForbidden();
+ }
+
+ public function test_closed_dossier_keeps_payment_history_readable_and_rejects_all_manual_writes(): void
+ {
+ $uploaded = $this->upload();
+ $payment = $this->declare();
+ DB::table('desk_cases')->where('id', $this->caseId)->update(['closed_at' => now()]);
+ $this->getJson('/balcao-virtual/pedidos/'.$this->requestId)->assertOk()->assertJsonPath('operationsEditable', false)->assertJsonCount(1, 'payments');
+ $this->attach($payment, $this->operation($uploaded['link_id']))->assertConflict();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/pagamentos', $this->declaration())->assertConflict();
+ $this->actingAs($this->reviewer);
+ $this->review($payment, 1, 'internal_issue')->assertConflict();
+ $this->postJson('/balcao-virtual/pedidos/'.$this->requestId.'/comunicacoes', ['channel' => 'phone', 'direction' => 'received', 'occurred_at' => now()->subMinute()->toIso8601String(), 'summary' => 'SYNTHETIC historical communication', 'evidence' => 'SYNTHETIC reference', 'client_key' => (string) Str::uuid()])->assertConflict();
+ }
+}
diff --git a/tests/Feature/DeskRequestCheckpointTest.php b/tests/Feature/DeskRequestCheckpointTest.php
new file mode 100644
index 00000000..6a9865cc
--- /dev/null
+++ b/tests/Feature/DeskRequestCheckpointTest.php
@@ -0,0 +1,204 @@
+withoutVite();
+ $this->owner = User::factory()->create();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email]]);
+ $definition = config('virtual-desk.services.project-change');
+ $definition['fields'] = [...$definition['fields'],
+ 'email' => ['label' => 'SYNTHETIC email', 'type' => 'email', 'required' => false],
+ 'amount' => ['label' => 'SYNTHETIC amount', 'type' => 'number', 'required' => false],
+ 'choices' => ['label' => 'SYNTHETIC choices', 'type' => 'multiselect', 'required' => false, 'options' => ['0' => 'Zero', 'cotton' => 'Cotton']],
+ 'declaration' => ['label' => 'SYNTHETIC declaration', 'type' => 'consent', 'required' => false, 'statement' => 'SYNTHETIC statement, no actual authorisation.'],
+ ];
+ $edition = $this->actingAs($this->manager)->putJson('/management/balcao/servicos/project-change', ['base_version' => 0, 'definition' => $definition, 'confirm' => true, 'reason' => 'SYNTHETIC checkpoint QA, not an actual publication.'])->assertCreated()->json('id');
+ $case = $this->actingAs($this->owner)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC checkpoint', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->id = $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function url(): string
+ {
+ return '/balcao-virtual/pedidos/'.$this->id.'/rascunho';
+ }
+
+ private function input(array $payload = [], int $version = 0, int $requestVersion = 1): array
+ {
+ return ['version' => $version, 'request_version' => $requestVersion, 'operation_key' => (string) Str::uuid(), 'payload' => $payload, 'edited_keys' => array_keys($payload), 'reason' => 'SYNTHETIC incomplete correction'];
+ }
+
+ private function answers(): array
+ {
+ return ['title' => 'SYNTHETIC main', 'description' => 'SYNTHETIC complete description', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC reason'];
+ }
+
+ public function test_incomplete_formats_are_recoverable_encrypted_and_never_change_the_authoritative_request_or_notifications(): void
+ {
+ $before = DB::table('desk_requests')->where('id', $this->id)->first();
+ $events = DB::table('desk_events')->count();
+ $notifications = DB::table('desk_notifications')->count();
+ $payload = ['email' => 'incomplete@', 'amount' => '-', 'choices' => ['cotton', '0'], 'declaration' => 'declined'];
+ $this->postJson($this->url(), $this->input($payload))->assertOk()->assertJsonPath('checkpoint.version', 1)->assertJsonPath('checkpoint.payload.email', 'incomplete@');
+ $this->getJson($this->url())->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('checkpoint.payload.amount', '-')->assertJsonPath('checkpoint.payload.choices', ['0', 'cotton'])->assertJsonPath('checkpoint.payload.declaration', 'declined');
+ $row = DB::table('desk_request_checkpoints')->first();
+ $this->assertStringNotContainsString('incomplete@', $row->snapshot);
+ $this->assertSame(app(VirtualDesk::class)->decode($before->payload), app(VirtualDesk::class)->decode($row->snapshot)['base_payload']);
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $this->id)->first());
+ $this->assertSame($events, DB::table('desk_events')->count());
+ $this->assertSame($notifications, DB::table('desk_notifications')->count());
+ $this->assertDatabaseCount('desk_revisions', 0);
+ $audit = DB::table('audit_events')->where('action', 'draft_checkpoint_saved')->first();
+ $this->assertSame(['version' => 1, 'request_version' => 1], json_decode($audit->after_data, true));
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => [...$this->answers(), ...$payload], 'submit' => true, 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors(['payload.email', 'payload.amount']);
+ }
+
+ public function test_attempt_retry_is_idempotent_but_changed_body_reused_key_and_stale_version_conflict(): void
+ {
+ $input = $this->input(['title' => 'SYNTHETIC one']);
+ $this->postJson($this->url(), $input)->assertOk();
+ $row = DB::table('desk_request_checkpoints')->first();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('checkpoint.version', 1);
+ $this->assertEquals($row, DB::table('desk_request_checkpoints')->first());
+ $this->postJson($this->url(), [...$input, 'payload' => ['title' => 'SYNTHETIC changed key']])->assertConflict();
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC other tab']))->assertConflict();
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC fresh'], 1))->assertOk()->assertJsonPath('checkpoint.version', 2);
+ $this->assertSame(2, DB::table('audit_events')->where('action', 'draft_checkpoint_saved')->count());
+ }
+
+ public function test_stale_main_version_is_exposed_for_comparison_and_cannot_be_silently_overwritten(): void
+ {
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC pending']))->assertOk();
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => ['title' => 'SYNTHETIC manually changed']])->assertOk();
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC stale'], 1))->assertConflict();
+ $this->getJson($this->url())->assertOk()->assertJsonPath('request.version', 2)->assertJsonPath('request.payload.title', 'SYNTHETIC manually changed')->assertJsonPath('checkpoint.request_version', 1)->assertJsonPath('checkpoint.payload.title', 'SYNTHETIC pending');
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC deliberately recovered'], 1, 2))->assertOk()->assertJsonPath('checkpoint.base_payload.title', 'SYNTHETIC manually changed');
+ $this->assertSame('SYNTHETIC manually changed', app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $this->id)->value('payload'))['title']);
+ }
+
+ public function test_checkpoint_route_cannot_submit_accept_arbitrary_keys_or_forged_baseline_and_still_bounds_types(): void
+ {
+ foreach ([['submit' => true], ['consent' => true], ['base_payload' => []], ['field_declarations' => []]] as $extra) {
+ $this->postJson($this->url(), [...$this->input(), ...$extra])->assertUnprocessable();
+ }
+ foreach ([['unknown' => 'SYNTHETIC'], ['choices' => ['absent']], ['choices' => [0]], ['declaration' => true], ['email' => ['nested']], ['amount' => false], ['amount' => str_repeat('1', 1001)]] as $payload) {
+ $this->postJson($this->url(), $this->input($payload))->assertUnprocessable();
+ }
+ $this->postJson($this->url(), [...$this->input(), 'edited_keys' => ['unknown']])->assertUnprocessable();
+ $this->assertDatabaseCount('desk_request_checkpoints', 0);
+ $this->postJson($this->url(), $this->input())->assertOk()->assertJsonPath('checkpoint.payload', []);
+ }
+
+ public function test_server_derives_edit_intent_and_conserves_deliberate_clear_and_zero(): void
+ {
+ $this->postJson($this->url(), [...$this->input(['title' => 'SYNTHETIC changed', 'amount' => 0]), 'edited_keys' => []])->assertOk()->assertJsonPath('checkpoint.edited_keys', ['title', 'description', 'regime', 'amount']);
+ $this->postJson($this->url(), $this->input(['amount' => 0, 'choices' => [], 'declaration' => null], 1))->assertOk()->assertJsonPath('checkpoint.payload.amount', 0)->assertJsonPath('checkpoint.payload.choices', [])->assertJsonPath('checkpoint.payload.declaration', null);
+ }
+
+ public function test_manager_and_unrelated_user_cannot_read_or_write_private_recovery(): void
+ {
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC private recovery']))->assertOk();
+ foreach ([$this->manager, User::factory()->create()] as $actor) {
+ $this->actingAs($actor)->getJson($this->url())->assertForbidden()->assertDontSee('SYNTHETIC private recovery');
+ $this->postJson($this->url(), $this->input())->assertForbidden();
+ }
+ $this->assertDatabaseCount('desk_request_checkpoints', 1);
+ }
+
+ public function test_submitted_and_closed_requests_reject_checkpoint_writes_and_do_not_create_a_declaration_snapshot_from_recovery(): void
+ {
+ $this->postJson($this->url(), $this->input(['declaration' => 'accepted']))->assertOk();
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => $this->answers(), 'submit' => true, 'consent' => true])->assertOk();
+ $row = DB::table('desk_requests')->where('id', $this->id)->first();
+ $this->postJson($this->url(), $this->input(['declaration' => 'accepted'], 1, 2))->assertConflict();
+ $this->getJson($this->url())->assertOk()->assertJsonPath('request.can_edit', false);
+ $this->assertSame([], app(VirtualDesk::class)->decode($row->submitted_snapshot)['field_declarations']);
+ $this->assertArrayNotHasKey('declaration', app(VirtualDesk::class)->decode($row->submitted_snapshot)['payload']);
+ $this->assertEquals($row, DB::table('desk_requests')->where('id', $this->id)->first());
+ }
+
+ public function test_returned_scope_is_enforced_for_both_values_and_claimed_intent(): void
+ {
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => $this->answers(), 'submit' => true, 'consent' => true])->assertOk();
+ app(VirtualDesk::class)->transition($this->manager, $this->id, ['version' => 2, 'status' => 'returned', 'reason' => 'SYNTHETIC description only', 'editable_fields' => ['description']]);
+ $this->postJson($this->url(), $this->input([...$this->answers(), 'description' => 'SYNTHETIC revised'], 0, 3))->assertUnprocessable();
+ $data = [...$this->input([...$this->answers(), 'description' => 'SYNTHETIC revised'], 0, 3), 'edited_keys' => ['description']];
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('checkpoint.edited_keys', ['description']);
+ $this->postJson($this->url(), [...$data, 'version' => 1, 'operation_key' => (string) Str::uuid(), 'payload' => [...$this->answers(), 'title' => 'SYNTHETIC forbidden']])->assertUnprocessable();
+ }
+
+ public function test_missing_migration_keeps_manual_route_available_and_rollback_refuses_retained_drafts(): void
+ {
+ Schema::rename('desk_request_checkpoints', 'desk_request_checkpoints_qa_absent');
+ try {
+ $this->getJson($this->url())->assertOk()->assertJsonPath('installed', false);
+ $this->postJson($this->url(), $this->input())->assertConflict();
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => []])->assertOk();
+ } finally {
+ Schema::rename('desk_request_checkpoints_qa_absent', 'desk_request_checkpoints');
+ }
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC preserved'], 0, 2))->assertOk();
+ $migration = require database_path('migrations/2026_11_03_040000_create_desk_request_checkpoints.php');
+ try {
+ $migration->down();
+ $this->fail('Rollback must not remove retained drafts.');
+ } catch (\RuntimeException $error) {
+ $this->assertStringContainsString('Preserve', $error->getMessage());
+ }
+ $this->assertDatabaseCount('desk_request_checkpoints', 1);
+ }
+
+ public function test_organisation_recovery_is_private_per_actor_and_revoked_or_read_only_members_have_no_access(): void
+ {
+ $org = (string) Str::uuid();
+ $officer = User::factory()->create();
+ $reader = User::factory()->create();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC checkpoint org', 'organization_type' => 'private']);
+ foreach ([[$this->owner, 'admin'], [$officer, 'officer'], [$reader, 'viewer']] as [$actor,$role]) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $actor->id, 'role' => $role]);
+ }
+ $caseId = DB::table('desk_requests')->where('id', $this->id)->value('case_id');
+ DB::table('desk_cases')->where('id', $caseId)->update(['organization_id' => $org]);
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC owner only']))->assertOk();
+ $this->actingAs($officer)->getJson($this->url())->assertOk()->assertJsonPath('checkpoint', null)->assertDontSee('SYNTHETIC owner only');
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC officer only']))->assertOk();
+ $this->actingAs($this->owner)->getJson($this->url())->assertOk()->assertJsonPath('checkpoint.payload.title', 'SYNTHETIC owner only');
+ $this->actingAs($reader)->getJson($this->url())->assertForbidden();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $officer->id)->update(['deleted_at' => now()]);
+ $this->actingAs($officer)->getJson($this->url())->assertForbidden()->assertDontSee('SYNTHETIC officer only');
+ $this->postJson($this->url(), $this->input([], 1))->assertForbidden();
+ $this->assertDatabaseCount('desk_request_checkpoints', 2);
+ }
+
+ public function test_closed_dossier_does_not_accept_checkpoint_even_when_request_is_still_a_draft(): void
+ {
+ $caseId = DB::table('desk_requests')->where('id', $this->id)->value('case_id');
+ DB::table('desk_cases')->where('id', $caseId)->update(['closed_at' => now()]);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('request.can_edit', false);
+ $this->postJson($this->url(), $this->input(['title' => 'SYNTHETIC forbidden']))->assertConflict();
+ $this->putJson('/balcao-virtual/pedidos/'.$this->id, ['version' => 1, 'payload' => []])->assertConflict();
+ $this->assertSame(1, DB::table('desk_requests')->where('id', $this->id)->value('version'));
+ $this->assertDatabaseCount('desk_request_checkpoints', 0);
+ }
+}
diff --git a/tests/Feature/DeskServiceEffectiveDatesTest.php b/tests/Feature/DeskServiceEffectiveDatesTest.php
new file mode 100644
index 00000000..7f0ff57e
--- /dev/null
+++ b/tests/Feature/DeskServiceEffectiveDatesTest.php
@@ -0,0 +1,198 @@
+withoutVite();
+ $this->travelTo(CarbonImmutable::parse('2026-11-02 10:00:00', 'UTC'));
+ $this->manager = User::factory()->create();
+ $this->investor = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email]]);
+ }
+
+ protected function tearDown(): void
+ {
+ $this->travelBack();
+ parent::tearDown();
+ }
+
+ private function input(int $base, string $title, ?string $date = null): array
+ {
+ $definition = config('virtual-desk.services.project-change');
+ $definition['title'] = $title;
+
+ return ['base_version' => $base, 'definition' => $definition, 'confirm' => true,
+ 'reason' => 'SYNTHETIC QA edition date; not an actual service publication.', 'effective_from' => $date];
+ }
+
+ private function publish(int $base, string $title, ?string $date = null): string
+ {
+ return $this->actingAs($this->manager)->putJson($this->url, $this->input($base, $title, $date))->assertCreated()->json('id');
+ }
+
+ private function dossier(): string
+ {
+ return $this->actingAs($this->investor)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC dated forms', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ public function test_only_started_edition_is_offered_and_forged_stale_or_future_selection_never_creates_a_request(): void
+ {
+ $v1 = $this->publish(0, 'SYNTHETIC current edition');
+ $case = $this->dossier();
+ $key = (string) Str::uuid();
+ $request = $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v1, 'client_key' => $key])->assertCreated()->json('id');
+ $before = DB::table('desk_requests')->where('id', $request)->first();
+ $v2 = $this->publish(1, 'SYNTHETIC future edition', '2026-11-03');
+ $this->actingAs($this->investor)->getJson('/balcao-virtual/servicos')->assertOk()->assertJsonPath('services.0.id', $v1)->assertDontSee('SYNTHETIC future edition');
+ $this->getJson('/balcao-virtual/dossiers/'.$case)->assertOk()->assertJsonPath('services.0.id', $v1);
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v2, 'client_key' => (string) Str::uuid()])->assertUnprocessable()->assertJsonValidationErrors('service_version_id');
+ $this->assertDatabaseCount('desk_requests', 1);
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 00:00:00', 'UTC'));
+ $this->getJson('/balcao-virtual/servicos')->assertOk()->assertJsonPath('services.0.id', $v2)->assertJsonPath('services.0.effective_from', '2026-11-03');
+ $this->getJson('/balcao-virtual/dossiers/'.$case)->assertOk()->assertJsonPath('services.0.id', $v2);
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v1, 'client_key' => $key])->assertCreated()->assertJsonPath('id', $request);
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v1, 'client_key' => (string) Str::uuid()])->assertUnprocessable()->assertJsonValidationErrors('service_version_id');
+ $this->getJson('/balcao-virtual/pedidos/'.$request)->assertOk()->assertJsonPath('definition.title', 'SYNTHETIC current edition')->assertJsonPath('serviceEffectiveFrom', '2026-11-02');
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $request)->first());
+ $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v2, 'client_key' => (string) Str::uuid()])->assertCreated();
+ }
+
+ public function test_immediate_correction_does_not_cancel_later_schedule_and_same_date_uses_highest_version(): void
+ {
+ $this->publish(0, 'SYNTHETIC initial');
+ $v2 = $this->publish(1, 'SYNTHETIC scheduled', '2026-11-12');
+ $v3 = $this->publish(2, 'SYNTHETIC correction', '2026-11-02');
+ $this->assertSame($v3, app(DeskServiceAvailability::class)->current()->first()->id);
+ $this->getJson('/management/balcao/servicos')->assertOk()->assertJsonPath('services.1.upcoming.0.version', 2);
+ $v4 = $this->publish(3, 'SYNTHETIC scheduled correction', '2026-11-12');
+ $this->getJson('/management/balcao/servicos')->assertOk()->assertJsonPath('services.1.activeVersion', 3)->assertJsonCount(1, 'services.1.upcoming')->assertJsonPath('services.1.upcoming.0.version', 4);
+ $this->travelTo(CarbonImmutable::parse('2026-11-12 00:00:00', 'UTC'));
+ $this->assertSame($v4, app(DeskServiceAvailability::class)->current()->first()->id);
+ $this->assertNotSame($v2, $v4);
+ $this->getJson('/management/balcao/servicos/project-change/versoes')->assertOk()->assertJsonPath('data.0.effective_from', '2026-11-12');
+ $this->assertDatabaseCount('desk_service_versions', 4);
+ }
+
+ public function test_scheduling_without_question_changes_is_a_new_edition_and_retries_keep_original_authorship_after_date_passes(): void
+ {
+ $this->publish(0, 'SYNTHETIC unchanged definition');
+ $v2 = $this->publish(1, 'SYNTHETIC unchanged definition', '2026-11-05');
+ $before = DB::table('desk_service_versions')->where('id', $v2)->first();
+ $this->actingAs($this->manager)->putJson($this->url, $this->input(1, 'SYNTHETIC unchanged definition'))->assertConflict();
+ $this->travelTo(CarbonImmutable::parse('2026-11-06 10:00:00', 'UTC'));
+ $this->actingAs($this->manager)->putJson($this->url, $this->input(1, 'SYNTHETIC unchanged definition', '2026-11-05'))->assertCreated()->assertJsonPath('id', $v2);
+ $this->assertEquals($before, DB::table('desk_service_versions')->where('id', $v2)->first());
+ $this->assertDatabaseCount('desk_service_versions', 2);
+ $this->assertSame(2, DB::table('audit_events')->where('action', 'service_definition_version_published')->count());
+ $this->putJson($this->url, $this->input(2, 'SYNTHETIC new backdated edition', '2026-11-05'))->assertUnprocessable()->assertJsonValidationErrors('effective_from');
+ }
+
+ public function test_invalid_dates_and_unprivileged_publication_are_rejected_without_changing_versions(): void
+ {
+ $this->actingAs($this->investor)->putJson($this->url, $this->input(0, 'SYNTHETIC denied', '2026-11-03'))->assertForbidden();
+ foreach (['2026-11-01', '2026-02-30', 'tomorrow', '2026-11-03T10:00:00Z'] as $date) {
+ $this->actingAs($this->manager)->putJson($this->url, $this->input(0, 'SYNTHETIC invalid', $date))->assertUnprocessable()->assertJsonValidationErrors('effective_from');
+ }
+ $this->assertDatabaseCount('desk_service_versions', 0);
+ }
+
+ public function test_existing_submitted_answers_and_definition_remain_intact_when_new_date_starts(): void
+ {
+ $v1 = $this->publish(0, 'SYNTHETIC submission edition');
+ $case = $this->dossier();
+ $request = $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v1, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ $answers = ['title' => 'SYNTHETIC actual answers', 'description' => 'SYNTHETIC reserved preparation description', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC change'];
+ $this->putJson('/balcao-virtual/pedidos/'.$request, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertOk();
+ $before = DB::table('desk_requests')->where('id', $request)->first();
+ $input = $this->input(1, 'SYNTHETIC new required question', '2026-11-03');
+ $input['definition']['fields']['new_evidence'] = ['label' => 'SYNTHETIC new evidence', 'type' => 'text', 'required' => true];
+ $v2 = $this->actingAs($this->manager)->putJson($this->url, $input)->assertCreated()->json('id');
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 10:00:00', 'UTC'));
+ $this->actingAs($this->investor)->getJson('/balcao-virtual/pedidos/'.$request)->assertOk()->assertJsonMissingPath('definition.fields.new_evidence');
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $request)->first());
+ $next = $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $v2, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ $this->putJson('/balcao-virtual/pedidos/'.$next, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors('payload.new_evidence');
+ $this->getJson('/balcao-virtual/pedidos/'.$request.'/recibo')->assertOk();
+ }
+
+ public function test_legacy_undated_versions_still_work_and_scheduling_requires_migration_without_rewriting_legacy_rows(): void
+ {
+ $migration = require database_path('migrations/2026_11_03_010000_desk_service_effective_dates.php');
+ $migration->down();
+ $this->assertFalse(Schema::hasColumn('desk_service_versions', 'effective_from'));
+ $v1 = $this->publish(0, 'SYNTHETIC legacy edition');
+ $before = DB::table('desk_service_versions')->where('id', $v1)->first();
+ $this->putJson($this->url, $this->input(1, 'SYNTHETIC unsupported scheduling', '2026-11-03'))->assertUnprocessable()->assertJsonValidationErrors('effective_from');
+ $this->assertSame($v1, app(DeskServiceAvailability::class)->current()->first()->id);
+ $migration->up();
+ $this->assertSame($before->definition, DB::table('desk_service_versions')->where('id', $v1)->value('definition'));
+ $this->assertNull(DB::table('desk_service_versions')->where('id', $v1)->value('effective_from'));
+ $this->publish(1, 'SYNTHETIC scheduled after legacy', '2026-11-03');
+ $this->assertSame($v1, app(DeskServiceAvailability::class)->current()->first()->id);
+ $this->expectException(\RuntimeException::class);
+ $migration->down();
+ }
+
+ public function test_investor_path_uses_the_same_dated_edition_as_the_catalogue(): void
+ {
+ config(['investor-path.enabled' => true, 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false]);
+ $v1 = $this->publish(0, 'SYNTHETIC path current');
+ $v2 = $this->publish(1, 'SYNTHETIC path future', '2026-11-03');
+ $id = $this->actingAs($this->investor)->postJson('/investimentos', ['title' => 'SYNTHETIC dated path', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ $this->getJson('/investimentos/'.$id)->assertOk()->assertJsonPath('services.0.id', $v1);
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 10:00:00', 'UTC'));
+ $this->getJson('/investimentos/'.$id)->assertOk()->assertJsonPath('services.0.id', $v2)->assertJsonPath('services.0.effective_from', '2026-11-03');
+ }
+
+ public function test_immediate_retry_retains_original_start_date_after_midnight(): void
+ {
+ $v1 = $this->publish(0, 'SYNTHETIC immediate retry');
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 10:00:00', 'UTC'));
+ $this->actingAs($this->manager)->putJson($this->url, $this->input(0, 'SYNTHETIC immediate retry'))->assertCreated()
+ ->assertJsonPath('id', $v1)->assertJsonPath('effective_from', '2026-11-02');
+ $this->assertDatabaseCount('desk_service_versions', 1);
+ $this->assertSame(1, DB::table('audit_events')->where('action', 'service_definition_version_published')->count());
+ }
+
+ public function test_initial_template_publication_also_records_the_immediate_date_and_retains_legacy_retry(): void
+ {
+ $input = ['code' => 'project-preparation', 'confirm' => true];
+ $id = $this->actingAs($this->manager)->postJson('/management/balcao/servicos', $input)->assertCreated()->json('id');
+ $this->assertSame('2026-11-02', DB::table('desk_service_versions')->where('id', $id)->value('effective_from'));
+ $this->assertSame($id, app(DeskServiceAvailability::class)->current()->first()->id);
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 10:00:00', 'UTC'));
+ $this->postJson('/management/balcao/servicos', $input)->assertCreated()->assertJsonPath('id', $id);
+ $this->assertDatabaseCount('desk_service_versions', 1);
+ $this->assertSame('2026-11-02', DB::table('desk_service_versions')->where('id', $id)->value('effective_from'));
+ }
+
+ public function test_calendar_change_alone_does_not_create_a_duplicate_unchanged_publication(): void
+ {
+ $this->publish(0, 'SYNTHETIC same form');
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 10:00:00', 'UTC'));
+ $this->actingAs($this->manager)->putJson($this->url, $this->input(1, 'SYNTHETIC same form'))->assertUnprocessable()->assertJsonValidationErrors('definition');
+ $this->assertDatabaseCount('desk_service_versions', 1);
+ $this->putJson($this->url, $this->input(1, 'SYNTHETIC same form', '2026-11-03'))->assertCreated()->assertJsonPath('version', 2);
+ }
+}
diff --git a/tests/Feature/DeskTypedFieldsTest.php b/tests/Feature/DeskTypedFieldsTest.php
new file mode 100644
index 00000000..c5743fa6
--- /dev/null
+++ b/tests/Feature/DeskTypedFieldsTest.php
@@ -0,0 +1,247 @@
+withoutVite();
+ $this->manager = User::factory()->create();
+ $this->investor = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email]]);
+ }
+
+ private function fields(): array
+ {
+ return [
+ 'branch' => ['label' => 'SYNTHETIC branch', 'type' => 'select', 'required' => false, 'options' => ['on' => 'Open', 'off' => 'Closed']],
+ 'activities' => ['label' => 'SYNTHETIC activities', 'type' => 'multiselect', 'required' => true, 'options' => ['0' => 'Synthetic zero', 'cotton' => 'Synthetic cotton', 'other' => 'Synthetic other'], 'when' => ['field' => 'branch', 'equals' => 'on']],
+ 'declaration' => ['label' => 'SYNTHETIC declaration', 'type' => 'consent', 'required' => true, 'statement' => 'SYNTHETIC statement — no real authorisation.', 'when' => ['field' => 'activities', 'operator' => 'contains', 'equals' => 'cotton']],
+ 'explanation' => ['label' => 'SYNTHETIC refusal explanation', 'type' => 'textarea', 'required' => true, 'when' => ['field' => 'declaration', 'equals' => 'declined']],
+ ];
+ }
+
+ private function input(int $base = 0): array
+ {
+ $definition = config('virtual-desk.services.project-change');
+ $definition['fields'] = [...$definition['fields'], ...$this->fields()];
+
+ return ['base_version' => $base, 'definition' => $definition, 'confirm' => true, 'reason' => 'SYNTHETIC typed fields QA; no actual service publication.'];
+ }
+
+ private function requestId(?array $input = null): string
+ {
+ $edition = $this->actingAs($this->manager)->putJson($this->editorUrl, $input ?? $this->input())->assertCreated()->json('id');
+ $case = $this->actingAs($this->investor)->postJson('/balcao-virtual/dossiers', ['title' => 'SYNTHETIC typed forms', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+
+ return $this->postJson('/balcao-virtual/dossiers/'.$case.'/pedidos', ['service_version_id' => $edition, 'client_key' => (string) Str::uuid()])->assertCreated()->json('id');
+ }
+
+ private function answers(): array
+ {
+ return ['title' => 'SYNTHETIC typed answers', 'description' => 'SYNTHETIC reserved private description', 'original_reference' => 'SYNTHETIC-REF', 'change_reason' => 'SYNTHETIC change', 'branch' => 'on', 'activities' => ['cotton', '0'], 'declaration' => 'declined', 'explanation' => 'SYNTHETIC explicit refusal'];
+ }
+
+ public function test_empty_drafts_are_valid_but_submission_requires_applicable_answers_and_global_consent(): void
+ {
+ $id = $this->requestId();
+ $url = '/balcao-virtual/pedidos/'.$id;
+ $this->putJson($url, ['version' => 1])->assertUnprocessable()->assertJsonValidationErrors('payload');
+ $this->putJson($url, ['version' => 1, 'payload' => []])->assertOk()->assertJsonPath('version', 2);
+ $this->putJson($url, ['version' => 2, 'payload' => [], 'submit' => true, 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors(['payload.title', 'payload.description']);
+ $answers = $this->answers();
+ unset($answers['declaration']);
+ $this->putJson($url, ['version' => 2, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertUnprocessable()->assertJsonValidationErrors('payload.declaration');
+ $this->putJson($url, ['version' => 2, 'payload' => $this->answers(), 'submit' => true, 'consent' => false])->assertUnprocessable()->assertJsonValidationErrors('consent');
+ $this->assertSame([], app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $id)->value('submitted_snapshot')));
+ }
+
+ public function test_multiple_answers_are_strict_distinct_lists_of_declared_string_codes(): void
+ {
+ $id = $this->requestId();
+ foreach ([['cotton', 'cotton'], ['missing'], [0], 'cotton', ['wrong' => 'cotton'], [['cotton']]] as $value) {
+ $response = $this->putJson('/balcao-virtual/pedidos/'.$id, ['version' => 1, 'payload' => ['activities' => $value]]);
+ $response->assertUnprocessable();
+ $this->assertNotEmpty(array_filter(array_keys($response->json('errors')), fn ($key) => str_starts_with($key, 'payload.activities')));
+ }
+ $this->putJson('/balcao-virtual/pedidos/'.$id, ['version' => 1, 'payload' => ['activities' => ['cotton', '0']]])->assertOk();
+ $this->assertSame(['0', 'cotton'], app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $id)->value('payload'))['activities']);
+ }
+
+ public function test_required_multiselect_is_not_satisfied_by_empty_or_null_and_declaration_never_accepts_boolean(): void
+ {
+ $desk = app(VirtualDesk::class);
+ foreach ([[], null] as $answer) {
+ try {
+ $desk->validateFields(['branch' => 'on', 'activities' => $answer], ['fields' => $this->fields()], true);
+ $this->fail('An applicable required choice cannot be empty.');
+ } catch (ValidationException $error) {
+ $this->assertArrayHasKey('payload.activities', $error->errors());
+ }
+ }
+ foreach ([true, false, 'yes', 1] as $answer) {
+ try {
+ $desk->validateFields(['branch' => 'on', 'activities' => ['cotton'], 'declaration' => $answer], ['fields' => $this->fields()], true);
+ $this->fail('An explicit declaration choice is required.');
+ } catch (ValidationException $error) {
+ $this->assertArrayHasKey('payload.declaration', $error->errors());
+ }
+ }
+ }
+
+ public function test_ancestor_conditions_preserve_hidden_answers_without_activating_descendants(): void
+ {
+ $desk = app(VirtualDesk::class);
+ $payload = ['branch' => 'off', 'activities' => ['cotton'], 'declaration' => 'declined'];
+ $definition = ['fields' => $this->fields()];
+ $this->assertSame($payload, $desk->validateFields($payload, $definition, true));
+ $this->assertSame(['branch'], array_keys($desk->applicableFields($payload, $definition)));
+ $payload['branch'] = 'on';
+ try {
+ $desk->validateFields($payload, $definition, true);
+ $this->fail('Opening ancestors must require the refusal explanation.');
+ } catch (ValidationException $error) {
+ $this->assertArrayHasKey('payload.explanation', $error->errors());
+ }
+ $payload['explanation'] = 'SYNTHETIC saved refusal';
+ $this->assertSame($payload, $desk->validateFields($payload, $definition, true));
+ $this->assertCount(4, $desk->applicableFields($payload, $definition));
+ }
+
+ public function test_zero_choice_is_a_real_answer_and_optional_declaration_can_remain_unanswered(): void
+ {
+ $desk = app(VirtualDesk::class);
+ $fields = $this->fields();
+ $payload = ['branch' => 'on', 'activities' => ['0']];
+ $this->assertSame($payload, $desk->validateFields($payload, ['fields' => $fields], true));
+ $fields['declaration']['required'] = false;
+ $payload = ['branch' => 'on', 'activities' => ['cotton'], 'declaration' => null];
+ $this->assertSame($payload, $desk->validateFields($payload, ['fields' => $fields], true));
+ $this->assertArrayNotHasKey('explanation', $desk->applicableFields($payload, ['fields' => $fields]));
+ $payload['declaration'] = 'accepted';
+ $this->assertSame($payload, $desk->validateFields($payload, ['fields' => $fields], true));
+ }
+
+ public function test_location_source_must_cover_the_multiple_choice_condition_of_its_location(): void
+ {
+ $input = $this->input();
+ $input['definition']['fields']['territory_id']['when'] = ['field' => 'activities', 'operator' => 'contains', 'equals' => 'cotton'];
+ $input['definition']['fields']['location_source']['when'] = ['field' => 'activities', 'operator' => 'contains', 'equals' => 'other'];
+ $this->actingAs($this->manager)->putJson($this->editorUrl, $input)->assertUnprocessable()->assertJsonValidationErrors('definition.fields.location_source.when');
+ $input['definition']['fields']['location_source']['when'] = $input['definition']['fields']['territory_id']['when'];
+ $this->putJson($this->editorUrl, $input)->assertCreated();
+ }
+
+ public function test_refusal_is_a_valid_answer_snapshot_is_server_bound_and_reordered_retry_is_idempotent(): void
+ {
+ $id = $this->requestId();
+ $answers = $this->answers();
+ $url = '/balcao-virtual/pedidos/'.$id;
+ $this->putJson($url, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true, 'field_declarations' => ['forged' => 'accepted']])->assertOk()->assertJsonPath('status', 'submitted');
+ $row = DB::table('desk_requests')->where('id', $id)->first();
+ $snapshot = app(VirtualDesk::class)->decode($row->submitted_snapshot);
+ $declaration = $snapshot['field_declarations']['declaration'];
+ $this->assertSame('declined', $declaration['answer']);
+ $this->assertSame($this->investor->id, $declaration['actor_id']);
+ $this->assertSame($row->service_version_id, $declaration['service_version_id']);
+ $this->assertSame($this->fields()['declaration']['statement'], $declaration['statement']);
+ $this->assertSame(hash('sha256', $declaration['statement']), $declaration['statement_sha256']);
+ $this->assertNotEmpty($declaration['declared_at']);
+ $this->assertSame(['declaration'], array_keys($snapshot['field_declarations']));
+ $answers['activities'] = ['0', 'cotton'];
+ $this->putJson($url, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertOk();
+ $this->assertEquals($row, DB::table('desk_requests')->where('id', $id)->first());
+ $this->assertSame(1, DB::table('desk_events')->where('request_id', $id)->where('action', 'submitted')->count());
+ $this->get($url.'/recibo?format=html')->assertOk()->assertSee('Synthetic zero · Synthetic cotton')->assertSee('Recusado')->assertSee($declaration['statement'])->assertDontSee('', false);
+ $this->actingAs(User::factory()->create())->get($url.'/recibo?format=html')->assertForbidden();
+ }
+
+ public function test_inactive_declarations_remain_answers_but_are_not_recorded_as_active_consent(): void
+ {
+ $id = $this->requestId();
+ $answers = [...$this->answers(), 'branch' => 'off', 'declaration' => 'accepted'];
+ $this->putJson('/balcao-virtual/pedidos/'.$id, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertOk();
+ $snapshot = app(VirtualDesk::class)->decode(DB::table('desk_requests')->where('id', $id)->value('submitted_snapshot'));
+ $this->assertSame('accepted', $snapshot['payload']['declaration']);
+ $this->assertSame([], $snapshot['field_declarations']);
+ $this->get('/balcao-virtual/pedidos/'.$id.'/recibo?format=html')->assertOk()->assertSee('Respostas conservadas de perguntas não aplicáveis')->assertDontSee('Declarações registadas nesta submissão');
+ }
+
+ public function test_new_schema_does_not_rewrite_old_labels_options_declaration_or_receipt(): void
+ {
+ $id = $this->requestId();
+ $answers = [...$this->answers(), 'declaration' => 'accepted'];
+ $this->putJson('/balcao-virtual/pedidos/'.$id, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertOk();
+ $before = DB::table('desk_requests')->where('id', $id)->first();
+ $input = $this->input(1);
+ $input['definition']['fields']['activities']['options']['cotton'] = 'SYNTHETIC revised label';
+ $input['definition']['fields']['declaration']['statement'] = 'SYNTHETIC different future wording.';
+ $this->actingAs($this->manager)->putJson($this->editorUrl, $input)->assertCreated();
+ $this->actingAs($this->investor)->getJson('/balcao-virtual/pedidos/'.$id)->assertOk()->assertJsonPath('definition.fields.activities.options.cotton', 'Synthetic cotton')->assertJsonPath('definition.fields.declaration.statement', $this->fields()['declaration']['statement']);
+ $this->get('/balcao-virtual/pedidos/'.$id.'/recibo?format=html')->assertOk()->assertSee('Synthetic cotton')->assertDontSee('SYNTHETIC different future wording.');
+ $this->assertEquals($before, DB::table('desk_requests')->where('id', $id)->first());
+ }
+
+ public function test_publication_rejects_ambiguous_conditions_or_incomplete_typed_definitions(): void
+ {
+ $valid = $this->input();
+ $this->actingAs($this->investor)->putJson($this->editorUrl, $valid)->assertForbidden();
+ $mutations = [
+ fn ($fields) => array_replace_recursive($fields, ['declaration' => ['statement' => ' ']]),
+ function ($fields) {
+ unset($fields['declaration']['statement']);
+
+ return $fields;
+ },
+ fn ($fields) => array_replace_recursive($fields, ['branch' => ['statement' => 'SYNTHETIC invalid metadata']]),
+ function ($fields) {
+ $fields['activities']['options'] = [];
+
+ return $fields;
+ },
+ fn ($fields) => array_replace_recursive($fields, ['declaration' => ['when' => ['operator' => 'equals']]]),
+ fn ($fields) => array_replace_recursive($fields, ['activities' => ['when' => ['operator' => 'contains']]]),
+ fn ($fields) => array_replace_recursive($fields, ['declaration' => ['when' => ['equals' => 'absent']]]),
+ fn ($fields) => array_replace_recursive($fields, ['explanation' => ['when' => ['equals' => 'yes']]]),
+ fn ($fields) => array_replace_recursive($fields, ['branch' => ['when' => ['field' => 'explanation', 'equals' => 'cycle']]]),
+ ];
+ foreach ($mutations as $mutate) {
+ $input = $valid;
+ $input['definition']['fields'] = $mutate($input['definition']['fields']);
+ $this->actingAs($this->manager)->putJson($this->editorUrl, $input)->assertUnprocessable();
+ }
+ $this->assertDatabaseCount('desk_service_versions', 0);
+ $this->putJson($this->editorUrl, $valid)->assertCreated();
+ }
+
+ public function test_returned_requests_reuse_array_answers_without_granting_extra_edit_rights(): void
+ {
+ $id = $this->requestId();
+ $url = '/balcao-virtual/pedidos/'.$id;
+ $answers = $this->answers();
+ $this->putJson($url, ['version' => 1, 'payload' => $answers, 'submit' => true, 'consent' => true])->assertOk();
+ app(VirtualDesk::class)->transition($this->manager, $id, ['version' => 2, 'status' => 'returned', 'reason' => 'SYNTHETIC clarify explanation only', 'editable_fields' => ['explanation']]);
+ $answers['activities'] = ['other'];
+ $this->actingAs($this->investor)->putJson($url, ['version' => 3, 'payload' => $answers])->assertUnprocessable()->assertJsonValidationErrors('payload.activities');
+ $answers = [...$this->answers(), 'activities' => ['0', 'cotton'], 'explanation' => 'SYNTHETIC revised explanation'];
+ $this->putJson($url, ['version' => 3, 'payload' => $answers, 'submit' => true, 'consent' => true, 'reason' => 'SYNTHETIC correction'])->assertOk();
+ }
+}
diff --git a/tests/Feature/DocumentScanRetryTest.php b/tests/Feature/DocumentScanRetryTest.php
new file mode 100644
index 00000000..01251cf6
--- /dev/null
+++ b/tests/Feature/DocumentScanRetryTest.php
@@ -0,0 +1,204 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ Storage::fake('local');
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'portal.document_managers' => [], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->actingAs($this->manager);
+ $this->id = (string) Str::uuid();
+ $bytes = "%PDF-1.7\nSYNTHETIC retry document\n%%EOF";
+ $this->cipher = Crypt::encryptString($bytes);
+ Storage::disk('local')->put('opportunity-resources/'.$this->id, $this->cipher);
+ DB::table('documents')->insert(['id' => $this->id, 'source_system' => 'portal-services', 'file_name' => 'PRIVATE-synthetic.pdf', 'storage_key' => 'opportunity-resources/'.$this->id,
+ 'sha256' => hash('sha256', $bytes), 'size_bytes' => strlen($bytes), 'media_type' => 'application/pdf', 'status' => 'quarantined', 'data_classification' => 'restricted',
+ 'storage_encryption' => 'laravel', 'uploaded_by' => $this->manager->id, 'malware_scan_status' => 'inconclusive', 'malware_failure_reason' => 'scanner_unavailable']);
+ }
+
+ private function retry(): TestResponse
+ {
+ return $this->from('/management/portal')->post('/management/documents/'.$this->id.'/malware/retry');
+ }
+
+ private function document(): \stdClass
+ {
+ return DB::table('documents')->where('id', $this->id)->first();
+ }
+
+ private function assertOriginal(): void
+ {
+ $this->assertSame($this->cipher, Storage::disk('local')->get('opportunity-resources/'.$this->id));
+ $this->assertSame(1, DB::table('documents')->count());
+ }
+
+ public function test_http_retry_confirms_dispatch_acceptance_and_audits_the_existing_manager(): void
+ {
+ $this->retry()->assertRedirect('/management/portal')->assertSessionHas('success', fn ($value) => str_contains($value, 'aceite pelo serviço de envio'));
+ Queue::assertPushed(ScanDocumentForMalware::class, 1);
+ $this->assertSame('pending', $this->document()->malware_scan_status);
+ $this->assertSame('quarantined', $this->document()->status);
+ $event = DB::table('audit_events')->where('action', 'scan_retry_requested')->sole();
+ $this->assertSame($this->manager->id, $event->actor_user_id);
+ $data = json_decode($event->after_data, true);
+ $this->assertSame($this->id, $data['document_id']);
+ $this->assertTrue(Str::isUuid($data['reference']));
+ $this->assertStringNotContainsString('PRIVATE', $event->after_data);
+ $this->assertOriginal();
+ }
+
+ public function test_an_existing_unique_lease_neither_resets_failure_nor_claims_another_push(): void
+ {
+ $job = new ScanDocumentForMalware($this->id);
+ $this->assertTrue((new UniqueLock(app(Repository::class)))->acquire($job));
+ $before = $this->document();
+ $this->retry()->assertRedirect()->assertSessionMissing('success')->assertSessionHas('warning', fn ($value) => str_contains($value, 'reserva de análise'));
+ Queue::assertNothingPushed();
+ $this->assertEquals($before, $this->document());
+ $this->assertSame(0, DB::table('audit_events')->where('action', 'scan_retry_requested')->count());
+ $this->assertOriginal();
+ }
+
+ public function test_transport_failure_is_reported_as_uncertain_and_does_not_erase_the_original(): void
+ {
+ Bus::shouldReceive('dispatch')->once()->andThrow(new \RuntimeException('PRIVATE queue password and SQL'));
+ $this->retry()->assertRedirect()->assertSessionMissing('success')->assertSessionHas('warning', fn ($value) => str_contains($value, 'Não foi possível confirmar'));
+ $this->assertStringNotContainsString('PRIVATE', session('warning'));
+ $this->assertSame('failed', $this->document()->malware_scan_status);
+ $this->assertSame('quarantined', $this->document()->status);
+ $this->assertSame(0, DB::table('document_malware_scans')->count());
+ $this->assertNull(Context::getHidden('laravel_unique_job_key'));
+ $this->assertFalse((new UniqueLock(app(Repository::class)))->acquire(new ScanDocumentForMalware($this->id)));
+ $this->assertOriginal();
+ }
+
+ public function test_lost_acknowledgement_after_a_sync_clean_result_does_not_requarantine_it(): void
+ {
+ Bus::shouldReceive('dispatch')->once()->andReturnUsing(function ($job) {
+ $job->handle(new CleanScannerFixture);
+ throw new \RuntimeException('PRIVATE acknowledgement lost');
+ });
+ $this->retry()->assertRedirect()->assertSessionHas('warning')->assertSessionMissing('success');
+ $this->assertSame('clean', $this->document()->malware_scan_status);
+ $this->assertSame('active', $this->document()->status);
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertOriginal();
+ }
+
+ public function test_outer_rollback_discards_the_request_and_a_later_clean_result_blocks_a_stale_callback(): void
+ {
+ DB::beginTransaction();
+ $result = app(DocumentScanRetry::class)->request($this->manager, $this->id);
+ $this->assertSame('deferred', $result['outcome']);
+ DB::rollBack();
+ Queue::assertNothingPushed();
+ $this->assertSame('inconclusive', $this->document()->malware_scan_status);
+ DB::beginTransaction();
+ app(DocumentScanRetry::class)->request($this->manager, $this->id);
+ DB::table('documents')->where('id', $this->id)->update(['status' => 'active', 'malware_scan_status' => 'clean']);
+ DB::commit();
+ Queue::assertNothingPushed();
+ $this->assertSame('clean', $this->document()->malware_scan_status);
+ $this->assertTrue((new UniqueLock(app(Repository::class)))->acquire(new ScanDocumentForMalware($this->id)));
+ $this->assertSame(0, DB::table('audit_events')->where('action', 'scan_retry_requested')->count());
+ }
+
+ public function test_current_permission_is_rechecked_after_commit_before_any_scan_state_change(): void
+ {
+ DB::beginTransaction();
+ app(DocumentScanRetry::class)->request($this->manager, $this->id);
+ config(['portal.managers' => []]);
+ DB::commit();
+ Queue::assertNothingPushed();
+ $this->assertSame('inconclusive', $this->document()->malware_scan_status);
+ $this->assertSame(0, DB::table('audit_events')->where('action', 'scan_retry_requested')->count());
+ $this->assertTrue((new UniqueLock(app(Repository::class)))->acquire(new ScanDocumentForMalware($this->id)));
+ }
+
+ public function test_support_without_document_management_authority_cannot_request_a_scan(): void
+ {
+ $support = User::factory()->create();
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->manager, ['user_id' => $support->id, 'role' => 'technical_support', 'opportunity_types' => ['investment_project'], 'source' => 'synthetic-retry-support-fixture']);
+ $this->actingAs($support);
+ $this->retry()->assertForbidden();
+ Queue::assertNothingPushed();
+ $this->assertSame('inconclusive', $this->document()->malware_scan_status);
+ }
+
+ public function test_clean_infected_scanning_and_deleted_documents_are_not_reset_by_retry(): void
+ {
+ foreach (['clean', 'infected', 'scanning'] as $state) {
+ DB::table('documents')->where('id', $this->id)->update(['malware_scan_status' => $state]);
+ $this->retry()->assertStatus(422);
+ $this->assertSame($state, $this->document()->malware_scan_status);
+ }
+ DB::table('documents')->where('id', $this->id)->update(['status' => 'deleted', 'deleted_at' => now()]);
+ $this->retry()->assertNotFound();
+ Queue::assertNothingPushed();
+ }
+
+ public function test_different_documents_have_independent_delivery_leases_and_stale_preparation_can_be_retried(): void
+ {
+ $first = new ScanDocumentForMalware($this->id);
+ $delivery = app(DocumentScanDelivery::class);
+ $this->assertSame('stale', $delivery->dispatch($first, fn () => false));
+ $this->assertSame('accepted', $delivery->dispatch(new ScanDocumentForMalware($this->id)));
+ $this->assertSame('duplicate', $delivery->dispatch(new ScanDocumentForMalware($this->id)));
+ $this->assertSame('accepted', $delivery->dispatch(new ScanDocumentForMalware((string) Str::uuid())));
+ Queue::assertPushed(ScanDocumentForMalware::class, 2);
+ }
+
+ public function test_json_retry_has_no_redirect_and_distinguishes_duplicate_from_transport_failure(): void
+ {
+ $url = '/management/documents/'.$this->id.'/malware/retry';
+ $this->postJson($url)->assertOk()->assertJsonPath('outcome', 'accepted')->assertHeader('Cache-Control', 'no-store, private');
+ $this->postJson($url)->assertOk()->assertJsonPath('outcome', 'duplicate');
+ Queue::assertPushed(ScanDocumentForMalware::class, 1);
+ }
+
+ public function test_json_transport_failure_returns_only_a_safe_reference_with_the_uncertain_status(): void
+ {
+ Bus::shouldReceive('dispatch')->once()->andThrow(new \RuntimeException('PRIVATE transport payload'));
+ $response = $this->postJson('/management/documents/'.$this->id.'/malware/retry')->assertStatus(503)->assertJsonPath('outcome', 'unconfirmed');
+ $this->assertTrue(Str::isUuid($response->json('reference')));
+ $this->assertStringNotContainsString('PRIVATE', $response->getContent());
+ $this->assertSame('failed', $this->document()->malware_scan_status);
+ }
+}
diff --git a/tests/Feature/EducationDeclarationDraftsTest.php b/tests/Feature/EducationDeclarationDraftsTest.php
new file mode 100644
index 00000000..3f0c1a4c
--- /dev/null
+++ b/tests/Feature/EducationDeclarationDraftsTest.php
@@ -0,0 +1,136 @@
+withoutVite();
+ $this->owner = User::factory()->create();
+ config(['education.enabled' => true, 'portal.managers' => [$this->owner->email]]);
+ $this->actingAs($this->owner);
+ }
+
+ private function valid(string $kind = 'demands'): array
+ {
+ $province = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $province, 'name' => 'SYNTHETIC QA province', 'code' => $province, 'location_type' => 'province']);
+ $data = ['occupation_id' => Occupation::create(['code' => (string) Str::uuid(), 'name' => 'Synthetic occupation'])->id,
+ 'skill_id' => Skill::create(['code' => (string) Str::uuid(), 'name' => 'Synthetic skill'])->id, 'geo_location_id' => $province,
+ 'qualification' => 'Synthetic qualification', 'quantity' => 20, 'period_start' => today()->addMonth()->toDateString(),
+ 'period_end' => today()->addMonths(2)->toDateString(), 'source' => 'SENSITIVE SYNTHETIC QA SOURCE TEXT',
+ 'reference_date' => today()->toDateString(), 'valid_until' => today()->addYear()->toDateString()];
+ if ($kind === 'demands') {
+ return [...$data, 'employer' => 'SENSITIVE SYNTHETIC QA EMPLOYER', 'project_id' => Project::create(['code' => (string) Str::uuid(), 'name' => 'Synthetic project', 'status' => 'draft'])->id];
+ }
+ $provider = TrainingProvider::create(['name' => 'Synthetic provider', 'status' => 'candidate']);
+
+ return [...$data, 'course_id' => Course::create(['provider_id' => $provider->id, 'code' => (string) Str::uuid(), 'title' => 'Synthetic course', 'status' => 'draft'])->id];
+ }
+
+ private function create(string $kind, array $payload = []): array
+ {
+ $input = ['client_key' => (string) Str::uuid(), 'version_no' => 0, 'payload' => $payload];
+ $response = $this->postJson('/management/education/drafts/'.$kind, $input)->assertOk()->assertHeader('Cache-Control', 'no-store, private');
+
+ return [$response->json('id'), $input];
+ }
+
+ public function test_incomplete_drafts_are_private_encrypted_recoverable_and_repeated_requests_do_not_duplicate(): void
+ {
+ [$id, $input] = $this->create('demands', ['employer' => 'PRIVATE SYNTHETIC EMPLOYER']);
+ $this->postJson('/management/education/drafts/demands', $input)->assertOk()->assertJsonPath('version_no', 1)->assertJsonPath('id', $id);
+ $this->assertDatabaseCount('education_declaration_drafts', 1);
+ $this->assertDatabaseCount('labour_demands', 0);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', DB::table('education_declaration_drafts')->sole()->payload);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', DB::table('audit_events')->where('source_system', 'education-drafts')->first()->after_data);
+ $other = User::factory()->create();
+ config(['portal.managers' => [$this->owner->email, $other->email]]);
+ $this->actingAs($other)->getJson('/management/education/drafts/demands/'.$id)->assertNotFound();
+ $this->get('/management/education?draft='.$id)->assertNotFound();
+ $this->get('/management/education')->assertOk()->assertInertia(fn ($page) => $page->has('ownDrafts.data', 0)->where('selectedDraft', null));
+ $this->getJson('/management/education/drafts/demands')->assertOk()->assertJsonCount(0, 'data');
+ $this->putJson('/management/education/drafts/demands/'.$id, ['version_no' => 1, 'payload' => []])->assertNotFound();
+ $this->actingAs(User::findOrFail($this->owner->id))->getJson('/management/education/drafts/demands/'.$id)->assertOk()->assertJsonPath('payload.employer', 'PRIVATE SYNTHETIC EMPLOYER');
+ $this->get('/management/education?draft='.$id)->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertInertia(fn ($page) => $page->component('education/index')->where('selectedDraft.id', $id)
+ ->where('selectedDraft.payload.employer', 'PRIVATE SYNTHETIC EMPLOYER')->has('ownDrafts.data', 1)->missing('ownDrafts.data.0.payload'));
+ $this->actingAs(User::factory()->create())->postJson('/management/education/drafts/demands', $input)->assertForbidden();
+ }
+
+ public function test_stale_edits_and_wrong_kind_are_rejected_while_incomplete_submission_creates_nothing(): void
+ {
+ [$id, $input] = $this->create('demands');
+ $url = '/management/education/drafts/demands/'.$id;
+ $this->putJson($url, ['version_no' => 1, 'payload' => ['quantity' => 0]])->assertOk()->assertJsonPath('version_no', 2);
+ $this->putJson($url, ['version_no' => 1, 'payload' => ['quantity' => 0]])->assertOk()->assertJsonPath('version_no', 2);
+ $this->putJson($url, ['version_no' => 1, 'payload' => ['quantity' => 5]])->assertConflict();
+ $this->postJson('/management/education/drafts/capacities', $input)->assertConflict();
+ $this->getJson('/management/education/drafts/capacities/'.$id)->assertNotFound();
+ $this->putJson($url, ['version_no' => 2, 'payload' => ['status' => 'reviewed']])->assertUnprocessable();
+ $this->postJson($url.'/submit', ['version_no' => 2, 'payload' => ['quantity' => 0]])->assertUnprocessable();
+ $this->assertDatabaseCount('labour_demands', 0);
+ $this->getJson($url)->assertJsonPath('state', 'draft');
+ }
+
+ public function test_distinct_numeric_text_is_not_collapsed_and_rollback_preserves_drafts(): void
+ {
+ [$id] = $this->create('demands', ['employer' => '001']);
+ $this->putJson('/management/education/drafts/demands/'.$id, ['version_no' => 1, 'payload' => ['employer' => '1']])->assertOk()
+ ->assertJsonPath('version_no', 2)->assertJsonPath('payload.employer', '1');
+ $migration = require database_path('migrations/2026_11_02_230000_education_declaration_drafts.php');
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('Preserve education drafts');
+ $migration->down();
+ }
+
+ public function test_submission_is_single_preserves_snapshot_and_still_requires_independent_review(): void
+ {
+ $payload = $this->valid();
+ [$id] = $this->create('demands', ['employer' => $payload['employer']]);
+ $url = '/management/education/drafts/demands/'.$id;
+ $input = ['version_no' => 1, 'payload' => $payload];
+ $record = $this->postJson($url.'/submit', $input)->assertOk()->assertJsonPath('state', 'submitted')->json('record_id');
+ $this->postJson($url.'/submit', $input)->assertOk()->assertJsonPath('record_id', $record);
+ $this->assertDatabaseCount('labour_demands', 1);
+ $this->assertSame('submitted', DB::table('labour_demands')->sole()->status);
+ $this->postJson('/management/education/demands/'.$record.'/review', ['version_no' => 1, 'status' => 'reviewed', 'review_reason' => 'Synthetic self-review must be refused.'])->assertForbidden();
+ $this->putJson($url, ['version_no' => 2, 'payload' => $payload])->assertConflict();
+ $this->postJson($url.'/submit', [...$input, 'payload' => [...$payload, 'quantity' => 50]])->assertConflict();
+ Project::whereKey($payload['project_id'])->update(['name' => 'Changed synthetic project']);
+ $this->getJson($url)->assertJsonPath('references.project_id.name', 'Synthetic project')->assertJsonPath('payload.quantity', 20);
+ $this->get('/management/education?draft='.$id)->assertOk()->assertInertia(fn ($page) => $page->where('selectedDraft.state', 'submitted')
+ ->where('selectedDraft.references.project_id.name', 'Synthetic project')->where('ownDrafts.data.0.label', 'Synthetic qualification'));
+ }
+
+ public function test_capacity_reuses_final_validation_and_does_not_accept_employer_or_project_fields(): void
+ {
+ $payload = $this->valid('capacities');
+ [$id] = $this->create('capacities', [...$payload, 'employer' => 'NOT APPLICABLE', 'project_id' => 'not-applicable']);
+ $url = '/management/education/drafts/capacities/'.$id;
+ $this->getJson($url)->assertJsonMissingPath('payload.employer')->assertJsonMissingPath('payload.project_id');
+ Course::whereKey($payload['course_id'])->update(['status' => 'retired']);
+ $this->postJson($url.'/submit', ['version_no' => 1, 'payload' => $payload])->assertUnprocessable();
+ Course::whereKey($payload['course_id'])->update(['status' => 'draft']);
+ $this->postJson($url.'/submit', ['version_no' => 1, 'payload' => $payload])->assertOk()->assertJsonPath('state', 'submitted');
+ $this->assertDatabaseCount('training_capacities', 1);
+ $this->assertDatabaseCount('labour_demands', 0);
+ }
+}
diff --git a/tests/Feature/EducationWorkQueueTest.php b/tests/Feature/EducationWorkQueueTest.php
new file mode 100644
index 00000000..93b84346
--- /dev/null
+++ b/tests/Feature/EducationWorkQueueTest.php
@@ -0,0 +1,294 @@
+ */
+ private array $data;
+
+ private string $project;
+
+ private string $course;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+ $this->withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->manager = User::factory()->create(['name' => 'SYNTHETIC education manager']);
+ $this->other = User::factory()->create(['name' => 'SYNTHETIC other submitter']);
+ config(['education.enabled' => true, 'portal.managers' => [$this->manager->email, $this->other->email], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->actingAsWithMfa($this->manager);
+ $geo = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $geo, 'name' => 'SYNTHETIC province', 'code' => $geo, 'location_type' => 'province']);
+ $this->project = Project::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC project', 'status' => 'draft'])->id;
+ $provider = TrainingProvider::create(['name' => 'SYNTHETIC provider', 'status' => 'candidate']);
+ $this->course = Course::create(['provider_id' => $provider->id, 'code' => (string) Str::uuid(), 'title' => 'SYNTHETIC course', 'status' => 'draft'])->id;
+ $this->data = ['occupation_id' => Occupation::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC occupation'])->id,
+ 'skill_id' => Skill::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC skill'])->id, 'geo_location_id' => $geo, 'qualification' => 'SYNTHETIC qualification',
+ 'quantity' => 10, 'period_start' => today()->addMonth()->toDateString(), 'period_end' => today()->addMonths(3)->toDateString(), 'reference_date' => today()->subMonth()->toDateString(),
+ 'valid_until' => today()->addYear()->toDateString(), 'source' => 'PRIVATE SYNTHETIC EDUCATION SOURCE', 'status' => 'submitted'];
+ }
+
+ /** @param array $changes */
+ private function demand(User $actor, array $changes = []): LabourDemand
+ {
+ return LabourDemand::create([...$this->data, 'project_id' => $this->project, 'employer' => 'SYNTHETIC employer', 'submitted_by' => $actor->id, ...$changes])->fresh();
+ }
+
+ /** @param array $changes */
+ private function capacity(User $actor, array $changes = []): TrainingCapacity
+ {
+ return TrainingCapacity::create([...$this->data, 'course_id' => $this->course, 'submitted_by' => $actor->id, ...$changes])->fresh();
+ }
+
+ /** @return array{client_key:string,version_no:int,status:string,review_reason:string} */
+ private function decision(): array
+ {
+ return ['client_key' => (string) Str::uuid(), 'version_no' => 1, 'status' => 'reviewed', 'review_reason' => 'SYNTHETIC independent review with evidence.'];
+ }
+
+ public function test_personal_counts_include_legacy_declarations_and_separate_units_and_expiry(): void
+ {
+ $this->demand($this->manager, ['quantity' => 100]);
+ $this->demand($this->manager, ['status' => 'reviewed', 'reviewed_by' => $this->other->id, 'review_reason' => 'SYNTHETIC previous review']);
+ $this->demand($this->manager, ['valid_until' => today()->subDay()->toDateString()]);
+ $this->demand($this->other, ['quantity' => 500]);
+ $this->demand($this->other, ['valid_until' => today()->subDay()->toDateString()]);
+ $this->capacity($this->manager, ['quantity' => 700]);
+ $this->capacity($this->other, ['quantity' => 999]);
+ $this->demand($this->manager)->delete();
+ $this->get('/management/education?q=not-found')->assertOk()->assertInertia(fn (Assert $page) => $page->component('education/index')->has('demands.data', 0)
+ ->where('workQueue.actor_id', $this->manager->id)->where('workQueue.demands.total', 3)->where('workQueue.demands.submitted', 1)->where('workQueue.demands.reviewed', 1)
+ ->where('workQueue.demands.expired', 1)->where('workQueue.demands.to_review', 1)->where('workQueue.capacities.total', 1)->where('workQueue.capacities.to_review', 1));
+ }
+
+ public function test_mine_and_independent_review_scopes_do_not_mix_authors_or_expired_decisions(): void
+ {
+ $mine = $this->demand($this->manager);
+ $other = $this->demand($this->other);
+ $this->demand($this->other, ['valid_until' => today()->subDay()->toDateString()]);
+ $this->get('/management/education?scope=mine')->assertOk()->assertInertia(fn (Assert $page) => $page->has('demands.data', 1)->where('demands.data.0.id', $mine->id)
+ ->where('demands.data.0.can_review', false)->where('demands.data.0.review_unavailable', 'self'));
+ $this->get('/management/education?scope=review&status=reviewed')->assertOk()->assertInertia(fn (Assert $page) => $page->has('demands.data', 1)->where('demands.data.0.id', $other->id)
+ ->where('demands.data.0.can_review', true)->where('filters.scope', 'review')->missing('filters.status'));
+ }
+
+ public function test_personal_view_keeps_territorial_catalogue_evidence_from_other_submitters(): void
+ {
+ $this->capacity($this->other);
+ $this->get('/management/education?scope=mine&geo_location_id='.$this->data['geo_location_id'])->assertOk()->assertInertia(fn (Assert $page) => $page
+ ->has('capacities.data', 0)->has('providers', 1)->has('courses', 1)->where('courses.0.id', $this->course));
+ }
+
+ public function test_private_open_drafts_are_counted_without_counting_derived_submissions_twice(): void
+ {
+ $input = ['version_no' => 0, 'client_key' => (string) Str::uuid(), 'payload' => []];
+ $this->postJson('/management/education/drafts/demands', $input)->assertOk();
+ $this->demand($this->manager);
+ $payload = $this->data;
+ unset($payload['status']);
+ $payload = [...$payload, 'project_id' => $this->project, 'employer' => 'SYNTHETIC derived employer'];
+ $created = $this->postJson('/management/education/drafts/demands', [...$input, 'client_key' => (string) Str::uuid(), 'payload' => $payload])->assertOk()->json('id');
+ $this->postJson('/management/education/drafts/demands/'.$created.'/submit', ['version_no' => 1, 'payload' => $payload])->assertOk();
+ $this->postJson('/management/education/drafts/demands/'.$created.'/submit', ['version_no' => 1, 'payload' => $payload])->assertOk();
+ $this->actingAsWithMfa($this->other);
+ $this->postJson('/management/education/drafts/demands', [...$input, 'client_key' => (string) Str::uuid()])->assertOk();
+ $this->actingAsWithMfa($this->manager);
+ $this->get('/management/education')->assertInertia(fn (Assert $page) => $page->where('workQueue.drafts', 1)->where('workQueue.demands.total', 2)->has('ownDrafts.data', 2));
+ }
+
+ public function test_detail_preserves_filter_context_and_shows_current_capabilities_and_reference_names(): void
+ {
+ $record = $this->demand($this->other);
+ $this->get('/management/education/demands/'.$record->id.'?scope=review&q=SYNTHETIC&demand_page=2')->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertInertia(fn (Assert $page) => $page->component('education/declaration')->where('actorId', $this->manager->id)->where('declaration.can_review', true)
+ ->where('declaration.submitted_by_name', 'SYNTHETIC other submitter')->where('references.project', 'SYNTHETIC project')->where('references.location', 'SYNTHETIC province')
+ ->where('backUrl', function (string $url): bool {
+ parse_str(parse_url($url, PHP_URL_QUERY) ?? '', $query);
+
+ return str_starts_with($url, '/management/education?') && $query == ['scope' => 'review', 'q' => 'SYNTHETIC', 'demand_page' => '2'];
+ }));
+ }
+
+ public function test_same_decision_key_replays_without_another_decision_version_or_business_event(): void
+ {
+ $record = $this->demand($this->other);
+ $url = '/management/education/demands/'.$record->id.'/review';
+ $data = $this->decision();
+ $this->post($url, $data)->assertRedirect();
+ $events = DB::table('audit_events')->where('entity_type', 'labour_demands')->count();
+ $this->post($url, $data)->assertRedirect();
+ $this->assertSame(2, $record->fresh()->version_no);
+ $this->assertSame($events, DB::table('audit_events')->where('entity_type', 'labour_demands')->count());
+ $this->get('/management/education/demands/'.$record->id)->assertInertia(fn (Assert $page) => $page->has('declaration.review_context.commands', 1)
+ ->where('declaration.review_context.commands.0.key', $data['client_key'])->where('declaration.review_context.commands.0.version', 2)
+ ->missing('declaration.review_context.commands.0.hash'));
+ }
+
+ public function test_used_key_with_different_data_and_fresh_key_with_stale_version_are_rejected(): void
+ {
+ $record = $this->capacity($this->other);
+ $url = '/management/education/capacities/'.$record->id.'/review';
+ $data = $this->decision();
+ $this->post($url, $data)->assertRedirect();
+ $this->postJson($url, [...$data, 'status' => 'rejected'])->assertConflict();
+ $this->postJson($url, [...$data, 'client_key' => (string) Str::uuid()])->assertConflict();
+ $this->assertSame('reviewed', $record->fresh()->status);
+ $this->assertSame(2, $record->fresh()->version_no);
+ }
+
+ public function test_self_review_and_expired_new_decisions_are_denied_while_reading_remains_available(): void
+ {
+ $own = $this->demand($this->manager);
+ $expired = $this->capacity($this->other, ['valid_until' => today()->subDay()->toDateString()]);
+ $this->postJson('/management/education/demands/'.$own->id.'/review', $this->decision())->assertForbidden();
+ $this->postJson('/management/education/capacities/'.$expired->id.'/review', $this->decision())->assertUnprocessable();
+ $this->get('/management/education/capacities/'.$expired->id)->assertOk()->assertInertia(fn (Assert $page) => $page->where('declaration.can_review', false)->where('declaration.review_unavailable', 'expired'));
+ }
+
+ public function test_replay_after_expiry_confirms_the_old_decision_without_extending_validity(): void
+ {
+ $record = $this->demand($this->other);
+ $url = '/management/education/demands/'.$record->id.'/review';
+ $data = $this->decision();
+ $this->post($url, $data)->assertRedirect();
+ $before = $record->fresh()->getAttributes();
+ $this->travel(2)->years();
+ $this->post($url, $data)->assertRedirect();
+ $this->assertSame($before, $record->fresh()->getAttributes());
+ $this->postJson($url, [...$data, 'client_key' => (string) Str::uuid(), 'version_no' => 2])->assertUnprocessable();
+ }
+
+ public function test_replay_requires_current_access_and_command_metadata_is_private_to_its_actor(): void
+ {
+ $record = $this->demand($this->other);
+ $url = '/management/education/demands/'.$record->id.'/review';
+ $data = $this->decision();
+ $this->post($url, $data)->assertRedirect();
+ $this->actingAsWithMfa($this->other);
+ $this->get('/management/education/demands/'.$record->id)->assertOk()->assertInertia(fn (Assert $page) => $page->has('declaration.review_context.commands', 0));
+ $this->actingAsWithMfa($this->manager);
+ config(['portal.managers' => [$this->other->email]]);
+ $this->postJson($url, $data)->assertForbidden();
+ $this->get('/management/education/demands/'.$record->id)->assertForbidden();
+ $this->assertSame(2, $record->fresh()->version_no);
+ }
+
+ public function test_legacy_review_contract_and_public_scope_are_preserved(): void
+ {
+ $record = $this->demand($this->other);
+ $data = $this->decision();
+ unset($data['client_key']);
+ $url = '/management/education/demands/'.$record->id.'/review';
+ $this->post($url, $data)->assertRedirect();
+ $this->postJson($url, $data)->assertConflict();
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-education-review')->count());
+ $event = json_decode(DB::table('audit_events')->where('source_system', 'portal-education-review')->value('after_data'), true);
+ $this->assertNull($event['education_review']['key']);
+ $this->actingAsWithMfa(User::factory()->create());
+ $this->get('/management/education')->assertForbidden();
+ $this->get('/management/education/demands/'.$record->id)->assertForbidden();
+ config(['education.enabled' => false]);
+ $this->actingAsWithMfa($this->manager);
+ $this->get('/management/education')->assertNotFound();
+ }
+
+ public function test_personal_pagination_keeps_the_other_collection_and_filter_context(): void
+ {
+ for ($i = 0; $i < 22; $i++) {
+ $this->demand($this->manager);
+ }$this->demand($this->other);
+ $this->get('/management/education?scope=mine&q=SYNTHETIC&capacity_page=3')->assertOk()->assertInertia(fn (Assert $page) => $page->has('demands.data', 20)->where('demands.total', 22)
+ ->where('demands.next_page_url', fn (string $url) => str_contains($url, 'scope=mine') && str_contains($url, 'capacity_page=3') && str_contains($url, 'demand_page=2')));
+ }
+
+ public function test_an_old_receipt_does_not_overwrite_a_later_independent_decision(): void
+ {
+ $record = $this->demand($this->other);
+ $url = '/management/education/demands/'.$record->id.'/review';
+ $original = $this->decision();
+ $this->post($url, $original)->assertRedirect();
+ $third = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email, $this->other->email, $third->email]]);
+ $this->actingAsWithMfa($third);
+ $this->post($url, [...$this->decision(), 'version_no' => 2, 'status' => 'rejected'])->assertRedirect();
+ $before = $record->fresh()->getAttributes();
+ $this->actingAsWithMfa($this->manager);
+ $this->post($url, $original)->assertRedirect();
+ $this->assertSame($before, $record->fresh()->getAttributes());
+ $this->get('/management/education/demands/'.$record->id)->assertInertia(fn (Assert $page) => $page->where('declaration.version_no', 3)->where('declaration.status', 'rejected')
+ ->where('declaration.review_context.commands.0.version', 2)->has('declaration.review_context.commands', 1));
+ }
+
+ public function test_current_declarations_remain_available_without_the_optional_draft_table(): void
+ {
+ Schema::rename('education_declaration_drafts', 'education_declaration_drafts_not_installed');
+ $record = $this->demand($this->other);
+ $this->get('/management/education?scope=review')->assertOk()->assertInertia(fn (Assert $page) => $page->where('workQueue.drafts', null)->where('workQueue.demands.to_review', 1)->has('demands.data', 1));
+ $this->post('/management/education/demands/'.$record->id.'/review', $this->decision())->assertRedirect();
+ }
+
+ public function test_review_history_preserves_encrypted_subject_and_previous_reason_without_exposing_command_metadata(): void
+ {
+ $record = $this->demand($this->other, ['review_reason' => 'PRIVATE SYNTHETIC previous legacy reason']);
+ $data = $this->decision();
+ $this->post('/management/education/demands/'.$record->id.'/review', $data)->assertRedirect();
+ $raw = DB::table('audit_events')->where('source_system', 'portal-education-review')->value('after_data');
+ $this->assertStringNotContainsString($data['review_reason'], $raw);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC previous legacy reason', $raw);
+ $envelope = json_decode($raw, true)['education_review'];
+ $snapshot = json_decode(Crypt::decryptString($envelope['snapshot']), true);
+ $this->assertSame($record->id, $snapshot['subject']['id']);
+ $this->assertSame('PRIVATE SYNTHETIC previous legacy reason', $snapshot['before']['review_reason']);
+ $this->assertSame($data['review_reason'], $snapshot['after']['review_reason']);
+ $this->get('/management/education/demands/'.$record->id)->assertOk()->assertInertia(fn (Assert $page) => $page->has('history.data', 1)
+ ->where('history.data.0.available', true)->where('history.data.0.reason', $data['review_reason'])->where('history.data.0.previous_reason', 'PRIVATE SYNTHETIC previous legacy reason')
+ ->missing('history.data.0.snapshot')->missing('history.data.0.key')->missing('history.data.0.hash'));
+ }
+
+ public function test_review_history_paginates_versions_and_keeps_unreadable_originals_without_inventing_reasons(): void
+ {
+ $record = $this->capacity($this->other);
+ for ($version = 1; $version <= 12; $version++) {
+ $this->post('/management/education/capacities/'.$record->id.'/review', [...$this->decision(), 'version_no' => $version])->assertRedirect();
+ }
+ $demand = $this->demand($this->other);
+ $this->post('/management/education/demands/'.$demand->id.'/review', $this->decision())->assertRedirect();
+ $this->get('/management/education/capacities/'.$record->id.'?scope=review&q=SYNTHETIC')->assertOk()->assertInertia(fn (Assert $page) => $page
+ ->has('history.data', 10)->where('history.total', 12)->where('history.data.0.version', 13)->where('history.data.9.version', 4)
+ ->where('history.next_page_url', fn (string $url) => str_contains($url, 'scope=review') && str_contains($url, 'history_page=2')));
+ DB::table('audit_events')->insert(['source_system' => 'portal-education-review', 'entity_type' => 'training_capacities', 'entity_id' => $record->id, 'actor_user_id' => $this->manager->id, 'action' => 'review_committed', 'data_classification' => 'restricted',
+ 'after_data' => json_encode(['education_review' => ['version' => 14, 'snapshot' => 'SYNTHETIC unreadable ciphertext']])]);
+ $this->get('/management/education/capacities/'.$record->id)->assertOk()->assertInertia(fn (Assert $page) => $page->where('history.data.0.available', false)->where('history.data.0.reason', null)->where('history.data.0.version', 14));
+ $this->get('/management/education/capacities/'.$record->id.'?history_page=2')->assertOk()->assertInertia(fn (Assert $page) => $page->has('history.data', 3)->where('history.data.0.version', 4)->where('history.data.2.version', 2));
+ $this->assertSame(14, DB::table('audit_events')->where('source_system', 'portal-education-review')->count());
+ }
+}
diff --git a/tests/Feature/InvestmentGuidesTest.php b/tests/Feature/InvestmentGuidesTest.php
new file mode 100644
index 00000000..39d11c1f
--- /dev/null
+++ b/tests/Feature/InvestmentGuidesTest.php
@@ -0,0 +1,186 @@
+withoutVite();
+ config(['investor-path.enabled' => true, 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false]);
+ Http::preventStrayRequests();
+ $this->owner = User::factory()->create();
+ }
+
+ private function dossier(): string
+ {
+ return $this->actingAs($this->owner)->postJson('/investimentos', ['title' => 'SYNTHETIC capitalisation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
+ }
+
+ private function url(string $id): string
+ {
+ return '/investimentos/'.$id.'/guias/capitalizacao';
+ }
+
+ /** @return array */
+ private function input(string $id, array $extra = []): array
+ {
+ return [...['version' => DB::table('desk_cases')->where('id', $id)->value('version'), 'operation_key' => (string) Str::uuid(), 'sha256' => app(InvestmentGuides::class)->guide('capitalizacao')['sha256'], 'instruments' => ['private_equity', 'debt'], 'note' => 'SYNTHETIC private preparation'], ...$extra];
+ }
+
+ public function test_public_source_versioned_guide_requires_neither_login_nor_ia_and_does_not_capture_private_notes(): void
+ {
+ $this->getJson('/guias-investimento/capitalizacao?note=PRIVATE')->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertJsonPath('note', '')->assertJsonPath('case', null)->assertJsonCount(4, 'guide.instruments')->assertJsonCount(5, 'guide.sources')
+ ->assertJsonPath('guide.sources.bni.sha256', 'fbeaab84c4cad22ee63e5c1dfb61ea3206333885ddd80c8001d37a3f49d2820e')
+ ->assertJsonPath('guide.sources.ifc_apply.locator', 'Eligibility; Investment Proposals, pontos 1–7');
+ $this->get('/guias-investimento/capitalizacao')->assertOk()->assertInertia(fn ($page) => $page->component('investment/guide'));
+ $this->assertDatabaseCount('desk_cases', 0);
+ $this->assertDatabaseCount('organizations', 0);
+ $this->getJson('/guias-investimento/invented')->assertNotFound();
+ }
+
+ public function test_instrument_choices_are_coded_and_source_pin_survives_normal_authentication_and_dossier_choice(): void
+ {
+ $guide = app(InvestmentGuides::class)->guide('capitalizacao');
+ $selection = ['slug' => 'capitalizacao', 'sha256' => $guide['sha256'], 'instruments' => ['private_equity', 'debt', 'debt']];
+ $this->getJson('/guias-investimento/capitalizacao?'.http_build_query($selection))->assertOk()->assertJsonPath('instruments', ['debt', 'private_equity']);
+ $this->getJson('/guias-investimento/capitalizacao?instruments[0]=invented')->assertUnprocessable();
+ $this->getJson('/guias-investimento/capitalizacao?instruments=debt')->assertUnprocessable();
+ $target = '/investimentos?'.http_build_query(['investment_guide' => $selection]);
+ $this->get($target)->assertRedirect('/login');
+ $this->assertSame(url($target), session('url.intended'));
+ $id = $this->dossier();
+ $this->getJson($target)->assertOk()->assertJsonPath('guideSelection.instruments', ['debt', 'private_equity']);
+ $this->getJson($this->url($id).'?'.http_build_query(['current' => 1, ...$selection]))->assertOk()->assertJsonPath('workingCopy', true)->assertJsonPath('saved', null);
+ $new = $this->postJson('/investimentos', ['title' => 'SYNTHETIC chosen guide destination', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'investment_guide' => $selection])->assertCreated()->json();
+ $this->getJson($new['guide_href'])->assertOk()->assertJsonPath('instruments', ['debt', 'private_equity'])->assertJsonPath('saved', null);
+ $this->assertSame(0, DB::table('desk_events')->where('action', InvestmentGuides::EVENT)->count());
+ $before = DB::table('desk_cases')->count();
+ $this->postJson('/investimentos', ['title' => 'SYNTHETIC invalid guide', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'investment_guide' => [...$selection, 'sha256' => str_repeat('0', 64)]])->assertConflict();
+ $this->assertSame($before, DB::table('desk_cases')->count());
+ }
+
+ public function test_private_reference_is_encrypted_scoped_versioned_idempotent_and_does_not_advance_any_finance_stage(): void
+ {
+ $id = $this->dossier();
+ $url = $this->url($id);
+ $steps = DB::table('journey_steps')->orderBy('id')->get()->toJson();
+ $before = app(VirtualDesk::class)->decode(DB::table('desk_cases')->where('id', $id)->value('payload'));
+ $input = $this->input($id, ['guide' => ['title' => 'FORGED guarantee'], 'instruments' => ['debt', 'private_equity']]);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('revision', 1);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, [...$input, 'note' => 'SYNTHETIC changed body'])->assertConflict();
+ $this->postJson($url, [...$input, 'operation_key' => (string) Str::uuid()])->assertConflict();
+ $this->postJson($url, $this->input($id))->assertOk()->assertJsonPath('unchanged', true);
+ $r = $this->getJson($url)->assertOk()->assertJsonPath('saved.scope', 'dossier_reference')->assertJsonPath('note', 'SYNTHETIC private preparation')->json();
+ $this->assertSame(app(InvestmentGuides::class)->guide('capitalizacao'), $r['guide']);
+ $stored = DB::table('desk_cases')->where('id', $id)->first();
+ $this->assertStringNotContainsString('SYNTHETIC private preparation', $stored->payload);
+ $payload = app(VirtualDesk::class)->decode($stored->payload);
+ unset($payload['investment_guides']);
+ $this->assertSame($before, $payload);
+ $event = DB::table('desk_events')->where('case_id', $id)->where('action', InvestmentGuides::EVENT)->first();
+ $this->assertStringNotContainsString('SYNTHETIC private preparation', $event->payload);
+ $this->assertStringNotContainsString('SYNTHETIC private preparation', DB::table('audit_events')->where('entity_id', $id)->get()->toJson());
+ $this->assertSame($steps, DB::table('journey_steps')->orderBy('id')->get()->toJson());
+ $this->assertDatabaseCount('desk_requests', 0);
+ $this->assertDatabaseCount('investment_company_declarations', 0);
+ $this->assertSame(1, DB::table('desk_events')->where('action', InvestmentGuides::EVENT)->count());
+ $this->getJson($url.'?'.http_build_query(['current' => 1, 'selection' => 1, 'sha256' => $r['guide']['sha256']]))->assertOk()->assertJsonPath('instruments', [])->assertJsonPath('workingCopy', true)->assertJsonPath('saved.instruments', ['debt', 'private_equity']);
+ DB::table('desk_cases')->where('id', $id)->update(['closed_at' => now()]);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($url, $this->input($id))->assertConflict();
+ }
+
+ public function test_source_editions_and_notes_remain_recoverable_after_updates_or_withdrawal_and_replays_use_original_choices(): void
+ {
+ $id = $this->dossier();
+ $url = $this->url($id);
+ $input = $this->input($id);
+ $this->postJson($url, $input)->assertOk();
+ $first = $this->getJson($url)->json();
+ config(['investment-guides.capitalizacao.version' => 'SYNTHETIC future', 'investment-guides.capitalizacao.instruments.debt' => null]);
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->getJson($url)->assertJsonPath('olderEdition', true)->assertJsonPath('guide', $first['guide']);
+ $this->postJson($url, [...$input, 'version' => $first['case']['version'], 'operation_key' => (string) Str::uuid()])->assertConflict();
+ config(['investment-guides.capitalizacao.instruments' => ['private_equity' => $first['guide']['instruments']['private_equity']]]);
+ $this->getJson($url.'?current=1')->assertOk()->assertJsonPath('unavailableInstruments', [$first['guide']['instruments']['debt']['title']])->assertJsonPath('note', $first['note']);
+ $this->postJson($url, $this->input($id, ['instruments' => ['private_equity'], 'note' => 'SYNTHETIC new edition']))->assertOk()->assertJsonPath('revision', 2);
+ $this->getJson($url.'?revision='.$first['history'][0]['id'])->assertOk()->assertJsonPath('guide', $first['guide'])->assertJsonPath('note', $first['note']);
+ config(['investment-guides.capitalizacao' => null]);
+ $this->getJson('/guias-investimento/capitalizacao')->assertNotFound();
+ $this->getJson($url)->assertOk()->assertJsonPath('currentAvailable', false)->assertJsonPath('note', 'SYNTHETIC new edition');
+ $this->getJson($url.'?current=1')->assertConflict();
+ $this->postJson($url, $input)->assertOk()->assertJsonPath('replayed', true);
+ }
+
+ public function test_pagination_preserves_every_revision_and_rejects_another_dossiers_history_identifier(): void
+ {
+ $id = $this->dossier();
+ $url = $this->url($id);
+ for ($i = 1; $i <= 26; $i++) {
+ $this->postJson($url, $this->input($id, ['note' => 'SYNTHETIC note '.$i]))->assertOk();
+ }
+ $r = $this->getJson($url)->assertJsonCount(25, 'history')->json();
+ $old = $this->getJson($url.'?history_before='.$r['historyNext'])->assertJsonCount(1, 'history')->json();
+ $revision = $old['history'][0]['id'];
+ $this->getJson($url.'?revision='.$revision)->assertOk()->assertJsonPath('saved.revision', 1)->assertJsonPath('historical', true);
+ $this->getJson($url.'?revision='.$revision.'¤t=1')->assertUnprocessable();
+ $other = $this->dossier();
+ $this->getJson($this->url($other).'?revision='.$revision)->assertNotFound();
+ }
+
+ public function test_context_changes_are_explicit_without_rewriting_the_previous_reference(): void
+ {
+ $id = $this->dossier();
+ $url = $this->url($id);
+ $this->postJson($url, $this->input($id))->assertOk();
+ $r = $this->getJson($url)->assertJsonPath('contextChanged', false)->json();
+ $case = DB::table('desk_cases')->where('id', $id)->first();
+ $payload = app(VirtualDesk::class)->decode($case->payload);
+ $payload['investor_path']['context'] = app(InvestorContext::class)->state($case);
+ $payload['investor_path']['context']['revision'] = 99;
+ $payload['investor_path']['context']['fields']['project_title'] = 'SYNTHETIC changed scope';
+ DB::table('desk_cases')->where('id', $id)->update(['payload' => app(VirtualDesk::class)->encode($payload)]);
+ $this->getJson($url)->assertJsonPath('contextChanged', true)->assertJsonPath('saved.context', $r['saved']['context']);
+ }
+
+ public function test_revocation_and_read_only_membership_are_effective_before_replay_or_validation(): void
+ {
+ $id = $this->dossier();
+ $url = $this->url($id);
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC financing organization', 'organization_type' => 'private']);
+ DB::table('desk_cases')->where('id', $id)->update(['organization_id' => $org]);
+ $editor = User::factory()->create();
+ $viewer = User::factory()->create();
+ foreach ([[$this->owner, 'officer'], [$editor, 'officer'], [$viewer, 'viewer']] as [$actor, $role]) {
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'organization_id' => $org, 'user_id' => $actor->id, 'role' => $role]);
+ }
+ $input = $this->input($id);
+ $this->actingAs($editor)->postJson($url, $input)->assertOk();
+ $this->actingAs($viewer)->getJson($url)->assertOk()->assertJsonPath('canWrite', false);
+ $this->postJson($url, $input)->assertForbidden();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $editor->id)->update(['deleted_at' => now()]);
+ $this->actingAs($editor)->getJson($url)->assertForbidden();
+ $this->postJson($url, $input)->assertForbidden();
+ $this->postJson($url, [])->assertForbidden();
+ $this->assertSame(1, DB::table('desk_events')->where('action', InvestmentGuides::EVENT)->count());
+ }
+}
diff --git a/tests/Feature/InvestmentProfileCommandsTest.php b/tests/Feature/InvestmentProfileCommandsTest.php
new file mode 100644
index 00000000..e1e0c254
--- /dev/null
+++ b/tests/Feature/InvestmentProfileCommandsTest.php
@@ -0,0 +1,107 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->actingAs(User::factory()->create());
+ }
+
+ private function company(): array
+ {
+ return ['version' => 0, 'operation_key' => (string) Str::uuid(), 'payload' => ['name' => 'SYNTHETIC private company', 'incorporation_country_code' => 'MZ', 'role' => 'SYNTHETIC declared representative']];
+ }
+
+ public function test_new_company_replay_returns_the_original_identity_and_preserves_ciphertext_and_audit(): void
+ {
+ $command = $this->company();
+ $first = $this->postJson('/api/v1/investment/companies', $command)->assertOk()->json();
+ $cipher = DB::table('investment_company_declarations')->value('payload');
+ $events = DB::table('audit_events')->count();
+ $this->postJson('/api/v1/investment/companies', $command)->assertExactJson($first);
+ $this->assertSame(1, DB::table('investment_company_declarations')->count());
+ $this->assertSame($cipher, DB::table('investment_company_declarations')->value('payload'));
+ $this->assertSame($events, DB::table('audit_events')->count());
+ $this->assertSame(0, DB::table('organizations')->count());
+ $this->assertSame(0, DB::table('memberships')->count());
+ $record = DB::table('audit_events')->where('source_system', 'investment-workspace-command')->sole();
+ $this->assertStringNotContainsString('SYNTHETIC private company', $record->after_data);
+ $metadata = json_decode($record->after_data, true);
+ $this->assertSame('SYNTHETIC private company', json_decode(Crypt::decryptString($metadata['command_encrypted']), true)['payload']['name']);
+ }
+
+ public function test_key_reuse_with_changed_content_is_a_conflict_and_cannot_change_the_original(): void
+ {
+ $command = $this->company();
+ $id = $this->postJson('/api/v1/investment/companies', $command)->assertOk()->json('id');
+ $before = DB::table('investment_company_declarations')->where('id', $id)->first();
+ $this->postJson('/api/v1/investment/companies', [...$command, 'payload' => [...$command['payload'], 'name' => 'SYNTHETIC changed']])->assertConflict();
+ $this->assertEquals($before, DB::table('investment_company_declarations')->where('id', $id)->first());
+ }
+
+ public function test_profile_commands_validate_iso_replay_without_increment_and_preserve_historical_country(): void
+ {
+ $command = ['version' => 0, 'operation_key' => (string) Str::uuid(), 'payload' => ['residence_country_code' => 'PT', 'country' => 'Historical country', 'phone' => 'SYNTHETIC-contact']];
+ $this->putJson('/api/v1/investment/profile', $command)->assertExactJson(['version' => 1]);
+ $before = DB::table('investment_accounts')->first();
+ $this->putJson('/api/v1/investment/profile', ['payload' => array_reverse($command['payload'], true), 'operation_key' => strtoupper($command['operation_key']), 'version' => 0])->assertExactJson(['version' => 1]);
+ $this->assertEquals($before, DB::table('investment_accounts')->first());
+ $this->putJson('/api/v1/investment/profile', ['version' => 1, 'operation_key' => (string) Str::uuid(), 'payload' => ['residence_country_code' => 'ZZ']])->assertUnprocessable()->assertJsonValidationErrors('payload.residence_country_code');
+ $this->getJson('/api/v1/investment/profile')->assertOk()->assertJsonPath('account.version', 1)->assertJsonPath('account.payload.residence_country_code', 'PT')->assertJsonPath('account.payload.country', 'Historical country')->assertHeader('Cache-Control', 'no-store, private');
+ $this->get('/investidor/profile')->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $page) => $page->component('investment/profile')->where('actorId', auth()->id())->where('account.payload.residence_country_code', 'PT'));
+ $this->assertEquals($before, DB::table('investment_accounts')->first());
+ }
+
+ public function test_replay_after_later_updates_returns_the_original_receipt_without_reverting_current_data(): void
+ {
+ $command = $this->company();
+ $id = $this->postJson('/api/v1/investment/companies', $command)->assertOk()->json('id');
+ $update = ['version' => 1, 'operation_key' => (string) Str::uuid(), 'payload' => [...$command['payload'], 'name' => 'SYNTHETIC newer name']];
+ $this->postJson('/api/v1/investment/companies/'.$id, $update)->assertJsonPath('version', 2);
+ $before = DB::table('investment_company_declarations')->where('id', $id)->first();
+ $this->postJson('/api/v1/investment/companies', $command)->assertExactJson(['id' => $id, 'version' => 1]);
+ $this->postJson('/api/v1/investment/companies/'.$id, $update)->assertExactJson(['id' => $id, 'version' => 2]);
+ $this->assertEquals($before, DB::table('investment_company_declarations')->where('id', $id)->first());
+ $this->postJson('/api/v1/investment/companies/'.$id, [...$update, 'operation_key' => (string) Str::uuid()])->assertConflict();
+ }
+
+ public function test_commands_are_private_per_actor_and_do_not_identify_companies_by_name(): void
+ {
+ $command = $this->company();
+ $id = $this->postJson('/api/v1/investment/companies', $command)->assertOk()->json('id');
+ $this->actingAs(User::factory()->create());
+ $otherId = $this->postJson('/api/v1/investment/companies', $command)->assertOk()->json('id');
+ $this->assertNotSame($id, $otherId);
+ $this->postJson('/api/v1/investment/companies/'.$id, [...$command, 'version' => 1])->assertNotFound();
+ $this->getJson('/api/v1/investment/profile')->assertJsonCount(1, 'companies')->assertJsonPath('companies.0.id', $otherId);
+ $this->assertSame(2, DB::table('investment_company_declarations')->count());
+ }
+
+ public function test_malformed_keys_are_rejected_before_any_write_and_legacy_requests_remain_supported(): void
+ {
+ $command = $this->company();
+ $this->postJson('/api/v1/investment/companies', [...$command, 'operation_key' => 'bad'])->assertUnprocessable()->assertJsonValidationErrors('operation_key');
+ $this->assertSame(0, DB::table('investment_company_declarations')->count());
+ unset($command['operation_key']);
+ $this->postJson('/api/v1/investment/companies', $command)->assertOk();
+ $this->assertSame(1, DB::table('investment_company_declarations')->count());
+ }
+}
diff --git a/tests/Feature/OpportunityCanonicalWorkflowTest.php b/tests/Feature/OpportunityCanonicalWorkflowTest.php
index d4d9c7df..ba2638aa 100644
--- a/tests/Feature/OpportunityCanonicalWorkflowTest.php
+++ b/tests/Feature/OpportunityCanonicalWorkflowTest.php
@@ -11,6 +11,7 @@ use App\Services\OpportunityCanonicalValue;
use App\Services\OpportunityCategoryFields;
use App\Services\OpportunityCompleteness;
use App\Services\OpportunityManagement;
+use App\Services\OpportunityMaturity;
use App\Services\OpportunityModularProfiles;
use App\Services\OpportunityReviewMateriality;
use App\Services\PortalProfileAccess;
@@ -23,6 +24,7 @@ use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Inertia\Testing\AssertableInertia as Assert;
+use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
class OpportunityCanonicalWorkflowTest extends TestCase
@@ -424,6 +426,124 @@ class OpportunityCanonicalWorkflowTest extends TestCase
$this->assertNotSame($before['approval']['review_cycle'], $published['approval']['review_cycle']);
}
+ /** @return array */
+ public static function maturityStages(): array
+ {
+ $cases = [];
+ foreach (OpportunityMaturity::STAGES as $stage => $label) {
+ $cases[$stage] = [$stage, count($cases) + 1, $label];
+ }
+
+ return $cases;
+ }
+
+ /** @param array $payload */
+ private function maturityLocation(array $payload): void
+ {
+ $location = json_decode(DB::table('opportunity_location_drafts')->where('id', $payload['locations'][0])->value('payload'), true);
+ $country = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $country, 'code' => $country, 'name' => 'Synthetic QA maturity country', 'location_type' => 'country',
+ 'data_classification' => 'public', 'source_system' => 'cartografia-workbook',
+ 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$country]);
+ DB::table('geo_locations')->where('id', $location['province_id'])->update(['parent_id' => $country]);
+ foreach ([$location['province_id'], $location['district_id']] as $territory) {
+ DB::table('geo_locations')->where('id', $territory)->update(['data_classification' => 'public', 'source_system' => 'cartografia-workbook',
+ 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$territory]);
+ }
+ }
+
+ #[DataProvider('maturityStages')]
+ public function test_clearing_an_optional_stage_does_not_reinterpret_its_published_number_as_historical(string $stage, int $position, string $label): void
+ {
+ [$id, $promoter, $validator, $publisher, $payload, $document] = $this->fixture();
+ $this->maturityLocation($payload);
+ $payload['maturity_stage'] = $stage;
+ if ($position >= 4) {
+ $payload['financial_indicators'] = ['npv' => 123, 'irr' => 6, 'payback_years' => 5, 'horizon_years' => 10,
+ 'discount_rate' => 7, 'currency' => 'MZN', 'scenario' => 'SYNTHETIC policy fixture, not a real financial model', 'model_document_id' => $document];
+ }
+ foreach ([1, 2] as $cycle) {
+ $this->loginFixture($promoter)->putJson('/minhas-oportunidades/'.$id.'/draft', [
+ 'etag' => app(OpportunityManagement::class)->etag(Opportunity::findOrFail($id)),
+ 'canonical' => $payload, 'reason' => self::REASON,
+ ])->assertOk();
+ $this->assertSame($payload['maturity_stage'], app(OpportunityManagement::class)->values(Opportunity::findOrFail($id))['canonical']['maturity_stage']);
+ $this->action($promoter, $id, 'submit');
+ $this->action($validator, $id, 'start_review');
+ foreach (['property_review', 'registry_urban_review', 'building_compliance_review'] as $gate) {
+ $this->action($validator, $id, 'review_gate', ['gate' => $gate, 'gate_decision' => 'approved', 'evidence_document_ids' => [$document]]);
+ }
+ $this->action($validator, $id, 'approve');
+ $this->action($publisher, $id, 'publish');
+ $record = Opportunity::findOrFail($id);
+ $this->assertSame($cycle === 1 ? $position : null, $record->maturity_level);
+ $this->assertSame($cycle === 1 ? $label : null, $record->maturity_label);
+ $this->assertEquals(['catalogue_version' => OpportunityMaturity::VERSION, 'stage' => $cycle === 1 ? $stage : null,
+ 'level' => $cycle === 1 ? $position : null, 'label' => $cycle === 1 ? $label : null], data_get($record->workflow_context, 'publication.maturity'));
+ $query = Opportunity::whereKey($id);
+ OpportunityMaturity::constrainSearch($query, 'historical:'.$position);
+ $this->assertSame(0, $query->count());
+ $query = Opportunity::whereKey($id);
+ OpportunityMaturity::constrainSearch($query, 'stage:'.$stage);
+ $this->assertSame($cycle === 1 ? 1 : 0, $query->count());
+ $this->assertSame(0, Opportunity::published()->whereKey($id)->count());
+ if ($cycle === 1) {
+ $this->action($publisher, $id, 'suspend');
+ $this->action($promoter, $id, 'request_revision');
+ $payload['maturity_stage'] = null;
+ }
+ }
+ $this->assertSame($stage, data_get($record->workflow_context, 'publication_history.0.maturity.stage'));
+ }
+
+ public function test_unknown_optional_maturity_stage_is_reported_before_review(): void
+ {
+ [$id, $promoter, , , $payload] = $this->fixture();
+ $payload['maturity_stage'] = 'SYNTHETIC-NOT-A-CATALOGUE-STAGE';
+ $this->loginFixture($promoter)->putJson('/minhas-oportunidades/'.$id.'/draft', [
+ 'etag' => app(OpportunityManagement::class)->etag(Opportunity::findOrFail($id)),
+ 'canonical' => $payload, 'reason' => self::REASON,
+ ])->assertUnprocessable()->assertJsonValidationErrors('canonical.maturity_stage');
+ $this->assertSame('draft', Opportunity::findOrFail($id)->status);
+ $this->assertArrayNotHasKey('maturity_stage', app(OpportunityManagement::class)->values(Opportunity::findOrFail($id))['canonical']);
+ }
+
+ /** @return array */
+ public static function historicalMaturityLevels(): array
+ {
+ $cases = [];
+ foreach (OpportunityMaturity::LEGACY_LABELS as $level => $label) {
+ $cases[] = [$level, $label];
+ }
+
+ return $cases;
+ }
+
+ #[DataProvider('historicalMaturityLevels')]
+ public function test_publication_without_a_maturity_stage_retains_its_legacy_level(int $level, string $label): void
+ {
+ [$id, $promoter, $validator, $publisher, $payload, $document] = $this->fixture();
+ $this->maturityLocation($payload);
+ Opportunity::findOrFail($id)->forceFill(['maturity_level' => $level, 'maturity_label' => $label])->save();
+ $this->action($promoter, $id, 'submit');
+ $this->action($validator, $id, 'start_review');
+ foreach (['property_review', 'registry_urban_review', 'building_compliance_review'] as $gate) {
+ $this->action($validator, $id, 'review_gate', ['gate' => $gate, 'gate_decision' => 'approved', 'evidence_document_ids' => [$document]]);
+ }
+ $this->action($validator, $id, 'approve');
+ $this->action($publisher, $id, 'publish');
+ $record = Opportunity::findOrFail($id);
+ $this->assertSame($level, $record->maturity_level);
+ $this->assertSame($label, $record->maturity_label);
+ $query = Opportunity::whereKey($id);
+ OpportunityMaturity::constrainSearch($query, 'historical:'.$level);
+ $this->assertSame(1, $query->count());
+ $query = Opportunity::whereKey($id);
+ OpportunityMaturity::constrainSearch($query, 'stage:'.array_keys(OpportunityMaturity::STAGES)[$level - 1]);
+ $this->assertSame(0, $query->count());
+ $this->assertSame(0, Opportunity::published()->whereKey($id)->count());
+ }
+
public function test_semantic_errors_are_keyed_to_fields_and_incomplete_drafts_remain_recoverable(): void
{
[$id,$promoter,$validator,$publisher,$payload,$document] = $this->fixture();
diff --git a/tests/Feature/OpportunityTechnicalIncidentsTest.php b/tests/Feature/OpportunityTechnicalIncidentsTest.php
new file mode 100644
index 00000000..71e09572
--- /dev/null
+++ b/tests/Feature/OpportunityTechnicalIncidentsTest.php
@@ -0,0 +1,258 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Storage::fake('local');
+ config(['portal.profile_access_enabled' => true, 'portal.opportunity_specialized_drafts_enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ }
+
+ /** @param list $responsibilities */
+ private function actor(string $role, string $org, array $responsibilities = []): User
+ {
+ $actor = User::factory()->create();
+ $actor->forceFill(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()])->save();
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), User::factory()->create(), ['user_id' => $actor->id, 'role' => $role, 'organization_id' => $role === 'promoter' ? $org : null, 'opportunity_types' => ['real_estate'], 'responsibilities' => $responsibilities, 'source' => 'synthetic-incident-fixture']);
+
+ return $actor;
+ }
+
+ private function loginFixture(User $actor): static
+ {
+ return $this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
+ }
+
+ /** @param array $extra */
+ private function act(User $actor, int $id, string $action, array $extra = []): TestResponse
+ {
+ $record = Opportunity::findOrFail($id);
+
+ return $this->loginFixture($actor)->postJson('/minhas-oportunidades/'.$id.'/workflow', ['etag' => app(OpportunityManagement::class)->etag($record), 'action' => $action, 'reason' => self::REASON, ...$extra]);
+ }
+
+ private function failAudit(string $action, bool $incidentToo = false): void
+ {
+ $source = $incidentToo ? "NEW.source_system = 'portal-opportunity-incident' OR " : '';
+ DB::unprepared("CREATE FUNCTION qa_incident_failure() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN IF ({$source}NEW.action = '{$action}') THEN RAISE EXCEPTION 'PRIVATE SYNTHETIC SQL TOKEN MUST NEVER REACH THE RESPONSE'; END IF; RETURN NEW; END \$\$; CREATE TRIGGER qa_incident_failure BEFORE INSERT ON audit_events FOR EACH ROW EXECUTE FUNCTION qa_incident_failure();");
+ }
+
+ public function test_failed_submission_rolls_back_and_records_only_minimal_private_metadata_then_allows_manual_recovery(): void
+ {
+ [$id,$promoter,$validator] = $this->fixture();
+ $before = Opportunity::findOrFail($id)->getRawOriginal();
+ $taskCount = DB::table('tasks')->count();
+ $this->failAudit('workflow_submit');
+ $response = $this->act($promoter, $id, 'submit')->assertStatus(503)->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('incident_recorded', true);
+ $reference = $response->json('reference');
+ $this->assertTrue(Str::isUuid($reference));
+ $this->assertStringNotContainsString('SQL TOKEN', $response->getContent());
+ $this->assertSame($before, Opportunity::findOrFail($id)->getRawOriginal());
+ $this->assertSame($taskCount, DB::table('tasks')->count());
+ $event = DB::table('audit_events')->where('id', $reference)->first();
+ $data = json_decode($event->after_data, true)['incident'];
+ $this->assertSame('restricted', $event->data_classification);
+ $this->assertSame($reference, $event->correlation_id);
+ $this->assertSame($id, $data['opportunity_id']);
+ $this->assertSame('submit', $data['operation']);
+ $this->assertSame('database_failure', $data['error_code']);
+ $this->assertArrayNotHasKey('reason', $data);
+ $this->assertArrayNotHasKey('exception', $data);
+ $this->assertArrayNotHasKey('payload', $data);
+ $this->get('/minhas-oportunidades/'.$id.'/view')->assertOk()->assertInertia(fn (Assert $page) => $page->has('workflowIncidents', 1)->where('workflowIncidents.0.reference', $reference)->missing('workflowIncidents.0.attempted_etag'));
+ $this->loginFixture($validator)->get('/minhas-oportunidades/'.$id.'/view')->assertOk()->assertInertia(fn (Assert $page) => $page->has('workflowIncidents', 0));
+ DB::unprepared('DROP TRIGGER qa_incident_failure ON audit_events; DROP FUNCTION qa_incident_failure();');
+ $this->act($promoter, $id, 'submit')->assertOk()->assertJsonPath('status', 'submitted');
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->count());
+ $this->assertSame($taskCount + 1, DB::table('tasks')->count());
+ }
+
+ public function test_publication_failure_preserves_approved_content_public_projection_tasks_and_original_decisions(): void
+ {
+ [$id,$promoter,$validator,$publisher,$payload,$document] = $this->fixture();
+ $this->act($promoter, $id, 'submit')->assertOk();
+ $this->act($validator, $id, 'start_review')->assertOk();
+ foreach (['property_review', 'registry_urban_review', 'building_compliance_review'] as $gate) {
+ $this->act($validator, $id, 'review_gate', ['gate' => $gate, 'gate_decision' => 'approved', 'evidence_document_ids' => [$document]])->assertOk();
+ }
+ $this->act($validator, $id, 'approve')->assertOk();
+ $record = Opportunity::findOrFail($id);
+ $before = $record->getRawOriginal();
+ $tasks = DB::table('tasks')->orderBy('id')->get()->toJson();
+ $this->failAudit('workflow_publish');
+ $this->act($publisher, $id, 'publish', ['confirm_publication' => true, 'preview_hash' => $record->workflow_context['approval']['hash']])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ $this->assertSame($before, Opportunity::findOrFail($id)->getRawOriginal());
+ $this->assertSame($tasks, DB::table('tasks')->orderBy('id')->get()->toJson());
+ $this->assertSame('publish', app(OpportunityTechnicalIncidents::class)->recent($publisher, $record)[0]['operation']);
+ $this->assertSame([], app(OpportunityTechnicalIncidents::class)->recent($promoter, $record));
+ }
+
+ public function test_validation_conflicts_and_permission_failures_are_not_technical_incidents(): void
+ {
+ [$id,$promoter,$validator] = $this->fixture();
+ $this->act($promoter, $id, 'submit', ['reason' => 'short'])->assertUnprocessable();
+ $this->act($promoter, $id, 'submit', ['etag' => str_repeat('0', 64)])->assertConflict();
+ $this->act($validator, $id, 'submit')->assertForbidden();
+ $this->assertSame(0, DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->count());
+ }
+
+ public function test_a_second_storage_failure_returns_an_honest_reference_without_leaking_sql_or_claiming_a_saved_incident(): void
+ {
+ [$id,$promoter] = $this->fixture();
+ $before = Opportunity::findOrFail($id)->getRawOriginal();
+ $this->failAudit('workflow_submit', true);
+ Log::shouldReceive('warning')->once()->with('Opportunity technical incident could not be stored.', \Mockery::on(fn ($context) => Str::isUuid($context['reference']) && $context['error_code'] === 'database_failure'));
+ $response = $this->act($promoter, $id, 'submit')->assertStatus(503)->assertJsonPath('incident_recorded', false);
+ $this->assertStringNotContainsString('SQL TOKEN', $response->getContent());
+ $this->assertTrue(Str::isUuid($response->json('reference')));
+ $this->assertSame($before, Opportunity::findOrFail($id)->getRawOriginal());
+ $this->assertSame(0, DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->count());
+ }
+
+ public function test_incident_consultation_rechecks_current_authority_and_never_grants_other_record_or_document_access(): void
+ {
+ [$id,$promoter] = $this->fixture();
+ $this->failAudit('workflow_submit');
+ $this->act($promoter, $id, 'submit')->assertStatus(503);
+ $draft = $this->loginFixture($promoter)->postJson('/minhas-oportunidades/drafts', ['creation_key' => (string) Str::uuid(), 'organization_id' => Opportunity::findOrFail($id)->organization_id, 'opportunity_category' => 'real_estate', 'reason' => self::REASON])->assertCreated()->json('id');
+ $this->assertSame([], app(OpportunityTechnicalIncidents::class)->recent($promoter, Opportunity::findOrFail($draft)));
+ DB::table('portal_role_assignments')->where('user_id', $promoter->id)->update(['revoked_at' => now()]);
+ $this->get('/minhas-oportunidades/'.$id.'/view')->assertForbidden();
+ }
+
+ public function test_support_profile_receives_only_current_scope_metadata_without_operational_or_document_access(): void
+ {
+ [$id,$promoter] = $this->fixture();
+ $record = Opportunity::findOrFail($id);
+ $this->failAudit('workflow_submit');
+ $this->act($promoter, $id, 'submit')->assertStatus(503);
+ $support = $this->actor('technical_support', $record->organization_id);
+ DB::table('portal_role_assignments')->where('user_id', $support->id)->update(['organization_id' => $record->organization_id]);
+ $this->loginFixture($support)->get('/suporte-tecnico/incidentes')->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $page) => $page->component('profiles/technical-support')->has('incidents.data', 1)->missing('incidents.data.0.attempted_etag')->missing('incidents.data.0.opportunity_id'));
+ $this->get('/minhas-oportunidades/'.$id.'/view')->assertForbidden();
+ $this->act($support, $id, 'publish')->assertForbidden();
+ $otherOrganization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $otherOrganization, 'name' => 'SYNTHETIC other organization', 'organization_type' => 'private']);
+ DB::table('portal_role_assignments')->where('user_id', $support->id)->update(['organization_id' => $otherOrganization]);
+ $this->get('/suporte-tecnico/incidentes')->assertOk()->assertInertia(fn (Assert $page) => $page->has('incidents.data', 0));
+ DB::table('portal_role_assignments')->where('user_id', $support->id)->update(['organization_id' => null]);
+ DB::table('opportunities')->where('id', $id)->update(['organization_id' => $otherOrganization]);
+ $this->get('/suporte-tecnico/incidentes')->assertOk()->assertInertia(fn (Assert $page) => $page->has('incidents.data', 0));
+ }
+
+ public function test_support_scope_revocation_expiry_and_auditor_restriction_are_effective(): void
+ {
+ [$id,$promoter] = $this->fixture();
+ $record = Opportunity::findOrFail($id);
+ $this->failAudit('workflow_submit');
+ $this->act($promoter, $id, 'submit')->assertStatus(503);
+ $support = $this->actor('technical_support', 'unused');
+ $this->loginFixture($support)->get('/suporte-tecnico/incidentes')->assertOk();
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), User::factory()->create(), ['user_id' => $support->id, 'role' => 'auditor', 'opportunity_types' => ['real_estate']]);
+ $this->get('/suporte-tecnico/incidentes')->assertForbidden();
+ DB::table('portal_role_assignments')->where('user_id', $support->id)->where('role', 'auditor')->update(['revoked_at' => now()]);
+ $this->get('/suporte-tecnico/incidentes')->assertOk();
+ $this->travel(2)->hours();
+ DB::table('portal_role_assignments')->where('user_id', $support->id)->where('role', 'technical_support')->update(['expires_at' => now()->subHour()]);
+ $this->get('/suporte-tecnico/incidentes')->assertForbidden();
+ }
+
+ public function test_support_grant_uses_existing_independent_administration_and_is_audited(): void
+ {
+ $admin = User::factory()->create();
+ $second = User::factory()->create();
+ DB::table('portal_superuser_pair')->insert(['id' => 1, 'first_user_id' => $admin->id, 'second_user_id' => $second->id, 'approved_by' => $second->id, 'version' => 1, 'created_at' => now(), 'updated_at' => now()]);
+ $admin->forceFill(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()])->save();
+ $subject = User::factory()->create();
+ $this->loginFixture($admin);
+ $input = ['user_id' => $subject->id, 'role' => 'technical_support', 'opportunity_types' => ['real_estate'], 'reason' => self::REASON];
+ $this->postJson('/perfis/atribuicoes', $input)->assertCreated();
+ $this->assertTrue(app(PortalProfileAccess::class)->has($subject, 'technical_support'));
+ $this->assertSame(1, DB::table('audit_events')->where('action', 'role_granted')->count());
+ $this->postJson('/perfis/atribuicoes', [...$input, 'user_id' => $admin->id])->assertForbidden();
+ $this->postJson('/perfis/atribuicoes', [...$input, 'responsibilities' => ['technical_reviewer']])->assertUnprocessable();
+ $this->assertFalse(app(PortalProfileAccess::class)->canCreate($subject, null, 'real_estate'));
+ $this->assertFalse(app(ScopedPortalAdministration::class)->administrative($subject));
+ }
+
+ /** @return array{int,User,User,User,array,string} */
+ private function fixture(): array
+ {
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'Synthetic QA organization', 'organization_type' => 'private']);
+ $promoter = $this->actor('promoter', $org);
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'user_id' => $promoter->id, 'organization_id' => $org, 'role' => 'officer']);
+ $validator = $this->actor('validator', $org, ['technical_reviewer', 'legal_reviewer', 'validation_coordinator']);
+ $publisher = $this->actor('publisher', $org, ['publication_coordinator']);
+ $version = (string) Str::uuid();
+ DB::table('reference_catalog_versions')->insert(['id' => $version, 'catalog_code' => 'qa-only-'.$org, 'version_no' => 1, 'source_system' => 'synthetic-policy-fixture', 'source_version' => 'qa', 'source_reference' => 'Not official', 'status' => 'published']);
+ $ids = [];
+ $parent = null;
+ foreach (range(1, 3) as $i) {
+ $sector = DB::table('sectors')->insertGetId(['name' => 'QA '.$i, 'slug' => 'qa-'.$org.'-'.$i, 'is_active' => true]);
+ $id = (string) Str::uuid();
+ DB::table('economic_activities')->insert(['id' => $id, 'parent_id' => $parent, 'sector_id' => $sector, 'catalog_version_id' => $version, 'code' => 'qa-'.$i, 'label_pt_mz' => 'QA '.$i, 'status' => 'published', 'valid_from' => today()]);
+ $ids[] = [$id, $sector];
+ $parent = $id;
+ }
+ $contact = (string) Str::uuid();
+ $investor = (string) Str::uuid();
+ DB::table('contacts')->insert(['id' => $contact, 'full_name' => 'Synthetic QA contact']);
+ DB::table('investors')->insert(['id' => $investor, 'organization_id' => $org, 'legal_name' => 'Synthetic QA entity', 'investor_type' => 'institutional', 'status' => 'active']);
+ DB::table('investor_contacts')->insert(['investor_id' => $investor, 'contact_id' => $contact]);
+ $draft = $this->loginFixture($promoter)->postJson('/minhas-oportunidades/drafts', ['creation_key' => (string) Str::uuid(), 'organization_id' => $org, 'opportunity_category' => 'real_estate', 'reason' => self::REASON])->assertCreated()->json();
+ $id = $draft['id'];
+ $location = (string) Str::uuid();
+ $provinceId = (string) Str::uuid();
+ $districtId = (string) Str::uuid();
+ DB::table('geo_locations')->insert([['id' => $provinceId, 'code' => $provinceId, 'name' => 'Synthetic QA province', 'location_type' => 'province', 'parent_id' => null, 'data_classification' => 'internal'], ['id' => $districtId, 'code' => $districtId, 'name' => 'Synthetic QA district', 'location_type' => 'district', 'parent_id' => $provinceId, 'data_classification' => 'internal']]);
+ $province = DB::table('geo_locations')->where('id', $provinceId)->first();
+ $district = DB::table('geo_locations')->where('id', $districtId)->first();
+ DB::table('opportunity_location_drafts')->insert(['id' => $location, 'opportunity_id' => $id, 'version' => 1, 'created_by' => $promoter->id, 'payload' => json_encode(['country_code' => 'MZ', 'province_id' => $province->id, 'district_id' => $district->id, 'role' => 'headquarters', 'is_primary' => true])]);
+ $document = (string) Str::uuid();
+ $file = (string) Str::uuid();
+ $bytes = 'Synthetic policy fixture, not a real scanner result.';
+ $key = 'opportunity-contract-test/'.$file;
+ Storage::disk('local')->put($key, Crypt::encryptString($bytes));
+ DB::table('documents')->insert(['id' => $file, 'file_name' => 'qa-fixture.txt', 'storage_key' => $key, 'storage_encryption' => 'laravel', 'media_type' => 'text/plain', 'sha256' => hash('sha256', $bytes), 'status' => 'active', 'malware_scan_status' => 'clean', 'malware_engine' => 'synthetic-policy-fixture', 'malware_scanned_sha256' => hash('sha256', $bytes), 'uploaded_by' => $promoter->id]);
+ DB::table('opportunity_documents')->insert(['id' => $document, 'opportunity_id' => $id, 'document_id' => $file, 'version' => 1, 'created_by' => $promoter->id, 'payload' => json_encode(['title' => 'QA', 'category' => 'qa', 'visibility' => 'internal'])]);
+ $payload = ['opportunity_category' => 'real_estate', 'official_title' => 'Imóvel sintético para ensaio QA', 'promoter_id' => $org, 'promoter_type' => 'private', 'internal_contact_id' => $contact, 'sector_id' => $ids[0][1], 'subsector_id' => $ids[1][0], 'economic_activity_id' => $ids[2][0], 'location_mode' => 'single', 'geographic_scope' => 'district', 'locations' => [$location], 'executive_summary' => trim(str_repeat('Resumo sintético QA. ', 20)), 'demand_statement' => trim(str_repeat('Necessidade sintética QA. ', 6)), 'documents' => [$document], 'evidences' => [['title' => 'QA', 'evidence_type' => 'qa', 'document_id' => $document]], 'publication_languages' => [['language_code' => 'pt-MZ', 'title' => 'QA', 'summary' => 'QA']], 'visibility' => 'internal', 'currency' => 'MZN', 'truth_declaration' => true, 'real_estate' => ['transaction_type' => 'sale', 'property_type' => 'warehouse', 'construction_status' => 'completed', 'property_condition' => 'good', 'land_area' => 1000, 'built_area' => 500, 'area_unit' => 'sqm', 'utilities' => [['type' => 'water', 'status' => 'existing']], 'occupancy_status' => 'vacant', 'title_type' => 'QA', 'registration_number' => 'QA-'.$id, 'encumbrances' => [['type' => 'none']], 'valuation' => ['value' => 1000, 'date' => '2026-10-10', 'method' => 'qa', 'appraiser' => 'QA', 'document_id' => $document], 'price' => 1000, 'use_license_document_id' => $document]];
+ $authority = (string) Str::uuid();
+ DB::table('authorities')->insert(['id' => $authority, 'catalog_version_id' => $version, 'organization_id' => $org, 'code' => 'QA-'.$id, 'authority_type' => 'qa-synthetic', 'label_pt_mz' => 'Entidade sintética QA', 'source_reference' => 'Synthetic policy fixture; not official', 'valid_from' => '2026-01-01', 'status' => 'published']);
+ $payload['real_estate']['utilities'] = array_map(fn ($type) => ['type' => $type, 'status' => 'existing'], ['electricity', 'water', 'sanitation', 'telecommunications', 'access']);
+ $payload['real_estate'] += ['title_document_id' => $document, 'title_holder_name' => 'Synthetic QA organization', 'issuing_authority_id' => $authority];
+
+ $this->loginFixture($promoter)->putJson('/minhas-oportunidades/'.$id.'/draft', ['etag' => $draft['etag'], 'canonical' => $payload, 'reason' => self::REASON])->assertOk();
+
+ return [$id, $promoter, $validator, $publisher, $payload, $document];
+ }
+}
diff --git a/tests/Feature/OrganizationCountryCommandsTest.php b/tests/Feature/OrganizationCountryCommandsTest.php
new file mode 100644
index 00000000..1e4b117a
--- /dev/null
+++ b/tests/Feature/OrganizationCountryCommandsTest.php
@@ -0,0 +1,130 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ config(['portal.organization_country_enabled' => true, 'portal.profile_access_enabled' => true]);
+ $this->actor = User::factory()->create();
+ $this->organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $this->organization, 'name' => 'SYNTHETIC country master', 'organization_type' => 'private', 'source_system' => 'synthetic-command-fixture', 'external_id' => 'SYNTHETIC-stable-source']);
+ DB::table('memberships')->insert(['user_id' => $this->actor->id, 'organization_id' => $this->organization, 'role' => 'officer']);
+ $this->actingAs($this->actor);
+ }
+
+ private function command(): array
+ {
+ return ['operation_key' => (string) Str::uuid(), 'version' => 1, 'country' => 'FR', 'source_reference' => 'SYNTHETIC PRIVATE declaration reference'];
+ }
+
+ private function url(?string $id = null): string
+ {
+ return '/api/v1/investment/organizations/'.($id ?? $this->organization).'/country';
+ }
+
+ public function test_replay_keeps_country_provenance_version_and_audit_identical(): void
+ {
+ $command = $this->command();
+ $first = $this->putJson($this->url(), $command)->assertOk()->assertJsonPath('version', 2)->json();
+ $before = DB::table('organizations')->where('id', $this->organization)->first();
+ $audits = DB::table('audit_events')->get()->toArray();
+ $this->putJson($this->url(), [...$command, 'operation_key' => strtoupper($command['operation_key'])])->assertExactJson($first);
+ $this->assertEquals($before, DB::table('organizations')->where('id', $this->organization)->first());
+ $this->assertEquals($audits, DB::table('audit_events')->get()->toArray());
+ $this->assertSame(2, DB::table('audit_events')->count());
+ $receipt = json_decode(DB::table('audit_events')->where('source_system', 'investment-workspace-command')->value('after_data'), true);
+ $this->assertStringNotContainsString('SYNTHETIC PRIVATE', json_encode($receipt));
+ $this->assertSame($command['source_reference'], json_decode(Crypt::decryptString($receipt['command_encrypted']), true)['payload']['source_reference']);
+ }
+
+ public function test_original_receipt_survives_a_later_change_without_reverting_current_country(): void
+ {
+ $command = $this->command();
+ $this->putJson($this->url(), $command)->assertOk();
+ $this->putJson($this->url(), [...$command, 'operation_key' => (string) Str::uuid(), 'version' => 2, 'country' => 'ZA'])->assertJsonPath('version', 3);
+ $before = DB::table('organizations')->where('id', $this->organization)->first();
+ $this->putJson($this->url(), $command)->assertExactJson(['version' => 2, 'country' => 'FR']);
+ $this->assertEquals($before, DB::table('organizations')->where('id', $this->organization)->first());
+ $this->assertSame('ZA', $before->incorporation_country_code);
+ }
+
+ public function test_changed_reference_country_target_or_operation_cannot_reuse_the_same_key(): void
+ {
+ $command = $this->command();
+ $this->putJson($this->url(), $command)->assertOk();
+ $this->putJson($this->url(), [...$command, 'source_reference' => 'SYNTHETIC altered reference'])->assertConflict();
+ $this->putJson($this->url(), [...$command, 'country' => 'ZA'])->assertConflict();
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC second master', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->actor->id, 'organization_id' => $id, 'role' => 'officer']);
+ $this->putJson($this->url($id), $command)->assertConflict();
+ $this->putJson('/api/v1/investment/profile', ['version' => 0, 'operation_key' => $command['operation_key'], 'payload' => ['residence_country_code' => 'PT']])->assertConflict();
+ $this->assertSame(0, DB::table('investment_accounts')->count());
+ $this->assertSame(2, DB::table('audit_events')->count());
+ }
+
+ public function test_revoked_representation_auditor_and_deleted_organization_cannot_read_a_replay_confirmation(): void
+ {
+ $command = $this->command();
+ $this->putJson($this->url(), $command)->assertOk();
+ $before = DB::table('organizations')->where('id', $this->organization)->first();
+ DB::table('memberships')->where('user_id', $this->actor->id)->update(['deleted_at' => now()]);
+ $this->putJson($this->url(), $command)->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->actor->id)->update(['deleted_at' => null]);
+ $approver = User::factory()->create();
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $approver, ['user_id' => $this->actor->id, 'role' => 'auditor', 'opportunity_types' => [], 'source' => 'synthetic-country-command-auditor']);
+ $this->actor->refresh();
+ $this->actingAs($this->actor)->withSession(['portal.access_revision' => $this->actor->portal_access_revision]);
+ $this->putJson($this->url(), $command)->assertForbidden();
+ DB::table('portal_role_assignments')->where('user_id', $this->actor->id)->update(['revoked_at' => now()]);
+ DB::table('organizations')->where('id', $this->organization)->update(['deleted_at' => now()]);
+ $this->putJson($this->url(), $command)->assertForbidden();
+ $after = DB::table('organizations')->where('id', $this->organization)->first();
+ $this->assertSame($before->incorporation_country_provenance, $after->incorporation_country_provenance);
+ $this->assertSame(2, $after->version_no);
+ }
+
+ public function test_invalid_country_reference_and_key_do_not_increment_version_and_legacy_requests_still_work(): void
+ {
+ $command = $this->command();
+ foreach ([['country' => 'ZZ'], ['source_reference' => 'x'], ['operation_key' => 'bad']] as $invalid) {
+ $this->putJson($this->url(), [...$command, ...$invalid])->assertUnprocessable()->assertJsonValidationErrors(array_keys($invalid));
+ }
+ $this->assertSame(1, DB::table('organizations')->where('id', $this->organization)->value('version_no'));
+ $this->assertSame(0, DB::table('audit_events')->count());
+ unset($command['operation_key']);
+ $this->putJson($this->url(), $command)->assertOk()->assertJsonPath('version', 2);
+ $this->assertSame(1, DB::table('audit_events')->count());
+ }
+
+ public function test_current_membership_role_changes_project_the_same_authority_as_the_write_endpoint(): void
+ {
+ $this->getJson('/api/v1/investment/profile')->assertOk()->assertJsonCount(1, 'organizations')->assertJsonPath('organizations.0.canEdit', true);
+ $this->putJson($this->url(), $this->command())->assertOk();
+ DB::table('memberships')->where('user_id', $this->actor->id)->update(['role' => 'viewer']);
+ $this->getJson('/api/v1/investment/profile')->assertOk()->assertJsonPath('organizations.0.canEdit', false);
+ $this->putJson($this->url(), [...$this->command(), 'version' => 2])->assertForbidden();
+ }
+}
diff --git a/tests/Feature/OrganizationCountryReuseCommandsTest.php b/tests/Feature/OrganizationCountryReuseCommandsTest.php
new file mode 100644
index 00000000..08ad6ba7
--- /dev/null
+++ b/tests/Feature/OrganizationCountryReuseCommandsTest.php
@@ -0,0 +1,148 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ config(['portal.organization_country_enabled' => true, 'portal.profile_access_enabled' => true]);
+ $this->actor = User::factory()->create();
+ $this->actingAs($this->actor);
+ $this->organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $this->organization, 'name' => 'SYNTHETIC reuse source', 'organization_type' => 'private', 'source_system' => 'synthetic-reuse-fixture', 'external_id' => 'SYNTHETIC-stable', 'version_no' => 3, 'incorporation_country_code' => 'FR', 'incorporation_country_provenance' => json_encode(['kind' => 'representative_declaration', 'reference' => 'SYNTHETIC source reference'])]);
+ DB::table('memberships')->insert(['user_id' => $this->actor->id, 'organization_id' => $this->organization, 'role' => 'viewer']);
+ $this->putJson('/api/v1/investment/profile', ['version' => 0, 'payload' => ['residence_country_code' => 'PT']])->assertOk();
+ $this->company = $this->postJson('/api/v1/investment/companies', ['version' => 0, 'payload' => ['name' => 'SYNTHETIC private reuse target', 'role' => 'SYNTHETIC representative', 'incorporation_country_code' => 'MZ']])->assertOk()->json('id');
+ $this->submission = $this->postJson('/api/v1/investment/submissions', ['company_id' => $this->company])->assertCreated()->json('id');
+ }
+
+ private function command(): array
+ {
+ return ['version' => 1, 'organization_id' => $this->organization, 'organization_version' => 3, 'operation_key' => (string) Str::uuid()];
+ }
+
+ private function url(?string $id = null): string
+ {
+ return '/api/v1/investment/companies/'.($id ?? $this->company).'/organization-country';
+ }
+
+ private function target(): \stdClass
+ {
+ return DB::table('investment_company_declarations')->where('id', $this->company)->first();
+ }
+
+ public function test_read_authority_can_reuse_once_and_replay_keeps_the_original_snapshot_and_encrypted_receipt(): void
+ {
+ $command = $this->command();
+ $submission = DB::table('investment_submissions')->where('id', $this->submission)->first();
+ $first = $this->postJson($this->url(), $command)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->json();
+ $target = $this->target();
+ $auditCount = DB::table('audit_events')->count();
+ $this->postJson($this->url(strtoupper($this->company)), [...$command, 'organization_id' => strtoupper($this->organization), 'operation_key' => strtoupper($command['operation_key'])])->assertExactJson($first);
+ $this->assertEquals($target, $this->target());
+ $this->assertSame($auditCount, DB::table('audit_events')->count());
+ $payload = json_decode(Crypt::decryptString($target->payload), true);
+ $this->assertSame('FR', $payload['incorporation_country_code']);
+ $this->assertSame(3, $payload['organization_country_snapshot']['organization_version']);
+ $receipt = json_decode(DB::table('audit_events')->where('source_system', 'investment-workspace-command')->value('after_data'), true);
+ $this->assertArrayNotHasKey('result', $receipt);
+ $this->assertArrayNotHasKey('country', $receipt);
+ $this->assertSame(['version' => 2, 'country' => 'FR'], json_decode(Crypt::decryptString($receipt['result_encrypted']), true));
+ $this->assertEquals($submission, DB::table('investment_submissions')->where('id', $this->submission)->first());
+ $this->getJson('/api/v1/investment/profile')->assertJsonPath('account.payload.residence_country_code', 'PT')->assertJsonPath('organizations.0.canEdit', false);
+ $this->assertSame(1, DB::table('organizations')->count());
+ $this->assertSame(1, DB::table('memberships')->count());
+ }
+
+ public function test_replay_reads_its_original_country_after_later_source_and_target_changes_even_if_source_country_is_now_missing(): void
+ {
+ $first = $this->command();
+ $this->postJson($this->url(), $first)->assertOk();
+ DB::table('organizations')->where('id', $this->organization)->update(['version_no' => 4, 'incorporation_country_code' => 'ZA']);
+ $this->postJson($this->url(), [...$first, 'operation_key' => (string) Str::uuid(), 'version' => 2, 'organization_version' => 4])->assertJsonPath('version', 3)->assertJsonPath('country', 'ZA');
+ $target = $this->target();
+ DB::table('organizations')->where('id', $this->organization)->update(['version_no' => 5, 'incorporation_country_code' => null]);
+ $this->postJson($this->url(), $first)->assertExactJson(['version' => 2, 'country' => 'FR']);
+ $this->assertEquals($target, $this->target());
+ $this->postJson($this->url(), [...$first, 'operation_key' => (string) Str::uuid(), 'version' => 3, 'organization_version' => 5])->assertUnprocessable();
+ $this->assertEquals($target, $this->target());
+ $this->assertSame(2, DB::table('audit_events')->where('action', 'organization_country_reused')->count());
+ }
+
+ public function test_stale_versions_malformed_keys_and_changed_intentions_do_not_write(): void
+ {
+ $command = $this->command();
+ $before = $this->target();
+ $this->postJson($this->url(), [...$command, 'organization_version' => 2])->assertConflict();
+ $this->postJson($this->url(), [...$command, 'version' => 2])->assertConflict();
+ $this->postJson($this->url(), [...$command, 'operation_key' => 'bad'])->assertUnprocessable()->assertJsonValidationErrors('operation_key');
+ $this->assertEquals($before, $this->target());
+ $this->postJson($this->url(), $command)->assertOk();
+ $after = $this->target();
+ $this->postJson($this->url(), [...$command, 'organization_version' => 4])->assertConflict();
+ $this->putJson('/api/v1/investment/profile', ['version' => 1, 'operation_key' => $command['operation_key'], 'payload' => ['residence_country_code' => 'ZA']])->assertConflict();
+ $this->assertEquals($after, $this->target());
+ }
+
+ public function test_replay_requires_current_source_access_and_current_ownership_and_can_resume_after_representation_is_restored(): void
+ {
+ $command = $this->command();
+ $this->postJson($this->url(), $command)->assertOk();
+ $target = $this->target();
+ DB::table('memberships')->where('user_id', $this->actor->id)->update(['deleted_at' => now()]);
+ $this->postJson($this->url(), $command)->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->actor->id)->update(['deleted_at' => null]);
+ $this->postJson($this->url(), $command)->assertExactJson(['version' => 2, 'country' => 'FR']);
+ DB::table('organizations')->where('id', $this->organization)->update(['deleted_at' => now()]);
+ $this->postJson($this->url(), $command)->assertForbidden();
+ $this->actingAs(User::factory()->create())->postJson($this->url(), $command)->assertNotFound();
+ $this->assertEquals($target, $this->target());
+ }
+
+ public function test_legacy_reuse_without_a_key_is_supported_and_its_country_never_updates_old_submissions(): void
+ {
+ $command = $this->command();
+ unset($command['operation_key']);
+ $before = DB::table('investment_submissions')->where('id', $this->submission)->first();
+ $this->postJson($this->url(), $command)->assertOk()->assertJsonPath('country', 'FR');
+ $new = $this->postJson('/api/v1/investment/submissions', ['company_id' => $this->company])->assertCreated()->json('id');
+ $this->getJson('/api/v1/investment/submissions/'.$new)->assertJsonPath('submission.payload.incorporation_country_code', 'FR')->assertJsonPath('submission.payload.organization_country_snapshot.organization_version', 3);
+ $this->assertEquals($before, DB::table('investment_submissions')->where('id', $this->submission)->first());
+ $this->assertSame(0, DB::table('audit_events')->where('source_system', 'investment-workspace-command')->count());
+ }
+
+ public function test_a_receipt_failure_rolls_back_the_company_and_business_audit_together(): void
+ {
+ $before = $this->target();
+ $auditCount = DB::table('audit_events')->count();
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_reject_country_reuse_receipt CHECK (source_system <> 'investment-workspace-command')");
+ $response = $this->postJson($this->url(), $this->command())->assertStatus(503);
+ $this->assertStringNotContainsString('SQLSTATE', $response->getContent());
+ $this->assertEquals($before, $this->target());
+ $this->assertSame($auditCount, DB::table('audit_events')->count());
+ }
+}
diff --git a/tests/Feature/PartnershipAgreementHistoryTest.php b/tests/Feature/PartnershipAgreementHistoryTest.php
new file mode 100644
index 00000000..48301691
--- /dev/null
+++ b/tests/Feature/PartnershipAgreementHistoryTest.php
@@ -0,0 +1,256 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC agreement', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submit');
+ $record = $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $interest = $service->interest($this->candidate, $record->id, ['proposal' => 'SYNTHETIC candidacy', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $service->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connect');
+ $this->roomId = (int) DB::table('partnership_rooms')->where('interest_id', $interest->id)->value('id');
+ $this->actingAs($this->owner)->postJson($this->url(), ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC instrument', 'terms' => 'SYNTHETIC terms', 'reason' => 'SYNTHETIC record'])->assertOk();
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/salas/'.$this->roomId.'/acordo';
+ }
+
+ private function command(string $action = 'cancel'): array
+ {
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+
+ return ['client_key' => (string) Str::uuid(), 'version' => $context['room']->version, 'partnership_version' => $context['partnership']->version, 'interest_version' => $context['interest']->version, 'action' => $action, 'reason' => 'SYNTHETIC documented action'];
+ }
+
+ public function test_history_reads_the_saved_instrument_without_changing_the_room(): void
+ {
+ $room = DB::table('partnership_rooms')->where('id', $this->roomId)->first();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->getJson($this->history())->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('room_id', $this->roomId)
+ ->assertJsonCount(1, 'entries')->assertJsonPath('entries.0.after.instrument.title', 'SYNTHETIC instrument')
+ ->assertJsonPath('entries.0.after.instrument.legal_signature_status', 'not_verified')->assertJsonPath('entries.0.previous.instrument_availability', 'not_recorded');
+ $this->assertEquals($room, DB::table('partnership_rooms')->where('id', $this->roomId)->first());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+
+ private function history(): string
+ {
+ return '/parcerias/salas/'.$this->roomId.'/historico';
+ }
+
+ private function record(string $title = 'SYNTHETIC next instrument'): void
+ {
+ app(PartnershipAgreements::class)->act($this->owner, $this->roomId, [...$this->command('record'), 'title' => $title, 'terms' => 'SYNTHETIC frozen conditions']);
+ }
+
+ private function alterEvent(callable $change): void
+ {
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_agreement.changed.v1')->orderByDesc('aggregate_version')->first();
+ $payload = json_decode($event->payload, true);
+ $payload['payload'] = $change($payload['payload']);
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ }
+
+ public function test_both_parties_read_closed_history_but_moderation_is_not_private_room_access(): void
+ {
+ $this->postJson($this->url(), $this->command())->assertOk();
+ $this->actingAs($this->candidate)->getJson($this->history())->assertOk()->assertJsonPath('entries.0.action', 'cancel');
+ $this->actingAs($this->owner)->get($this->history())->assertOk()->assertInertia(fn (Assert $page) => $page->component('partnerships/agreement-history')->where('room_id', $this->roomId));
+ $other = User::factory()->create();
+ config(['portal.managers' => [$other->email]]);
+ $this->actingAs($other)->getJson($this->history())->assertForbidden();
+ $this->getJson('/parcerias/salas/999999999/historico')->assertNotFound();
+ }
+
+ public function test_instruments_and_confirmations_are_frozen_and_only_projected_fields_leave_events(): void
+ {
+ $this->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $this->alterEvent(function ($data) {
+ $data['applied']['agreement']['private_secret'] = 'SYNTHETIC do not disclose';
+ $data['applied']['agreement']['confirmations']['proponent']['private_secret'] = 'SYNTHETIC do not disclose';
+
+ return $data;
+ });
+ $instrument = json_decode(DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'), true);
+ $instrument['title'] = 'SYNTHETIC current title never a historical fallback';
+ DB::table('partnership_rooms')->where('id', $this->roomId)->update(['agreement' => json_encode($instrument)]);
+ $result = $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.previous.instrument.title', 'SYNTHETIC instrument')
+ ->assertJsonPath('entries.0.after.instrument.title', 'SYNTHETIC instrument')->assertJsonPath('entries.0.confirmation_party', 'proponent')
+ ->assertJsonPath('entries.0.after.instrument.confirmations.proponent.reason', 'SYNTHETIC documented action');
+ foreach (['private_secret', 'do not disclose', 'command_hash', 'client_key', '_notification_context', 'previous_versions', 'current title never'] as $secret) {
+ $this->assertStringNotContainsString($secret, $result->getContent());
+ }
+ }
+
+ public function test_pagination_is_bounded_and_inserting_a_newer_event_does_not_repeat_older_pages(): void
+ {
+ for ($i = 0; $i < 12; $i++) {
+ $this->record('SYNTHETIC revision '.$i);
+ }
+ $first = $this->getJson($this->history())->assertOk()->assertJsonCount(10, 'entries');
+ $next = $first->json('next_url');
+ $this->assertIsString($next);
+ $this->record('SYNTHETIC inserted after pagination');
+ $older = $this->getJson($next)->assertOk()->assertJsonCount(3, 'entries')->assertJsonPath('next_url', null)->assertJsonPath('older_page', true);
+ $versions = [...array_column($first->json('entries'), 'version'), ...array_column($older->json('entries'), 'version')];
+ $this->assertCount(13, array_unique($versions));
+ $sorted = $versions;
+ rsort($sorted);
+ $this->assertSame($sorted, $versions);
+ }
+
+ public function test_cursor_is_bound_to_account_room_relationship_and_purpose(): void
+ {
+ for ($i = 0; $i < 10; $i++) {
+ $this->record();
+ }
+ $next = $this->getJson($this->history())->assertOk()->json('next_url');
+ $this->actingAs($this->candidate)->getJson($next)->assertUnprocessable();
+ $this->actingAs($this->owner)->getJson($this->history().'?before=invalid')->assertUnprocessable();
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+ foreach (['purpose' => 'publication', 'actor' => $this->candidate->id, 'room' => $this->roomId + 1, 'interest' => $context['interest']->id + 1, 'partnership' => $context['partnership']->id + 1, 'before' => '1'] as $key => $wrong) {
+ $cursor = ['purpose' => 'agreement', 'actor' => $this->owner->id, 'room' => $this->roomId, 'interest' => (int) $context['interest']->id, 'partnership' => (int) $context['partnership']->id, 'before' => 9999];
+ $cursor[$key] = $wrong;
+ $this->getJson($this->history().'?before='.rawurlencode(Crypt::encryptString(json_encode($cursor))))->assertUnprocessable();
+ }
+ }
+
+ public function test_current_representative_cannot_inherit_an_older_organization_instrument(): void
+ {
+ $a = (string) Str::uuid();
+ $b = (string) Str::uuid();
+ $viewer = User::factory()->create();
+ foreach ([$a, $b] as $org) {
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ }
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $b, 'role' => 'viewer']);
+ $exchange = app(PartnershipExchange::class);
+ $parent = $exchange->room($this->owner, $this->roomId)['partnership'];
+ $parent = $exchange->save($this->owner, ['version' => $parent->version, 'kind' => 'seeking', 'organization_id' => $a], $parent->id);
+ $this->record('SYNTHETIC OLD organization instrument');
+ $exchange->save($this->owner, ['version' => $parent->version, 'kind' => 'seeking', 'organization_id' => $b], $parent->id);
+ $this->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $result = $this->actingAs($viewer)->getJson($this->history())->assertOk()->assertJsonPath('entries.0.restricted', false)
+ ->assertJsonPath('entries.0.after.instrument_availability', 'restricted')->assertJsonPath('entries.1.restricted', true);
+ $this->assertStringNotContainsString('OLD organization instrument', $result->getContent());
+ $this->actingAs($this->candidate)->getJson($this->history())->assertOk()->assertJsonPath('entries.0.after.instrument.title', 'SYNTHETIC OLD organization instrument');
+ DB::table('memberships')->where('user_id', $viewer->id)->update(['deleted_at' => now()]);
+ $this->actingAs($viewer)->getJson($this->history())->assertForbidden();
+ }
+
+ public function test_missing_or_inconsistent_historical_scope_hides_content_instead_of_using_current_parties(): void
+ {
+ $this->alterEvent(function ($data) {
+ $data['_notification_context']['interest']['id']++;
+
+ return $data;
+ });
+ $result = $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.restricted', true)->assertJsonPath('entries.0.reason', null)->assertJsonPath('entries.0.after.availability', 'scope_unknown');
+ $this->assertStringNotContainsString('SYNTHETIC instrument', $result->getContent());
+ $this->alterEvent(function ($data) {
+ unset($data['_notification_context']);
+
+ return $data;
+ });
+ $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.after.availability', 'scope_unknown');
+ }
+
+ public function test_legacy_events_without_snapshots_are_explicitly_incomplete(): void
+ {
+ $this->alterEvent(function ($data) {
+ unset($data['previous'], $data['applied']);
+
+ return $data;
+ });
+ $result = $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.previous.availability', 'not_recorded')->assertJsonPath('entries.0.after.availability', 'not_recorded');
+ $this->assertStringNotContainsString('SYNTHETIC instrument', $result->getContent());
+ }
+
+ public function test_foreign_snapshot_id_and_unknown_instrument_origin_do_not_disclose_values(): void
+ {
+ $this->alterEvent(function ($data) {
+ $data['previous'] = $data['applied'];
+ $data['previous']['id']++;
+ unset($data['applied']['agreement']['recorded_context']);
+
+ return $data;
+ });
+ $result = $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.previous.availability', 'scope_unknown')->assertJsonPath('entries.0.after.instrument_availability', 'scope_unknown');
+ $this->assertStringNotContainsString('SYNTHETIC instrument', $result->getContent());
+ }
+
+ public function test_legacy_confirmation_shapes_remain_explicit_and_private_fields_are_omitted(): void
+ {
+ $this->alterEvent(function ($data) {
+ $data['applied']['agreement']['confirmations'] = ['proponent' => ['actor_id' => 'wrong', 'date' => ['SYNTHETIC private']], 'unknown-secret-key' => ['SYNTHETIC private']];
+
+ return $data;
+ });
+ $result = $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.after.instrument.confirmations.proponent.actor_id', null)->assertJsonPath('entries.0.after.instrument.confirmations._unrecognized_references', true);
+ $this->assertStringNotContainsString('unknown-secret-key', $result->getContent());
+ $this->assertStringNotContainsString('SYNTHETIC private', $result->getContent());
+ $this->alterEvent(function ($data) {
+ $data['applied']['agreement']['confirmations'] = null;
+
+ return $data;
+ });
+ $this->getJson($this->history())->assertOk()->assertJsonPath('entries.0.after.instrument.confirmations', null);
+ }
+
+ public function test_another_room_is_never_included_in_the_history(): void
+ {
+ $exchange = app(PartnershipExchange::class);
+ $context = $exchange->room($this->owner, $this->roomId);
+ $other = User::factory()->create();
+ $interest = $exchange->interest($other, $context['partnership']->id, ['proposal' => 'SYNTHETIC other candidacy', 'payload' => ['consent' => true]]);
+ $interest = $exchange->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $exchange->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connect');
+ $room = DB::table('partnership_rooms')->where('interest_id', $interest->id)->first();
+ app(PartnershipAgreements::class)->act($this->owner, $room->id, ['version' => 1, 'action' => 'record', 'reason' => 'SYNTHETIC other', 'title' => 'SYNTHETIC OTHER PRIVATE', 'terms' => 'SYNTHETIC private']);
+ $result = $this->getJson($this->history())->assertOk()->assertJsonCount(1, 'entries');
+ $this->assertStringNotContainsString('OTHER PRIVATE', $result->getContent());
+ $this->actingAs($other)->getJson($this->history())->assertForbidden();
+ }
+}
diff --git a/tests/Feature/PartnershipAgreementProjectionTest.php b/tests/Feature/PartnershipAgreementProjectionTest.php
new file mode 100644
index 00000000..aa5395c0
--- /dev/null
+++ b/tests/Feature/PartnershipAgreementProjectionTest.php
@@ -0,0 +1,235 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC agreement', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submit');
+ $record = $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $interest = $service->interest($this->candidate, $record->id, ['proposal' => 'SYNTHETIC candidacy', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $service->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connect');
+ $this->roomId = (int) DB::table('partnership_rooms')->where('interest_id', $interest->id)->value('id');
+ $this->actingAs($this->owner)->postJson($this->url(), ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC instrument', 'terms' => 'SYNTHETIC terms', 'reason' => 'SYNTHETIC record'])->assertOk();
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/salas/'.$this->roomId.'/acordo';
+ }
+
+ private function command(string $action = 'cancel'): array
+ {
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+
+ return ['client_key' => (string) Str::uuid(), 'version' => $context['room']->version, 'partnership_version' => $context['partnership']->version, 'interest_version' => $context['interest']->version, 'action' => $action, 'reason' => 'SYNTHETIC documented action'];
+ }
+
+ public function test_current_room_does_not_disclose_versions_from_an_older_organization(): void
+ {
+ $a = (string) Str::uuid();
+ $b = (string) Str::uuid();
+ $viewer = User::factory()->create();
+ foreach ([$a, $b] as $org) {
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ }
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $b, 'role' => 'viewer']);
+ $exchange = app(PartnershipExchange::class);
+ $parent = $exchange->room($this->owner, $this->roomId)['partnership'];
+ $parent = $exchange->save($this->owner, ['version' => $parent->version, 'kind' => 'seeking', 'organization_id' => $a], $parent->id);
+ $this->postJson($this->url(), [...$this->command('record'), 'title' => 'SYNTHETIC OLD PRIVATE INSTRUMENT', 'terms' => 'SYNTHETIC OLD PRIVATE CONDITIONS'])->assertOk();
+ $exchange->save($this->owner, ['version' => $parent->version, 'kind' => 'seeking', 'organization_id' => $b], $parent->id);
+ $this->postJson($this->url(), [...$this->command('record'), 'title' => 'SYNTHETIC CURRENT INSTRUMENT', 'terms' => 'SYNTHETIC CURRENT CONDITIONS'])->assertOk();
+ $saved = DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement');
+ $response = $this->actingAs($viewer)->getJson('/parcerias/salas/'.$this->roomId)->assertOk()->assertJsonPath('room.agreement.title', 'SYNTHETIC CURRENT INSTRUMENT')->assertJsonMissingPath('room.agreement.previous_versions');
+ $this->assertStringNotContainsString('OLD PRIVATE', $response->getContent());
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ $this->getJson('/parcerias/salas/'.$this->roomId.'/historico')->assertOk()->assertJsonPath('entries.1.restricted', true)->assertJsonPath('entries.1.after.availability', 'restricted');
+ $this->actingAs($this->candidate)->getJson('/parcerias/salas/'.$this->roomId.'/historico')->assertOk()->assertJsonPath('entries.1.after.instrument.title', 'SYNTHETIC OLD PRIVATE INSTRUMENT');
+ }
+
+ private function roomUrl(): string
+ {
+ return '/parcerias/salas/'.$this->roomId;
+ }
+
+ private function instrument(): array
+ {
+ return json_decode(DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'), true);
+ }
+
+ private function storeInstrument(mixed $value): string
+ {
+ DB::table('partnership_rooms')->where('id', $this->roomId)->update(['agreement' => json_encode($value)]);
+
+ return DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement');
+ }
+
+ public function test_current_fields_and_named_confirmations_survive_while_private_extensions_do_not(): void
+ {
+ $this->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $this->actingAs($this->candidate)->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $instrument = $this->instrument();
+ $instrument['private_extension'] = ['secret' => 'SYNTHETIC INTERNAL SECRET'];
+ $instrument['confirmations']['proponent']['actor_name'] = 'SYNTHETIC FORGED NAME';
+ $instrument['confirmations']['proponent']['private_extension'] = 'SYNTHETIC INTERNAL SECRET';
+ $saved = $this->storeInstrument($instrument);
+ $response = $this->actingAs($this->owner)->getJson($this->roomUrl())->assertOk()
+ ->assertJsonPath('room.status', 'agreed')->assertJsonPath('room.agreement.title', 'SYNTHETIC instrument')
+ ->assertJsonPath('room.agreement.terms', 'SYNTHETIC terms')->assertJsonPath('room.agreement.legal_signature_status', 'not_verified')
+ ->assertJsonPath('room.agreement.confirmations.proponent.actor_id', $this->owner->id)
+ ->assertJsonPath('room.agreement.confirmations.candidate.actor_id', $this->candidate->id)
+ ->assertJsonPath('room.agreement.confirmations.proponent.reason', 'SYNTHETIC documented action')->assertJsonCount(1, 'agreementCommands');
+ foreach (['previous_versions', 'recorded_context', 'private_extension', 'INTERNAL SECRET', 'FORGED NAME'] as $hidden) {
+ $this->assertStringNotContainsString($hidden, $response->getContent());
+ }
+ $this->assertSame($instrument['confirmations']['proponent']['date'], $response->json('room.agreement.confirmations.proponent.date'));
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ }
+
+ public function test_native_inertia_uses_the_same_current_projection_and_private_response(): void
+ {
+ $instrument = $this->instrument();
+ $instrument['previous_versions'] = [['title' => 'SYNTHETIC NATIVE PRIVATE']];
+ $instrument['private_extension'] = 'SYNTHETIC NATIVE PRIVATE';
+ $this->storeInstrument($instrument);
+ $this->get($this->roomUrl())->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertInertia(fn (Assert $page) => $page->component('partnerships/room')->where('room.id', $this->roomId)
+ ->where('room.agreement.title', 'SYNTHETIC instrument')->missing('room.agreement.previous_versions')->missing('room.agreement.recorded_context'))
+ ->assertDontSee('NATIVE PRIVATE');
+ }
+
+ public function test_unrecognized_legacy_instruments_are_marked_without_echoing_opaque_content(): void
+ {
+ foreach (['SYNTHETIC OPAQUE PRIVATE', false, 123, ['SYNTHETIC OPAQUE PRIVATE']] as $value) {
+ $saved = $this->storeInstrument($value);
+ $response = $this->getJson($this->roomUrl())->assertOk()->assertJsonPath('room.agreement', 'unrecognized');
+ $this->assertStringNotContainsString('OPAQUE PRIVATE', $response->getContent());
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ }
+ $this->storeInstrument(null);
+ $this->getJson($this->roomUrl())->assertOk()->assertJsonPath('room.agreement', null);
+ }
+
+ public function test_missing_null_empty_and_malformed_confirmation_maps_remain_distinguishable(): void
+ {
+ $base = $this->instrument();
+ foreach ([null, [], (object) [], 'SYNTHETIC MAP PRIVATE', [['actor_id' => $this->owner->id]]] as $map) {
+ $saved = $this->storeInstrument([...$base, 'confirmations' => $map]);
+ $response = $this->getJson($this->roomUrl())->assertOk();
+ $projected = $response->json('room.agreement.confirmations');
+ if ($map === null) {
+ $this->assertNull($projected);
+ } elseif ($map === [] || $map instanceof \stdClass) {
+ $this->assertSame([], $projected);
+ } else {
+ $this->assertSame('unrecognized', $projected);
+ }
+ $this->assertStringNotContainsString('MAP PRIVATE', $response->getContent());
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ }
+ unset($base['confirmations']);
+ $this->storeInstrument($base);
+ $this->getJson($this->roomUrl())->assertOk()->assertJsonMissingPath('room.agreement.confirmations');
+ }
+
+ public function test_incomplete_stamps_and_unknown_references_do_not_disclose_their_raw_fields(): void
+ {
+ $value = $this->instrument();
+ $value['confirmations'] = ['proponent' => ['actor_id' => 'SYNTHETIC BAD PRIVATE', 'date' => ['SYNTHETIC BAD PRIVATE'], 'reason' => ['secret' => 'SYNTHETIC BAD PRIVATE']], 'SYNTHETIC UNKNOWN PRIVATE' => ['actor_id' => $this->candidate->id]];
+ $saved = $this->storeInstrument($value);
+ $response = $this->getJson($this->roomUrl())->assertOk()->assertJsonPath('room.agreement.confirmations.proponent.actor_id', null)
+ ->assertJsonPath('room.agreement.confirmations.proponent.date', null)->assertJsonPath('room.agreement.confirmations.proponent.reason', null)
+ ->assertJsonPath('room.agreement.confirmations._unrecognized_references', true)->assertJsonMissingPath('room.agreement.confirmations.candidate');
+ $this->assertStringNotContainsString('PRIVATE', $response->getContent());
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ }
+
+ public function test_reads_and_replay_do_not_sanitize_the_stored_aggregate_or_its_audit_snapshots(): void
+ {
+ $original = $this->instrument();
+ $original['private_extension'] = 'SYNTHETIC PRESERVED PRIVATE';
+ $original['previous_versions'] = [['title' => 'SYNTHETIC HISTORICAL PRIVATE']];
+ $this->storeInstrument($original);
+ $command = [...$this->command('record'), 'title' => 'SYNTHETIC new public-facing title', 'terms' => 'SYNTHETIC new terms'];
+ $this->postJson($this->url(), $command)->assertOk();
+ $saved = DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement');
+ $stored = $this->instrument();
+ $this->assertSame('SYNTHETIC PRESERVED PRIVATE', $stored['previous_versions'][1]['private_extension']);
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->getJson($this->roomUrl())->assertOk()->assertJsonMissingPath('room.agreement.previous_versions');
+ $this->postJson($this->url(), $command)->assertOk()->assertJsonPath('replayed', true);
+ $this->assertSame($saved, DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'));
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_agreement.changed.v1')->orderByDesc('aggregate_version')->first();
+ $data = json_decode($event->payload, true)['payload'];
+ $this->assertSame('SYNTHETIC PRESERVED PRIVATE', $data['previous']['agreement']['private_extension']);
+ $this->assertSame($stored, $data['applied']['agreement']);
+ }
+
+ public function test_current_representation_and_private_room_access_still_apply(): void
+ {
+ $outsider = User::factory()->create();
+ config(['portal.managers' => [$outsider->email]]);
+ $this->actingAs($outsider)->getJson($this->roomUrl())->assertForbidden();
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC access', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'viewer']);
+ DB::table('portal_partnerships')->where('id', app(PartnershipExchange::class)->room($this->owner, $this->roomId)['partnership']->id)->update(['organization_id' => $org]);
+ $this->actingAs($this->owner)->getJson($this->roomUrl())->assertOk()->assertJsonPath('canWrite', false)->assertJsonPath('agreementCommands', []);
+ $this->postJson($this->url(), $this->command('confirm'))->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->owner->id)->update(['deleted_at' => now()]);
+ $this->getJson($this->roomUrl())->assertForbidden();
+ $this->actingAs($this->candidate)->getJson($this->roomUrl())->assertOk();
+ }
+
+ public function test_other_room_consumers_link_to_the_room_without_embedding_its_instrument_history(): void
+ {
+ $value = $this->instrument();
+ $value['previous_versions'] = [['title' => 'SYNTHETIC OTHER CONSUMER PRIVATE']];
+ $this->storeInstrument($value);
+ $parent = app(PartnershipExchange::class)->room($this->owner, $this->roomId)['partnership'];
+ $response = $this->getJson('/parcerias/'.$parent->id)->assertOk()->assertJsonPath('interests.0.room_id', $this->roomId);
+ $this->assertStringNotContainsString('OTHER CONSUMER PRIVATE', $response->getContent());
+ $this->actingAs($this->candidate)->get('/parcerias/painel')->assertOk()
+ ->assertInertia(fn (Assert $page) => $page->component('partnerships/dashboard')->where('interests.0.room_id', $this->roomId))
+ ->assertDontSee('OTHER CONSUMER PRIVATE');
+ }
+}
diff --git a/tests/Feature/PartnershipAgreementRecoveryTest.php b/tests/Feature/PartnershipAgreementRecoveryTest.php
new file mode 100644
index 00000000..c02b681e
--- /dev/null
+++ b/tests/Feature/PartnershipAgreementRecoveryTest.php
@@ -0,0 +1,232 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC agreement', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submit');
+ $record = $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $interest = $service->interest($this->candidate, $record->id, ['proposal' => 'SYNTHETIC candidacy', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $service->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connect');
+ $this->roomId = (int) DB::table('partnership_rooms')->where('interest_id', $interest->id)->value('id');
+ $this->actingAs($this->owner)->postJson($this->url(), ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC instrument', 'terms' => 'SYNTHETIC terms', 'reason' => 'SYNTHETIC record'])->assertOk();
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/salas/'.$this->roomId.'/acordo';
+ }
+
+ private function command(string $action = 'cancel'): array
+ {
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+
+ return ['client_key' => (string) Str::uuid(), 'version' => $context['room']->version, 'partnership_version' => $context['partnership']->version, 'interest_version' => $context['interest']->version, 'action' => $action, 'reason' => 'SYNTHETIC documented action'];
+ }
+
+ public function test_cancel_replay_after_terminal_state_is_a_read_without_repeated_events(): void
+ {
+ $data = $this->command();
+ $this->postJson($this->url(), $data)->assertOk();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('status', 'cancelled');
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+
+ public function test_changed_proposal_context_requires_review_even_when_room_version_is_unchanged(): void
+ {
+ $data = $this->command('confirm');
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+ $record = $context['partnership'];
+ app(PartnershipExchange::class)->save($this->owner, ['version' => $record->version, 'kind' => 'seeking', 'title' => 'SYNTHETIC changed proposal'], $record->id);
+ $this->postJson($this->url(), $data)->assertConflict();
+ $this->assertSame(2, DB::table('partnership_rooms')->where('id', $this->roomId)->value('version'));
+ }
+
+ private function instrument(): array
+ {
+ return json_decode(DB::table('partnership_rooms')->where('id', $this->roomId)->value('agreement'), true);
+ }
+
+ private function confirmBoth(): void
+ {
+ $this->actingAs($this->owner)->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $this->actingAs($this->candidate)->postJson($this->url(), $this->command('confirm'))->assertOk()->assertJsonPath('status', 'agreed');
+ $this->actingAs($this->owner);
+ }
+
+ public function test_record_replay_preserves_a_later_confirmation(): void
+ {
+ $data = [...$this->command('record'), 'title' => 'SYNTHETIC revised instrument', 'terms' => 'SYNTHETIC revised terms'];
+ $this->postJson($this->url(), $data)->assertOk();
+ $this->postJson($this->url(), $this->command('confirm'))->assertOk();
+ $before = $this->instrument();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('saved_version', 3);
+ $this->assertSame($before, $this->instrument());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_key_conflicts_and_case_normalization_do_not_duplicate_decisions(): void
+ {
+ $data = $this->command('confirm');
+ $this->postJson($this->url(), $data)->assertOk();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), [...$data, 'reason' => 'SYNTHETIC changed reason'])->assertConflict();
+ $this->postJson($this->url(), [...$data, 'client_key' => strtoupper($data['client_key'])])->assertOk()->assertJsonPath('replayed', true);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_only_the_two_named_parties_count_and_supplied_party_does_not_override_authority(): void
+ {
+ $agreement = $this->instrument();
+ $agreement['confirmations'] = ['unrelated' => ['actor_id' => $this->candidate->id, 'date' => 'SYNTHETIC']];
+ DB::table('partnership_rooms')->where('id', $this->roomId)->update(['agreement' => json_encode($agreement)]);
+ $data = $this->command('confirm');
+ $this->postJson($this->url(), [...$data, 'party' => 'candidate', 'actor_id' => $this->candidate->id])->assertOk()->assertJsonPath('status', 'agreement_recorded');
+ $this->assertSame($this->owner->id, $this->instrument()['confirmations']['proponent']['actor_id']);
+ $this->assertArrayNotHasKey('candidate', $this->instrument()['confirmations']);
+ $this->actingAs($this->candidate)->postJson($this->url(), [...$this->command('confirm'), 'client_key' => $data['client_key']])->assertOk()->assertJsonPath('replayed', false)->assertJsonPath('status', 'agreed');
+ $this->assertSame('not_verified', $this->instrument()['legal_signature_status']);
+ }
+
+ public function test_record_and_renew_preserve_versions_and_reset_only_their_confirmation_set(): void
+ {
+ $this->postJson($this->url(), [...$this->command('record'), 'title' => 'SYNTHETIC version two', 'terms' => 'SYNTHETIC version two terms'])->assertOk();
+ $this->assertSame('SYNTHETIC instrument', $this->instrument()['previous_versions'][0]['title']);
+ $this->confirmBoth();
+ $data = $this->command('renew');
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('status', 'negotiation');
+ $instrument = $this->instrument();
+ $this->assertCount(2, $instrument['previous_versions']);
+ $this->assertSame([], $instrument['confirmations']);
+ $this->assertArrayHasKey('recorded_context', $instrument['previous_versions'][1]);
+ $this->assertArrayHasKey('proponent', $instrument['previous_versions'][1]['confirmations']);
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true);
+ $this->assertSame($instrument, $this->instrument());
+ }
+
+ public function test_completion_requires_finished_milestones_and_closure_replay_is_read_only(): void
+ {
+ $this->confirmBoth();
+ $data = ['title' => 'SYNTHETIC delivery', 'responsible_id' => $this->candidate->id, 'status' => 'pending'];
+ $this->postJson('/parcerias/salas/'.$this->roomId.'/marcos', $data)->assertOk();
+ $this->postJson($this->url(), $this->command('start'))->assertOk()->assertJsonPath('status', 'execution');
+ $complete = $this->command('complete');
+ $this->postJson($this->url(), $complete)->assertConflict();
+ $item = DB::table('partnership_milestones')->where('room_id', $this->roomId)->first();
+ $this->putJson('/parcerias/salas/'.$this->roomId.'/marcos/'.$item->id, [...$data, 'version' => $item->version, 'status' => 'completed', 'evidence' => 'SYNTHETIC evidence'])->assertOk();
+ $this->postJson($this->url(), $complete)->assertOk()->assertJsonPath('status', 'closed');
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $complete)->assertOk()->assertJsonPath('replayed', true);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame('completed', DB::table('partnership_milestones')->where('id', $item->id)->value('status'));
+ }
+
+ public function test_revocation_or_read_only_role_prevents_replay_and_private_command_receipts(): void
+ {
+ $context = app(PartnershipExchange::class)->room($this->owner, $this->roomId);
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC agreement organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ app(PartnershipExchange::class)->save($this->owner, ['version' => $context['partnership']->version, 'kind' => 'seeking', 'organization_id' => $org], $context['partnership']->id);
+ $data = $this->command();
+ $this->postJson($this->url(), $data)->assertOk();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->owner->id)->update(['role' => 'viewer']);
+ $this->postJson($this->url(), $data)->assertForbidden();
+ $this->getJson('/parcerias/salas/'.$this->roomId)->assertOk()->assertJsonPath('agreementCommands', [])->assertJsonPath('agreementParty', null)->assertJsonPath('canWrite', false);
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->owner->id)->update(['deleted_at' => now()]);
+ $this->postJson($this->url(), $data)->assertForbidden();
+ }
+
+ public function test_receipts_are_actor_specific_and_snapshots_do_not_expose_internal_hashes(): void
+ {
+ $data = $this->command('confirm');
+ $this->postJson($this->url(), $data)->assertOk();
+ $response = $this->getJson('/parcerias/salas/'.$this->roomId)->assertOk()->assertJsonPath('agreementActorId', $this->owner->id)->assertJsonPath('agreementParty', 'proponent')->assertJsonPath('agreementCommands.0.key', $data['client_key'])->assertJsonPath('agreementCommands.0.party', 'proponent');
+ foreach (['command_hash', '_creation_hash', '_notification_context'] as $key) {
+ $this->assertStringNotContainsString($key, $response->getContent());
+ }$this->actingAs($this->candidate)->getJson('/parcerias/salas/'.$this->roomId)->assertOk()->assertJsonPath('agreementCommands', [])->assertJsonPath('agreementParty', 'candidate');
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_agreement.changed.v1')->orderByDesc('aggregate_version')->first();
+ $metadata = json_decode($event->payload, true)['payload'];
+ $this->assertSame('SYNTHETIC terms', $metadata['previous']['agreement']['terms']);
+ $this->assertSame($this->owner->id, $metadata['applied']['agreement']['confirmations']['proponent']['actor_id']);
+ $this->assertSame('proponent', $metadata['confirmation_party']);
+ }
+
+ public function test_context_tokens_reject_stale_candidacy_and_legacy_calls_keep_the_room_protocol(): void
+ {
+ $data = $this->command('confirm');
+ $this->postJson($this->url(), [...$data, 'interest_version' => $data['interest_version'] + 1])->assertConflict();
+ $this->postJson($this->url(), [...$data, 'client_key' => 'invalid'])->assertUnprocessable();
+ unset($data['client_key'],$data['interest_version'],$data['partnership_version']);
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', false);
+ }
+
+ public function test_malformed_legacy_instrument_is_not_overwritten_or_a_server_error(): void
+ {
+ $instrument = $this->instrument();
+ $instrument['previous_versions'] = 'SYNTHETIC invalid legacy';
+ DB::table('partnership_rooms')->where('id', $this->roomId)->update(['agreement' => json_encode($instrument)]);
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), [...$this->command('record'), 'title' => 'SYNTHETIC new title', 'terms' => 'SYNTHETIC new terms'])->assertConflict();
+ $this->assertSame($instrument, $this->instrument());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $instrument['previous_versions'] = [];
+ $instrument['confirmations'] = 'SYNTHETIC invalid confirmations';
+ DB::table('partnership_rooms')->where('id', $this->roomId)->update(['agreement' => json_encode($instrument)]);
+ $this->postJson($this->url(), $this->command('confirm'))->assertConflict();
+ }
+
+ public function test_keys_are_room_scoped_and_moderation_does_not_grant_private_room_access(): void
+ {
+ $data = $this->command();
+ $this->postJson($this->url(), $data)->assertOk();
+ $service = app(PartnershipExchange::class);
+ $context = $service->room($this->owner, $this->roomId);
+ $other = User::factory()->create();
+ $interest = $service->interest($other, $context['partnership']->id, ['proposal' => 'SYNTHETIC other candidature', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connect');
+ $room = DB::table('partnership_rooms')->where('interest_id',$interest->id)->first();
+ $this->postJson('/parcerias/salas/'.$room->id.'/acordo',[...$data, 'version' => $room->version, 'interest_version' => $interest->version])->assertOk()->assertJsonPath('replayed',false);
+ config(['portal.managers' => [$other->email]]);
+ $this->actingAs($other)->postJson($this->url(),$data)->assertForbidden();
+ }
+}
diff --git a/tests/Feature/PartnershipCandidaciesTest.php b/tests/Feature/PartnershipCandidaciesTest.php
new file mode 100644
index 00000000..1577f02e
--- /dev/null
+++ b/tests/Feature/PartnershipCandidaciesTest.php
@@ -0,0 +1,250 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $this->record = $this->published($this->owner);
+ $this->actingAs($this->candidate);
+ }
+
+ private function published(User $owner): object
+ {
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC candidature context', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'seeking' => 'SYNTHETIC cooperation', 'payload' => ['consent' => true, 'mandatory' => ['capacity']]]);
+ $record = $service->transition($owner, $record->id, $record->version, 'submit', 'SYNTHETIC submission');
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+
+ return $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC independent review');
+ }
+
+ private function input(array $changes = []): array
+ {
+ return ['proposal' => 'SYNTHETIC original proposal', 'payload' => ['consent' => true, 'capacity' => 'SYNTHETIC original capacity', 'availability' => 'SYNTHETIC original availability', 'contribution' => 'SYNTHETIC original contribution', 'conflicts' => 'SYNTHETIC declared conflicts'], ...$changes];
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/'.$this->record->id.'/interesses';
+ }
+
+ private function interest(array $changes = [], ?User $actor = null): object
+ {
+ return app(PartnershipExchange::class)->interest($actor ?? $this->candidate, $this->record->id, $this->input($changes));
+ }
+
+ private function organization(User $user, string $role = 'officer'): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC candidacy organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $user->id, 'organization_id' => $id, 'role' => $role]);
+
+ return $id;
+ }
+
+ public function test_omitted_declarations_and_organization_survive_a_partial_resubmission(): void
+ {
+ $org = $this->organization($this->candidate);
+ $interest = $this->interest(['organization_id' => $org]);
+ $this->postJson($this->url(), ['interest_id' => $interest->id, 'version' => $interest->version, 'proposal' => 'SYNTHETIC changed proposal', 'payload' => ['consent' => true]])->assertOk();
+ $saved = DB::table('partnership_interests')->where('id', $interest->id)->first();
+ $this->assertSame($org, $saved->organization_id);
+ $payload = json_decode($saved->payload, true);
+ $this->assertSame('SYNTHETIC original capacity', $payload['capacity']);
+ $this->assertSame('SYNTHETIC original availability', $payload['availability']);
+ $this->assertSame('SYNTHETIC declared conflicts', $payload['conflicts']);
+ }
+
+ public function test_explicit_candidacy_identity_updates_the_selected_withdrawn_organization_record(): void
+ {
+ $personal = $this->interest();
+ $otherAuthor = User::factory()->create();
+ $org = $this->organization($otherAuthor);
+ DB::table('memberships')->insert(['user_id' => $this->candidate->id, 'organization_id' => $org, 'role' => 'officer']);
+ $organizational = $this->interest(['organization_id' => $org], $otherAuthor);
+ $organizational = app(PartnershipExchange::class)->decideInterest($otherAuthor, $organizational->id, $organizational->version, 'withdraw', 'SYNTHETIC withdrawal');
+ DB::table('partnership_interests')->where('id', $personal->id)->update(['version' => $organizational->version]);
+ $this->postJson($this->url(), $this->input(['interest_id' => $organizational->id, 'version' => $organizational->version, 'organization_id' => $org, 'proposal' => 'SYNTHETIC intended organization update']))->assertOk()->assertJsonPath('id', $organizational->id);
+ $this->assertDatabaseHas('partnership_interests', ['id' => $personal->id, 'organization_id' => null, 'proposal' => 'SYNTHETIC original proposal']);
+ $this->assertDatabaseHas('partnership_interests', ['id' => $organizational->id, 'status' => 'submitted', 'proposal' => 'SYNTHETIC intended organization update']);
+ }
+
+ public function test_read_only_representative_can_consult_but_has_no_candidacy_write_actions(): void
+ {
+ $org = $this->organization($this->candidate);
+ $interest = $this->interest(['organization_id' => $org]);
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $org, 'role' => 'viewer']);
+ $this->actingAs($viewer)->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('interests.0.can_edit', false);
+ $this->postJson($this->url(), $this->input(['interest_id' => $interest->id, 'version' => 1, 'organization_id' => $org]))->assertForbidden();
+ }
+
+ public function test_owning_actor_can_recover_a_committed_submission_without_resetting_assessment_or_version(): void
+ {
+ $input = $this->input(['client_key' => (string) Str::uuid()]);
+ $interest = app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, $input);
+ $assessed = app(PartnershipExchange::class)->decideInterest($this->owner, $interest->id, 1, 'assess', 'SYNTHETIC evidence reviewed', ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC evidence']]);
+ $before = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('id', $interest->id)->assertJsonPath('version', $assessed->version)->assertJsonPath('replayed', true);
+ $this->assertSame($before, DB::table('partnership_events')->count());
+ $this->assertSame('met', json_decode(DB::table('partnership_interests')->where('id', $interest->id)->value('assessment'), true)['capacity']['state']);
+ }
+
+ public function test_explicit_clearing_creates_a_new_submission_and_preserves_the_previous_evaluation_in_the_event(): void
+ {
+ $org = $this->organization($this->candidate);
+ $interest = $this->interest(['organization_id' => $org]);
+ $interest = app(PartnershipExchange::class)->decideInterest($this->owner, $interest->id, 1, 'assess', 'SYNTHETIC evidence reviewed', ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC prior evidence']]);
+ $input = $this->input(['client_key' => (string) Str::uuid(), 'interest_id' => $interest->id, 'version' => 2, 'organization_id' => null, 'payload' => ['consent' => true, 'capacity' => '', 'conflicts' => null]]);
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('version', 3);
+ $saved = DB::table('partnership_interests')->where('id', $interest->id)->first();
+ $this->assertNull($saved->organization_id);
+ $this->assertEmpty(json_decode($saved->assessment, true));
+ $this->assertNull(json_decode($saved->payload, true)['capacity']);
+ $this->assertNull(json_decode($saved->payload, true)['conflicts']);
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.submitted.v1')->orderByDesc('aggregate_version')->first();
+ $payload = json_decode($event->payload, true)['payload'];
+ $this->assertSame(2, $payload['previous']['version']);
+ $this->assertSame($org, $payload['previous']['organization_id']);
+ $this->assertSame('SYNTHETIC prior evidence', $payload['previous']['assessment']['capacity']['evidence']);
+ $this->assertSame('SYNTHETIC original capacity', $payload['previous']['payload']['capacity']);
+ $this->assertSame(3, $payload['submitted']['version']);
+ }
+
+ public function test_ambiguous_legacy_submission_and_a_foreign_candidacy_cannot_change_another_record(): void
+ {
+ $personal = $this->interest();
+ $other = User::factory()->create();
+ $org = $this->organization($other);
+ DB::table('memberships')->insert(['user_id' => $this->candidate->id, 'organization_id' => $org, 'role' => 'officer']);
+ $organizational = $this->interest(['organization_id' => $org], $other);
+ $this->postJson($this->url(), $this->input(['version' => 1, 'organization_id' => $org]))->assertConflict();
+ $different = $this->published(User::factory()->create());
+ $foreign = app(PartnershipExchange::class)->interest($this->candidate, $different->id, $this->input());
+ $this->postJson($this->url(), $this->input(['interest_id' => $foreign->id, 'version' => 1]))->assertNotFound();
+ $this->assertDatabaseHas('partnership_interests', ['id' => $personal->id, 'organization_id' => null, 'version' => 1]);
+ $this->assertDatabaseHas('partnership_interests', ['id' => $organizational->id, 'organization_id' => $org, 'version' => 1]);
+ }
+
+ public function test_replay_is_content_bound_case_normalized_and_never_grants_revoked_representation(): void
+ {
+ $org = $this->organization($this->candidate);
+ $input = $this->input(['organization_id' => $org, 'client_key' => (string) Str::uuid()]);
+ $interest = app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, $input);
+ $this->postJson($this->url(), [...$input, 'client_key' => strtoupper($input['client_key'])])->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($this->url(), [...$input, 'proposal' => 'SYNTHETIC different content'])->assertConflict();
+ DB::table('memberships')->where('organization_id', $org)->update(['deleted_at' => now()]);
+ $this->postJson($this->url(), $input)->assertForbidden();
+ $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('canStartInterest', false)->assertJsonCount(0, 'interests');
+ $this->assertDatabaseHas('partnership_interests', ['id' => $interest->id, 'version' => 1]);
+ }
+
+ public function test_submission_and_decision_reject_stale_partnership_context_without_writes(): void
+ {
+ $interest = $this->interest();
+ $before = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $this->input(['interest_id' => $interest->id, 'version' => 1, 'partnership_version' => $this->record->version - 1]))->assertConflict();
+ $this->actingAs($this->owner)->postJson('/parcerias/candidaturas/'.$interest->id, ['version' => 1, 'partnership_version' => $this->record->version - 1, 'action' => 'assess', 'reason' => 'SYNTHETIC stale context', 'assessment' => ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC stale evidence']]])->assertConflict();
+ $this->assertSame($before, DB::table('partnership_events')->count());
+ $this->assertDatabaseHas('partnership_interests', ['id' => $interest->id, 'version' => 1, 'assessment' => '{}']);
+ }
+
+ public function test_matching_weights_are_checked_and_legacy_decisions_keep_their_existing_path(): void
+ {
+ $interest = $this->interest();
+ $hash = app(PartnershipMatching::class)->explain($this->record, $interest)['weights_hash'];
+ config(['partnerships.weights.capacity' => 21]);
+ $this->actingAs($this->owner)->postJson('/parcerias/candidaturas/'.$interest->id, ['version' => 1, 'partnership_version' => $this->record->version, 'weights_hash' => $hash, 'action' => 'assess', 'reason' => 'SYNTHETIC old weights', 'assessment' => ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC evidence']]])->assertConflict();
+ $this->postJson('/parcerias/candidaturas/'.$interest->id, ['version' => 1, 'action' => 'assess', 'reason' => 'SYNTHETIC legacy client', 'assessment' => ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC evidence', 'irrelevant' => 'Must not persist']]])->assertOk();
+ $stored = json_decode(DB::table('partnership_interests')->where('id', $interest->id)->value('assessment'), true)['capacity'];
+ $this->assertArrayNotHasKey('irrelevant', $stored);
+ $this->assertSame($this->owner->id, $stored['assessed_by']);
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.changed.v1')->orderByDesc('aggregate_version')->first();
+ $payload = json_decode($event->payload, true)['payload'];
+ $this->assertSame($this->record->version, $payload['partnership_version']);
+ $this->assertNotSame($hash, $payload['matching_context']['weights_hash']);
+ $this->assertSame('transparent-rules.v1', $payload['matching_context']['algorithm_version']);
+ $capacity = array_values(array_filter($payload['matching_context']['criteria'], fn ($criterion) => $criterion['code'] === 'capacity'))[0];
+ $this->assertSame(21, $capacity['weight']);
+ $this->assertTrue($capacity['mandatory']);
+ }
+
+ public function test_replaying_a_decision_does_not_repeat_events_or_affect_another_candidacy(): void
+ {
+ $interest = $this->interest();
+ $other = $this->interest([], User::factory()->create());
+ $input = ['client_key' => (string) Str::uuid(), 'version' => 1, 'action' => 'shortlist', 'reason' => 'SYNTHETIC shortlist unknown evidence'];
+ $this->actingAs($this->owner)->postJson('/parcerias/candidaturas/'.$interest->id, $input)->assertOk();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson('/parcerias/candidaturas/'.$interest->id, $input)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('version', 2);
+ $this->postJson('/parcerias/candidaturas/'.$other->id, $input)->assertConflict();
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertDatabaseHas('partnership_interests', ['id' => $other->id, 'version' => 1, 'status' => 'submitted']);
+ $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('interests.0.commands.0.key', $input['client_key']);
+ $this->actingAs($this->candidate)->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonCount(0, 'interests.0.commands');
+ }
+
+ public function test_withdrawal_and_read_only_recovery_do_not_depend_on_a_current_publication_window(): void
+ {
+ $input = $this->input(['client_key' => (string) Str::uuid()]);
+ $interest = app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, $input);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['status' => 'archived', 'version' => $this->record->version + 1]);
+ $withdraw = ['client_key' => (string) Str::uuid(), 'version' => 1, 'partnership_version' => 1, 'weights_hash' => str_repeat('0', 64), 'action' => 'withdraw', 'reason' => 'SYNTHETIC withdrawal independent of publication'];
+ $this->postJson('/parcerias/candidaturas/'.$interest->id, $withdraw)->assertOk();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('version', 2);
+ $this->postJson('/parcerias/candidaturas/'.$interest->id, $withdraw)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($this->url(), $this->input(['interest_id' => $interest->id, 'version' => 2]))->assertConflict();
+ $this->assertDatabaseHas('partnership_interests', ['id' => $interest->id, 'status' => 'withdrawn', 'version' => 2]);
+ }
+
+ public function test_explicit_update_replay_preserves_later_decisions_and_requires_accepted_consent(): void
+ {
+ $interest = $this->interest();
+ $input = $this->input(['interest_id' => $interest->id, 'version' => 1, 'client_key' => (string) Str::uuid()]);
+ $this->postJson($this->url(), [...$input, 'payload' => ['consent' => false]])->assertUnprocessable();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('version', 2);
+ app(PartnershipExchange::class)->decideInterest($this->owner, $interest->id, 2, 'shortlist', 'SYNTHETIC shortlist after update');
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('version', 3)->assertJsonPath('replayed', true);
+ $this->assertDatabaseHas('partnership_interests', ['id' => $interest->id, 'status' => 'shortlisted', 'version' => 3]);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_organization_choices_keep_distinct_entities_with_equal_names(): void
+ {
+ $first = $this->organization($this->candidate);
+ $second = $this->organization($this->candidate);
+ $choices = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonCount(2, 'organizations')->json('organizations');
+ $this->assertEqualsCanonicalizing([$first, $second], array_column($choices, 'id'));
+ $this->assertSame($choices[0]['name'], $choices[1]['name']);
+ }
+}
diff --git a/tests/Feature/PartnershipCandidacyHistoryTest.php b/tests/Feature/PartnershipCandidacyHistoryTest.php
new file mode 100644
index 00000000..3639d8f8
--- /dev/null
+++ b/tests/Feature/PartnershipCandidacyHistoryTest.php
@@ -0,0 +1,204 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $this->moderator = User::factory()->create();
+ config(['portal.managers' => [$this->moderator->email]]);
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC private history context', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'seeking' => 'SYNTHETIC cooperation', 'payload' => ['consent' => true, 'mandatory' => ['capacity']]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submission');
+ $this->record = $service->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC review');
+ $this->interest = $service->interest($this->candidate, $record->id, ['client_key' => (string) Str::uuid(), 'proposal' => 'SYNTHETIC original proposal', 'payload' => ['consent' => true, 'capacity' => 'SYNTHETIC original capacity']]);
+ $this->actingAs($this->candidate);
+ }
+
+ private function url(?int $id = null): string
+ {
+ return '/parcerias/candidaturas/'.($id ?? $this->interest->id).'/historico';
+ }
+
+ private function assess(int $version, string $evidence = 'SYNTHETIC preserved evidence'): object
+ {
+ return app(PartnershipExchange::class)->decideInterest($this->owner, $this->interest->id, $version, 'assess', 'SYNTHETIC evidence reviewed', ['capacity' => ['state' => 'met', 'evidence' => $evidence]]);
+ }
+
+ private function organization(User $person, string $role = 'officer'): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC history organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $person->id, 'organization_id' => $id, 'role' => $role]);
+
+ return $id;
+ }
+
+ public function test_history_recovers_real_versions_and_frozen_matching_without_recalculation(): void
+ {
+ $this->assess(1);
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 2, 'proposal' => 'SYNTHETIC revised proposal', 'payload' => ['consent' => true, 'capacity' => 'SYNTHETIC revised capacity']]);
+ config(['partnerships.weights.capacity' => 99, 'partnerships.criteria.capacity' => 'SYNTHETIC renamed current label']);
+ $response = $this->getJson($this->url())->assertOk()->assertJsonCount(3, 'entries')->assertJsonPath('entries.0.version', 3)->assertJsonPath('entries.0.after.fields.proposal', 'SYNTHETIC revised proposal')->assertJsonPath('entries.0.previous.fields.capacity', 'SYNTHETIC original capacity')->assertJsonPath('entries.1.after.fields.proposal', 'SYNTHETIC original proposal')->assertJsonPath('entries.1.after.assessment.0.evidence', 'SYNTHETIC preserved evidence')->assertJsonPath('entries.2.previous.availability', 'not_recorded');
+ $criteria = collect($response->json('entries.1.matching.criteria'))->keyBy('code');
+ $this->assertSame(20, $criteria['capacity']['weight']);
+ $this->assertSame('Capacidade técnica/produtiva', $criteria['capacity']['label']);
+ $this->assertTrue($criteria['capacity']['mandatory']);
+ $this->assertStringNotContainsString('client_key', $response->getContent());
+ $this->assertStringNotContainsString('command_hash', $response->getContent());
+ }
+
+ public function test_anonymous_competitors_and_moderation_do_not_receive_another_candidacy_history(): void
+ {
+ $other = User::factory()->create();
+ $otherInterest = app(PartnershipExchange::class)->interest($other, $this->record->id, ['proposal' => 'SYNTHETIC other candidature', 'payload' => ['consent' => true]]);
+ $this->getJson($this->url($otherInterest->id))->assertForbidden();
+ $this->actingAs($this->moderator)->getJson($this->url())->assertForbidden();
+ $this->actingAs($other)->getJson($this->url())->assertForbidden();
+ $this->getJson($this->url($otherInterest->id))->assertOk()->assertJsonCount(1, 'entries');
+ $this->actingAs($this->owner)->getJson($this->url())->assertOk();
+ auth()->forgetGuards();
+ $this->app['auth']->forgetGuards();
+ $this->getJson($this->url())->assertUnauthorized();
+ }
+
+ public function test_read_only_organization_members_can_read_and_revoked_authors_cannot(): void
+ {
+ $org = $this->organization($this->candidate);
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $org, 'proposal' => 'SYNTHETIC organizational version', 'payload' => ['consent' => true]]);
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $org, 'role' => 'viewer']);
+ $this->actingAs($viewer)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.after.availability', 'available')->assertJsonPath('entries.0.previous.availability', 'restricted')->assertJsonPath('entries.1.restricted', true);
+ DB::table('memberships')->where('user_id', $this->candidate->id)->update(['deleted_at' => now()]);
+ $this->actingAs($this->candidate)->getJson($this->url())->assertForbidden();
+ $this->actingAs($viewer)->getJson($this->url())->assertOk();
+ }
+
+ public function test_new_organization_does_not_gain_old_organization_snapshots_or_assessment(): void
+ {
+ $orgA = $this->organization($this->candidate);
+ $orgB = $this->organization($this->candidate);
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $orgA, 'proposal' => 'SYNTHETIC A-only proposal', 'payload' => ['consent' => true]]);
+ $this->assess(2, 'SYNTHETIC A-only evidence');
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 3, 'organization_id' => $orgB, 'proposal' => 'SYNTHETIC B submission', 'payload' => ['consent' => true, 'capacity' => 'SYNTHETIC B capacity']]);
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $orgB, 'role' => 'viewer']);
+ $response = $this->actingAs($viewer)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.after.fields.proposal', 'SYNTHETIC B submission')->assertJsonPath('entries.0.previous.availability', 'restricted')->assertJsonPath('entries.1.restricted', true)->assertJsonPath('entries.1.actor_name', null)->assertJsonPath('entries.1.matching', null);
+ $this->assertStringNotContainsString('SYNTHETIC A-only', $response->getContent());
+ $this->actingAs($this->owner)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.previous.fields.proposal', 'SYNTHETIC A-only proposal');
+ DB::table('memberships')->where('organization_id', $orgA)->where('user_id', $this->candidate->id)->update(['deleted_at' => now()]);
+ $this->actingAs($this->candidate)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.previous.availability', 'restricted');
+ }
+
+ public function test_legacy_partial_events_explain_missing_snapshots_without_copying_current_declarations(): void
+ {
+ DB::table('partnership_interests')->where('id', $this->interest->id)->update(['proposal' => 'SYNTHETIC current-only declaration', 'version' => 2, 'status' => 'clarification']);
+ app(PartnershipExchange::class)->event($this->record, $this->owner, 'partnership_interest.changed.v1', ['interest_id' => $this->interest->id, 'interest_version' => 2, 'from' => 'submitted', 'to' => 'clarification', 'reason' => 'SYNTHETIC legacy reason', 'assessment' => ['capacity' => ['state' => 'met', 'evidence' => 'SYNTHETIC legacy evidence']]], 'SYNTHETIC legacy fixture');
+ $response = $this->actingAs($this->owner)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.action', null)->assertJsonPath('entries.0.previous.availability', 'not_recorded')->assertJsonPath('entries.0.after.complete', false)->assertJsonPath('entries.0.after.status', 'clarification')->assertJsonPath('entries.0.matching', null);
+ $this->assertArrayNotHasKey('proposal', $response->json('entries.0.after.fields'));
+ $this->assertStringNotContainsString('SYNTHETIC current-only', $response->getContent());
+ $this->actingAs($this->candidate)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.restricted', true)->assertJsonPath('entries.0.after.availability', 'scope_unknown');
+ }
+
+ public function test_pagination_is_stable_when_new_decisions_arrive_and_never_mixes_candidacies(): void
+ {
+ for ($version = 1; $version <= 21; $version++) {
+ $this->assess($version);
+ }
+ $other = app(PartnershipExchange::class)->interest(User::factory()->create(), $this->record->id, ['proposal' => 'SYNTHETIC unrelated timeline', 'payload' => ['consent' => true]]);
+ $first = $this->actingAs($this->owner)->getJson($this->url())->assertOk()->assertJsonCount(10, 'entries');
+ $versions = array_column($first->json('entries'), 'version');
+ $this->assertSame(range(22, 13), $versions);
+ $this->assess(22);
+ $second = $this->getJson($first->json('next_url'))->assertOk()->assertJsonCount(10, 'entries');
+ $third = $this->getJson($second->json('next_url'))->assertOk()->assertJsonCount(2, 'entries')->assertJsonPath('next_url', null);
+ $this->assertSame(range(22, 1), [...$versions, ...array_column($second->json('entries'), 'version'), ...array_column($third->json('entries'), 'version')]);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.version', 23);
+ $this->getJson($this->url($other->id))->assertOk()->assertJsonCount(1, 'entries');
+ }
+
+ public function test_cursors_are_bound_to_actor_and_candidacy_and_checked_after_current_access(): void
+ {
+ for ($version = 1; $version <= 10; $version++) {
+ $this->assess($version);
+ }
+ $cursor = $this->actingAs($this->owner)->getJson($this->url())->assertOk()->json('next_url');
+ $this->actingAs($this->candidate)->getJson($cursor)->assertUnprocessable();
+ $other = app(PartnershipExchange::class)->interest(User::factory()->create(), $this->record->id, ['proposal' => 'SYNTHETIC other', 'payload' => ['consent' => true]]);
+ $query = parse_url($cursor, PHP_URL_QUERY);
+ $this->actingAs($this->owner)->getJson($this->url($other->id).'?'.$query)->assertUnprocessable();
+ $this->getJson($this->url().'?before=invalid-token')->assertUnprocessable();
+ $this->getJson($cursor)->assertOk();
+ }
+
+ public function test_private_history_remains_readable_after_archiving_without_exposing_a_new_draft(): void
+ {
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['status' => 'archived', 'title' => 'SYNTHETIC undisclosed revised title', 'offer' => 'SYNTHETIC private new draft']);
+ $response = $this->getJson($this->url())->assertOk()->assertJsonPath('partnership_href', null)->assertJsonPath('dashboard_href', '/parcerias/painel');
+ $this->assertStringNotContainsString('SYNTHETIC undisclosed', $response->getContent());
+ $this->assertStringNotContainsString('SYNTHETIC private new draft', $response->getContent());
+ $this->getJson('/parcerias/'.$this->record->id)->assertNotFound();
+ $this->actingAs($this->owner)->getJson($this->url())->assertOk()->assertJsonPath('partnership_href', '/parcerias/'.$this->record->id);
+ }
+
+ public function test_consultation_is_read_only_private_and_uses_the_native_history_page(): void
+ {
+ $this->assess(1);
+ $row = DB::table('partnership_interests')->where('id', $this->interest->id)->first();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notifications = DB::table('partnership_notifications')->count();
+ $version = app(HandleInertiaRequests::class)->version(Request::create($this->url()));
+ $response = $this->get($this->url(), ['X-Inertia' => 'true', 'X-Inertia-Version' => $version ?? ''])->assertOk()->assertJsonPath('component', 'partnerships/interest-history')->assertJsonPath('encryptHistory', true);
+ $this->assertTrue($response->headers->hasCacheControlDirective('private'));
+ $this->assertTrue($response->headers->hasCacheControlDirective('no-store'));
+ $this->assertEquals($row, DB::table('partnership_interests')->where('id', $this->interest->id)->first());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notifications, DB::table('partnership_notifications')->count());
+ }
+
+ public function test_missing_or_malformed_matching_parameters_stay_unknown_and_never_become_zero(): void
+ {
+ $this->assess(1);
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.changed.v1')->first();
+ $data = json_decode($event->payload, true);
+ $data['payload']['matching_context']['score_min'] = ['invalid'];
+ $data['payload']['matching_context']['score_max'] = null;
+ $data['payload']['matching_context']['criteria'][0]['weight'] = ['invalid'];
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($data)]);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.matching.score_min', null)->assertJsonPath('entries.0.matching.score_max', null)->assertJsonPath('entries.0.matching.criteria.0.weight', null);
+ }
+}
diff --git a/tests/Feature/PartnershipDashboardPrivacyTest.php b/tests/Feature/PartnershipDashboardPrivacyTest.php
new file mode 100644
index 00000000..5da714d5
--- /dev/null
+++ b/tests/Feature/PartnershipDashboardPrivacyTest.php
@@ -0,0 +1,324 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $this->moderator = User::factory()->create();
+ config(['portal.managers' => [$this->moderator->email]]);
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC published title', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submit');
+ $this->record = $service->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $this->interest = $service->interest($this->candidate, $record->id, ['client_key' => (string) Str::uuid(), 'proposal' => 'SYNTHETIC candidate', 'payload' => ['consent' => true]]);
+ $this->actingAs($this->candidate);
+ }
+
+ private function panel(): TestResponse
+ {
+ $version = app(HandleInertiaRequests::class)->version(Request::create('/parcerias/painel'));
+
+ return $this->get('/parcerias/painel', ['X-Inertia' => 'true', 'X-Inertia-Version' => $version ?? '']);
+ }
+
+ private function organization(User $person, string $role = 'officer'): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC dashboard organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $person->id, 'organization_id' => $id, 'role' => $role]);
+
+ return $id;
+ }
+
+ public function test_dashboard_does_not_disclose_current_title_after_unpublication(): void
+ {
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['status' => 'draft', 'title' => 'SYNTHETIC undisclosed private replacement']);
+ $response = $this->panel()->assertOk()->assertJsonPath('props.interests.0.title', null)->assertJsonPath('props.interests.0.partnership_href', null);
+ $this->assertStringNotContainsString('SYNTHETIC undisclosed private replacement', $response->getContent());
+ }
+
+ public function test_deleted_organization_does_not_leave_its_drafts_in_the_panel(): void
+ {
+ $org = $this->organization($this->candidate);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org, 'status' => 'draft', 'title' => 'SYNTHETIC deleted organization draft']);
+ DB::table('partnership_interests')->where('id', $this->interest->id)->update(['organization_id' => $org]);
+ DB::table('organizations')->where('id', $org)->update(['deleted_at' => now()]);
+ $response = $this->panel()->assertOk()->assertJsonCount(0, 'props.mine')->assertJsonCount(0, 'props.interests');
+ $this->assertStringNotContainsString('SYNTHETIC deleted organization draft', $response->getContent());
+ }
+
+ public function test_revoked_candidate_does_not_read_or_acknowledge_old_notification(): void
+ {
+ $org = $this->organization($this->candidate);
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $org, 'proposal' => 'SYNTHETIC organizational candidate', 'payload' => ['consent' => true]]);
+ app(PartnershipExchange::class)->decideInterest($this->owner, $this->interest->id, 2, 'clarify', 'SYNTHETIC clarification');
+ $notice = DB::table('partnership_notifications')->where('user_id', $this->candidate->id)->orderByDesc('id')->first();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->candidate->id)->update(['deleted_at' => now()]);
+ $response = $this->panel()->assertOk();
+ $ids = array_column($response->json('props.notifications'), 'id');
+ $this->assertNotContains($notice->id, $ids);
+ $this->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertNotFound();
+ $this->assertNull(DB::table('partnership_notifications')->where('id', $notice->id)->value('read_at'));
+ }
+
+ public function test_current_parent_reader_or_moderator_keeps_the_authorized_proposal_link(): void
+ {
+ $this->panel()->assertOk()->assertJsonPath('props.interests.0.title', 'SYNTHETIC published title')->assertJsonPath('props.interests.0.partnership_href', '/parcerias/'.$this->record->id);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['status' => 'draft']);
+ $org = $this->organization($this->owner);
+ DB::table('memberships')->insert(['user_id' => $this->candidate->id, 'organization_id' => $org, 'role' => 'viewer']);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ $this->panel()->assertOk()->assertJsonPath('props.mine.0.title', 'SYNTHETIC published title')->assertJsonPath('props.interests.0.partnership_href', '/parcerias/'.$this->record->id);
+ config(['portal.managers' => [$this->candidate->email]]);
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->candidate->id)->update(['deleted_at' => now()]);
+ $this->panel()->assertOk()->assertJsonCount(0, 'props.mine')->assertJsonPath('props.interests.0.partnership_href', '/parcerias/'.$this->record->id);
+ }
+
+ public function test_new_notices_follow_current_operational_participants_without_notifying_revoked_authors(): void
+ {
+ $proponentOrg = $this->organization($this->owner);
+ $candidateOrg = $this->organization($this->candidate);
+ $proponent = User::factory()->create();
+ $candidate = User::factory()->create();
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert([['user_id' => $proponent->id, 'organization_id' => $proponentOrg, 'role' => 'manager'], ['user_id' => $candidate->id, 'organization_id' => $candidateOrg, 'role' => 'officer'], ['user_id' => $viewer->id, 'organization_id' => $candidateOrg, 'role' => 'viewer']]);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $proponentOrg]);
+ app(PartnershipExchange::class)->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $candidateOrg, 'proposal' => 'SYNTHETIC organizational candidate', 'payload' => ['consent' => true]]);
+ DB::table('memberships')->whereIn('user_id', [$this->owner->id, $this->candidate->id])->update(['deleted_at' => now()]);
+ app(PartnershipExchange::class)->decideInterest($proponent, $this->interest->id, 2, 'clarify', 'SYNTHETIC current representatives');
+ $event = DB::table('partnership_events')->where('partnership_id', $this->record->id)->orderByDesc('aggregate_version')->first();
+ $recipients = DB::table('partnership_notifications')->where('event_id', $event->id)->pluck('user_id')->all();
+ sort($recipients);
+ $expected = [$proponent->id, $candidate->id];
+ sort($expected);
+ $this->assertSame($expected, $recipients);
+ $payload = json_decode($event->payload, true)['payload']['_notification_context'];
+ $this->assertSame($proponentOrg, $payload['partnership']['organization_id']);
+ $this->assertSame($candidateOrg, $payload['interest']['organization_id']);
+ $this->actingAs($candidate);
+ $this->panel()->assertOk()->assertJsonPath('props.notifications.0.href', '/parcerias/candidaturas/'.$this->interest->id.'/historico');
+ $this->actingAs($viewer);
+ $this->panel()->assertOk()->assertJsonCount(0, 'props.notifications');
+ }
+
+ public function test_change_to_another_organization_does_not_transfer_old_notices_to_the_new_representation(): void
+ {
+ $orgA = $this->organization($this->candidate);
+ $representative = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $representative->id, 'organization_id' => $orgA, 'role' => 'officer']);
+ $service = app(PartnershipExchange::class);
+ $service->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $orgA, 'proposal' => 'SYNTHETIC organization A', 'payload' => ['consent' => true]]);
+ $service->decideInterest($this->owner, $this->interest->id, 2, 'clarify', 'SYNTHETIC A clarification');
+ $old = DB::table('partnership_notifications')->where('user_id', $representative->id)->orderByDesc('id')->first();
+ $orgB = $this->organization($this->candidate);
+ DB::table('memberships')->insert(['user_id' => $representative->id, 'organization_id' => $orgB, 'role' => 'officer']);
+ $service->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 3, 'organization_id' => $orgB, 'proposal' => 'SYNTHETIC organization B', 'payload' => ['consent' => true]]);
+ DB::table('memberships')->where('organization_id', $orgA)->where('user_id', $representative->id)->update(['deleted_at' => now()]);
+ $this->actingAs($representative);
+ $response = $this->panel()->assertOk()->assertJsonCount(1, 'props.notifications');
+ $this->assertNotContains($old->id, array_column($response->json('props.notifications'), 'id'));
+ $this->post('/parcerias/notificacoes/'.$old->id.'/ler')->assertNotFound();
+ }
+
+ public function test_historical_scope_is_required_even_when_current_proponent_organization_is_authorized(): void
+ {
+ $orgA = $this->organization($this->owner);
+ $representative = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $representative->id, 'organization_id' => $orgA, 'role' => 'officer']);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $orgA]);
+ $service = app(PartnershipExchange::class);
+ $service->event($service->find($this->record->id), $this->owner, 'partnership_opportunity.changed.v1', [], 'SYNTHETIC A private notice', [$this->owner->id]);
+ $old = DB::table('partnership_notifications')->where('user_id', $representative->id)->orderByDesc('id')->first();
+ $orgB = $this->organization($representative);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $orgB]);
+ DB::table('memberships')->where('organization_id', $orgA)->where('user_id', $representative->id)->update(['deleted_at' => now()]);
+ $this->actingAs($representative);
+ $this->panel()->assertOk()->assertJsonCount(0, 'props.notifications');
+ $this->post('/parcerias/notificacoes/'.$old->id.'/ler')->assertNotFound();
+ }
+
+ public function test_legacy_candidate_snapshot_is_reused_without_inventing_missing_proponent_scope(): void
+ {
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.submitted.v1')->first();
+ $payload = json_decode($event->payload, true);
+ unset($payload['payload']['_notification_context']);
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $this->panel()->assertOk()->assertJsonCount(1, 'props.notifications')->assertJsonPath('props.notifications.0.href', '/parcerias/candidaturas/'.$this->interest->id.'/historico');
+ $this->actingAs($this->owner);
+ $response = $this->panel()->assertOk();
+ $candidateNotice = DB::table('partnership_notifications')->where('event_id', $event->id)->where('user_id', $this->owner->id)->first();
+ $this->assertNotContains($candidateNotice->id, array_column($response->json('props.notifications'), 'id'));
+ unset($payload['payload']['submitted']['organization_id']);
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $this->actingAs($this->candidate);
+ $this->panel()->assertOk()->assertJsonCount(0, 'props.notifications');
+ $this->assertSame(2, DB::table('partnership_notifications')->where('event_id', $event->id)->count());
+ }
+
+ public function test_inaccessible_rows_do_not_consume_the_visible_limit_or_hide_an_older_authorized_notice(): void
+ {
+ $record = app(PartnershipExchange::class)->find($this->record->id);
+ $sequence = DB::table('partnership_events')->where('partnership_id', $record->id)->max('aggregate_version');
+ $events = [];
+ $notices = [];
+ for ($i = 1; $i <= 105; $i++) {
+ $event = (string) Str::uuid();
+ $events[] = ['id' => $event, 'partnership_id' => $record->id, 'actor_id' => $this->owner->id, 'event_type' => 'partnership_opportunity.changed.v1', 'aggregate_version' => $sequence + $i, 'payload' => json_encode(['payload' => ['_notification_context' => ['version' => 1, 'partnership' => ['id' => $record->id, 'user_id' => $this->owner->id, 'organization_id' => null], 'interest' => null, 'room_id' => null]]])];
+ $notices[] = ['event_id' => $event, 'user_id' => $this->candidate->id, 'title' => 'SYNTHETIC inaccessible title', 'href' => 'javascript:synthetic()'];
+ }
+ DB::table('partnership_events')->insert($events);
+ DB::table('partnership_notifications')->insert($notices);
+ $response = $this->panel()->assertOk()->assertJsonCount(1, 'props.notifications');
+ $this->assertStringNotContainsString('SYNTHETIC inaccessible title', $response->getContent());
+ $this->assertStringNotContainsString('javascript:', $response->getContent());
+ }
+
+ public function test_notification_link_is_rebuilt_and_marking_read_is_idempotent_without_business_events(): void
+ {
+ $notice = DB::table('partnership_notifications')->where('user_id', $this->candidate->id)->first();
+ DB::table('partnership_notifications')->where('id', $notice->id)->update(['href' => 'javascript:synthetic()']);
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $this->panel()->assertOk()->assertJsonPath('props.notifications.0.href', '/parcerias/candidaturas/'.$this->interest->id.'/historico');
+ $this->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertRedirect();
+ $first = DB::table('partnership_notifications')->where('id', $notice->id)->value('read_at');
+ $this->assertNotNull($first);
+ $this->travel(5)->minutes();
+ $this->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertRedirect();
+ $this->assertSame($first, DB::table('partnership_notifications')->where('id', $notice->id)->value('read_at'));
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->actingAs($this->owner)->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertNotFound();
+ auth()->forgetGuards();
+ $this->postJson('/parcerias/notificacoes/'.$notice->id.'/ler')->assertUnauthorized();
+ }
+
+ public function test_room_notices_link_to_the_current_authorized_room_and_message_replay_does_not_duplicate_delivery(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $service->decideInterest($this->owner, $this->interest->id, 1, 'shortlist', 'SYNTHETIC shortlist');
+ $service->decideInterest($this->owner, $this->interest->id, 2, 'connect', 'SYNTHETIC connect');
+ $room = DB::table('partnership_rooms')->where('interest_id', $this->interest->id)->first();
+ $data = ['client_key' => (string) Str::uuid(), 'body' => 'SYNTHETIC message'];
+ $this->postJson('/parcerias/salas/'.$room->id.'/mensagens', $data)->assertOk();
+ $count = DB::table('partnership_notifications')->count();
+ $this->postJson('/parcerias/salas/'.$room->id.'/mensagens', $data)->assertOk();
+ $this->assertSame($count, DB::table('partnership_notifications')->count());
+ $this->panel()->assertOk()->assertJsonPath('props.notifications.0.href', '/parcerias/salas/'.$room->id);
+ }
+
+ public function test_malformed_explicit_context_does_not_fall_back_to_a_legacy_snapshot(): void
+ {
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.submitted.v1')->first();
+ $payload = json_decode($event->payload, true);
+ $notice = DB::table('partnership_notifications')->where('event_id', $event->id)->where('user_id', $this->candidate->id)->first();
+ foreach ([null, ['version' => 99], ['version' => 1, 'partnership' => ['id' => $this->record->id + 999, 'user_id' => $this->owner->id, 'organization_id' => null]]] as $invalid) {
+ $payload['payload']['_notification_context'] = $invalid;
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $this->panel()->assertOk()->assertJsonCount(0, 'props.notifications');
+ $this->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertNotFound();
+ }
+ }
+
+ public function test_a_read_only_representative_keeps_reading_an_existing_notice_without_receiving_new_operational_delivery(): void
+ {
+ $org = $this->organization($this->candidate);
+ $service = app(PartnershipExchange::class);
+ $service->interest($this->candidate, $this->record->id, ['interest_id' => $this->interest->id, 'version' => 1, 'organization_id' => $org, 'proposal' => 'SYNTHETIC organization', 'payload' => ['consent' => true]]);
+ $notice = DB::table('partnership_notifications')->where('user_id', $this->candidate->id)->orderByDesc('id')->first();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->candidate->id)->update(['role' => 'viewer']);
+ $this->panel()->assertOk()->assertJsonPath('props.notifications.0.id', $notice->id);
+ $this->post('/parcerias/notificacoes/'.$notice->id.'/ler')->assertRedirect();
+ $service->decideInterest($this->owner, $this->interest->id, 2, 'clarify', 'SYNTHETIC later decision');
+ $this->assertSame(2, DB::table('partnership_notifications')->where('user_id', $this->candidate->id)->count());
+ $this->postJson('/parcerias/candidaturas/'.$this->interest->id, ['version' => 3, 'action' => 'withdraw', 'reason' => 'SYNTHETIC unauthorized write'])->assertForbidden();
+ }
+
+ public function test_visible_limit_keeps_the_latest_fifty_authorized_notifications_in_order(): void
+ {
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_interest.submitted.v1')->first();
+ $payload = $event->payload;
+ $sequence = DB::table('partnership_events')->where('partnership_id', $this->record->id)->max('aggregate_version');
+ $events = [];
+ $notices = [];
+ for ($i = 1; $i <= 55; $i++) {
+ $id = (string) Str::uuid();
+ $events[] = ['id' => $id, 'partnership_id' => $this->record->id, 'actor_id' => $this->candidate->id, 'event_type' => 'partnership_interest.submitted.v1', 'aggregate_version' => $sequence + $i, 'payload' => $payload];
+ $notices[] = ['event_id' => $id, 'user_id' => $this->candidate->id, 'title' => 'SYNTHETIC notice '.$i, 'href' => '/unused'];
+ }
+ DB::table('partnership_events')->insert($events);
+ DB::table('partnership_notifications')->insert($notices);
+ $response = $this->panel()->assertOk()->assertJsonCount(50, 'props.notifications')->assertJsonPath('props.notifications.0.title', 'SYNTHETIC notice 55')->assertJsonPath('props.notifications.49.title', 'SYNTHETIC notice 6');
+ $ids = array_column($response->json('props.notifications'), 'id');
+ $sorted = $ids;
+ rsort($sorted);
+ $this->assertSame($sorted, $ids);
+ $this->assertCount(50, array_unique($ids));
+ }
+
+ public function test_an_inconsistent_event_context_rolls_back_without_cross_partnership_delivery(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $other = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC other partnership', 'kind' => 'seeking']);
+ $events = DB::table('partnership_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $audits = DB::table('audit_events')->count();
+ try {
+ $service->event($other, $this->owner, 'partnership_interest.changed.v1', ['interest_id' => $this->interest->id], 'SYNTHETIC inconsistent context', [$this->candidate->id]);
+ $this->fail('A foreign candidacy must not produce a notification.');
+ } catch (\LogicException $error) {
+ $this->assertSame('Notification belongs to another partnership.', $error->getMessage());
+ }
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ }
+
+ public function test_events_without_a_notification_intent_remain_without_delivery_and_shared_parties_are_deduplicated(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $before = DB::table('partnership_notifications')->count();
+ $service->event($service->find($this->record->id), $this->owner, 'partnership.document_accessed.v1', [], 'SYNTHETIC read only');
+ $this->assertSame($before, DB::table('partnership_notifications')->count());
+ $org = $this->organization($this->owner);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ DB::table('partnership_interests')->where('id', $this->interest->id)->update(['organization_id' => $org]);
+ $service->event($service->find($this->record->id), $this->owner, 'partnership_interest.changed.v1', ['interest_id' => $this->interest->id], 'SYNTHETIC same party', [$this->owner->id, $this->candidate->id]);
+ $event = DB::table('partnership_events')->where('partnership_id', $this->record->id)->orderByDesc('aggregate_version')->first();
+ $this->assertSame([$this->owner->id], DB::table('partnership_notifications')->where('event_id',$event->id)->pluck('user_id')->all());
+ }
+}
diff --git a/tests/Feature/PartnershipDraftRecoveryTest.php b/tests/Feature/PartnershipDraftRecoveryTest.php
new file mode 100644
index 00000000..b7ff719e
--- /dev/null
+++ b/tests/Feature/PartnershipDraftRecoveryTest.php
@@ -0,0 +1,184 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->actingAs($this->owner);
+ $this->record = app(PartnershipExchange::class)->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC original draft', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true, 'mandatory' => ['capacity']]]);
+ }
+
+ private function command(array $changes = []): array
+ {
+ return ['operation_key' => (string) Str::uuid(), 'version' => $this->record->version, 'kind' => 'seeking', 'title' => 'SYNTHETIC saved revision', 'partnership_type' => 'joint_venture', 'payload' => ['mandatory' => ['capacity']], ...$changes];
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/'.$this->record->id;
+ }
+
+ public function test_repeating_a_committed_edit_preserves_a_later_state_and_does_not_create_another_revision(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $current = app(PartnershipExchange::class)->find($this->record->id);
+ app(PartnershipExchange::class)->transition($this->owner, $current->id, $current->version, 'submit', 'SYNTHETIC submit after edit');
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->putJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('saved_version', $data['version'] + 1)->assertJsonPath('status', 'submitted');
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+
+ public function test_replay_does_not_revalidate_retired_type_or_criteria_as_a_new_write(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ config(['partnerships.types' => [], 'partnerships.criteria' => []]);
+ $this->putJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true);
+ }
+
+ public function test_changed_payload_with_the_same_operation_key_is_a_conflict_without_new_events(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $events = DB::table('partnership_events')->count();
+ $this->putJson($this->url(), [...$data, 'title' => 'SYNTHETIC changed content'])->assertConflict();
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame('SYNTHETIC saved revision', DB::table('portal_partnerships')->where('id', $this->record->id)->value('title'));
+ }
+
+ public function test_updates_use_distinct_operation_keys_without_changing_the_creation_identity(): void
+ {
+ $first = $this->command(['client_key' => (string) Str::uuid()]);
+ $this->putJson($this->url(), $first)->assertOk()->assertJsonPath('replayed', false);
+ $second = $this->command(['version' => $first['version'] + 1, 'title' => 'SYNTHETIC second revision', 'client_key' => $first['client_key']]);
+ $this->putJson($this->url(), $second)->assertOk()->assertJsonPath('saved_version', $second['version'] + 1);
+ $this->assertNotSame($first['operation_key'], $second['operation_key']);
+ $this->assertSame($this->record->client_key, DB::table('portal_partnerships')->where('id', $this->record->id)->value('client_key'));
+ }
+
+ public function test_authority_is_required_for_recovery_even_for_a_revoked_original_author(): void
+ {
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC editing organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ DB::table('memberships')->where('user_id', $this->owner->id)->where('organization_id', $org)->update(['role' => 'viewer']);
+ $this->putJson($this->url(), $data)->assertForbidden();
+ $this->get($this->url().'/editar')->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->owner->id)->where('organization_id', $org)->update(['deleted_at' => now()]);
+ $this->putJson($this->url(), $data)->assertForbidden();
+ }
+
+ public function test_editor_exposes_only_the_current_actors_save_keys_and_not_private_hashes(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $url = $this->url().'/editar';
+ $version = app(HandleInertiaRequests::class)->version(Request::create($url));
+ $response = $this->get($url, ['X-Inertia' => 'true', 'X-Inertia-Version' => $version ?? ''])->assertOk()->assertJsonPath('props.editorActorId', $this->owner->id)->assertJsonPath('props.saveCommands.0.key', $data['operation_key'])->assertJsonPath('props.saveCommands.0.version', $data['version'] + 1);
+ foreach (['operation_hash', 'command_hash', '_creation_hash', '_notification_context'] as $private) {
+ $this->assertStringNotContainsString($private, $response->getContent());
+ }
+ $org = (string) Str::uuid();
+ $other = User::factory()->create();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC shared draft', 'organization_type' => 'private']);
+ DB::table('memberships')->insert([['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer'], ['user_id' => $other->id, 'organization_id' => $org, 'role' => 'officer']]);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ $this->actingAs($other)->get($url, ['X-Inertia' => 'true', 'X-Inertia-Version' => $version ?? ''])->assertOk()->assertJsonPath('props.saveCommands', [])->assertJsonPath('props.editorActorId', $other->id);
+ }
+
+ public function test_retired_sector_blocks_a_new_edit_but_not_a_read_only_replay(): void
+ {
+ $sector = Sector::create(['name' => 'SYNTHETIC edit sector', 'slug' => 'synthetic-'.Str::uuid(), 'is_active' => true]);
+ $data = $this->command(['sector_id' => $sector->id]);
+ $this->putJson($this->url(), $data)->assertOk();
+ $sector->update(['is_active' => false]);
+ $this->putJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true);
+ $this->putJson($this->url(), [...$data, 'operation_key' => (string) Str::uuid(), 'version' => $data['version'] + 1])->assertUnprocessable();
+ }
+
+ public function test_invalid_or_stale_uncommitted_attempts_do_not_consume_a_key(): void
+ {
+ $data = $this->command();
+ $events = DB::table('partnership_events')->count();
+ $this->putJson($this->url(), [...$data, 'operation_key' => 'invalid'])->assertUnprocessable();
+ $this->putJson($this->url(), [...$data, 'version' => $data['version'] + 9])->assertConflict();
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->putJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', false);
+ }
+
+ public function test_operation_uuid_case_and_unused_creation_key_do_not_change_the_committed_edit(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $this->putJson($this->url(), [...$data, 'operation_key' => strtoupper($data['operation_key']), 'client_key' => (string) Str::uuid()])->assertOk()->assertJsonPath('replayed', true);
+ }
+
+ public function test_omitted_organization_and_payload_are_preserved_and_explicit_removal_is_a_new_command(): void
+ {
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC source organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $saved = app(PartnershipExchange::class)->find($this->record->id);
+ $this->assertSame($org, $saved->organization_id);
+ $this->assertTrue(json_decode($saved->payload, true)['consent']);
+ $this->putJson($this->url(), [...$data, 'organization_id' => null])->assertConflict();
+ $this->putJson($this->url(), [...$data, 'operation_key' => (string) Str::uuid(), 'version' => $saved->version, 'organization_id' => null])->assertOk();
+ $this->assertNull(app(PartnershipExchange::class)->find($saved->id)->organization_id);
+ }
+
+ public function test_legacy_edits_without_operation_keys_keep_version_conflicts_instead_of_a_false_replay(): void
+ {
+ $data = $this->command();
+ unset($data['operation_key']);
+ $this->putJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', false)->assertJsonPath('saved_version', null);
+ $this->putJson($this->url(), $data)->assertConflict();
+ }
+
+ public function test_operation_keys_are_scoped_to_the_actor_and_partnership(): void
+ {
+ $data = $this->command();
+ $this->putJson($this->url(), $data)->assertOk();
+ $other = User::factory()->create();
+ $record = app(PartnershipExchange::class)->save($other, ['client_key' => (string) Str::uuid(), 'kind' => 'seeking']);
+ $this->actingAs($other)->putJson('/parcerias/'.$record->id,[...$data, 'version' => $record->version])->assertOk()->assertJsonPath('replayed',false);
+ $this->putJson($this->url(),$data)->assertForbidden();
+ }
+}
diff --git a/tests/Feature/PartnershipEditingTest.php b/tests/Feature/PartnershipEditingTest.php
new file mode 100644
index 00000000..28bd4ac7
--- /dev/null
+++ b/tests/Feature/PartnershipEditingTest.php
@@ -0,0 +1,211 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->owner = User::factory()->create();
+ $this->actingAs($this->owner);
+ }
+
+ private function input(array $changes = []): array
+ {
+ return ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC partnership draft', 'kind' => 'seeking', 'partnership_type' => 'joint_venture',
+ 'offer' => 'SYNTHETIC existing resources', 'seeking' => 'SYNTHETIC collaboration', 'payload' => ['summary' => 'SYNTHETIC summary', 'requirements' => 'SYNTHETIC requirements', 'mandatory' => ['capacity'], 'consent' => true, 'confidentiality' => 'private', 'availability' => 'SYNTHETIC resources available from November'], 'origins' => [], 'locations' => [], ...$changes];
+ }
+
+ private function payload(int $id): array
+ {
+ return json_decode(DB::table('portal_partnerships')->where('id', $id)->value('payload'), true, 512, JSON_THROW_ON_ERROR);
+ }
+
+ private function organization(string $name): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC '.$name, 'source_system' => 'unit-synthetic', 'organization_type' => 'private']);
+
+ return $id;
+ }
+
+ private function links(): array
+ {
+ $place = (string) Str::uuid();
+ // Positive QA fixture for the existing workbook predicate, not an imported official place or geometry.
+ DB::table('geo_locations')->insert(['id' => $place, 'code' => $place, 'name' => 'SYNTHETIC coverage reference', 'location_type' => 'country', 'data_classification' => 'public', 'source_system' => 'cartografia-workbook', 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:synthetic-'.substr($place, 0, 8)]);
+ $project = Project::factory()->create();
+ InvestmentDossier::create(['project_id' => $project->id, 'title' => 'SYNTHETIC source dossier', 'source' => 'Synthetic fixture, no actual disclosure', 'content' => [], 'publication_status' => 'published', 'published_at' => now()->subMinute(), 'data_classification' => 'public', 'approval_basis' => 'document_owner', 'approval_evidence' => 'Synthetic QA fixture only']);
+
+ return ['origins' => [['type' => 'project', 'target_id' => $project->id]], 'locations' => [['geo_location_id' => $place, 'role' => 'coverage', 'source_reference' => 'SYNTHETIC declared coverage']]];
+ }
+
+ public function test_partial_edits_preserve_organization_and_scalar_fields_without_transferring_ownership(): void
+ {
+ $organization = $this->organization('retained organization');
+ $officer = User::factory()->create();
+ foreach ([$this->owner->id, $officer->id] as $actor) {
+ DB::table('memberships')->insert(['user_id' => $actor, 'organization_id' => $organization, 'role' => 'officer']);
+ }
+ $sector = Sector::create(['name' => 'SYNTHETIC retained sector', 'slug' => 'synthetic-'.Str::uuid(), 'is_active' => true]);
+ $input = $this->input(['organization_id' => $organization, 'sector_id' => $sector->id, 'deadline' => now()->addMonth()->toDateString(), ...$this->links()]);
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $origins = DB::table('partnership_origins')->where('partnership_id', $record->id)->get()->toArray();
+ $locations = DB::table('partnership_locations')->where('partnership_id', $record->id)->get()->toArray();
+ $this->actingAs($officer)->putJson('/parcerias/'.$record->id, ['version' => $record->version, 'kind' => 'seeking', 'payload' => ['summary' => 'SYNTHETIC summary only']])->assertOk();
+ $saved = DB::table('portal_partnerships')->where('id', $record->id)->first();
+ foreach (['title', 'offer', 'seeking', 'organization_id', 'sector_id', 'partnership_type', 'deadline'] as $field) {
+ $this->assertSame($input[$field], $saved->{$field});
+ }
+ $this->assertSame($record->user_id, $saved->user_id);
+ $this->assertEquals($origins, DB::table('partnership_origins')->where('partnership_id', $record->id)->get()->toArray());
+ $this->assertEquals($locations, DB::table('partnership_locations')->where('partnership_id', $record->id)->get()->toArray());
+ $this->get('/parcerias/'.$record->id.'/editar')->assertOk();
+ }
+
+ public function test_explicit_empty_scalar_and_relation_values_still_remove_the_selected_information(): void
+ {
+ $organization = $this->organization('explicitly removed link');
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $organization, 'role' => 'officer']);
+ $record = app(PartnershipExchange::class)->save($this->owner, $this->input(['organization_id' => $organization, ...$this->links()]));
+ $this->putJson('/parcerias/'.$record->id, ['version' => $record->version, 'kind' => 'seeking', 'title' => null, 'offer' => null, 'seeking' => null, 'organization_id' => null, 'sector_id' => null, 'partnership_type' => null, 'deadline' => null, 'origins' => [], 'locations' => []])->assertOk();
+ $saved = DB::table('portal_partnerships')->where('id', $record->id)->first();
+ $this->assertSame('', $saved->title);
+ $this->assertSame('', $saved->offer);
+ $this->assertSame('', $saved->seeking);
+ $this->assertNull($saved->organization_id);
+ $this->assertNull($saved->sector_id);
+ $this->assertNull($saved->deadline);
+ $this->assertNull($saved->partnership_type);
+ $this->assertSame(0, DB::table('partnership_origins')->where('partnership_id', $record->id)->count());
+ $this->assertSame(0, DB::table('partnership_locations')->where('partnership_id', $record->id)->count());
+ $this->assertSame('SYNTHETIC resources available from November', $this->payload($record->id)['availability']);
+ $this->get('/parcerias/'.$record->id.'/editar')->assertOk();
+ }
+
+ public function test_omitted_availability_is_preserved_when_an_older_editor_saves_other_fields(): void
+ {
+ $input = $this->input();
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ unset($input['payload']['availability']);
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version, 'title' => 'SYNTHETIC changed title'])->assertOk();
+ $this->assertSame('SYNTHETIC resources available from November', $this->payload($record->id)['availability'] ?? null);
+ }
+
+ public function test_explicit_clearing_is_preserved_and_previous_event_is_not_rewritten(): void
+ {
+ $input = $this->input();
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $before = DB::table('partnership_events')->where('partnership_id', $record->id)->orderBy('aggregate_version')->first();
+ $input['payload']['availability'] = null;
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version])->assertOk();
+ $this->assertNull($this->payload($record->id)['availability']);
+ $this->assertSame((array) $before, (array) DB::table('partnership_events')->where('id', $before->id)->first());
+ }
+
+ public function test_omitted_payload_fields_are_retained_but_explicit_false_empty_text_and_lists_are_applied(): void
+ {
+ $input = $this->input();
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $original = $this->payload($record->id);
+ $this->putJson('/parcerias/'.$record->id, ['version' => $record->version, 'kind' => 'seeking', 'payload' => ['summary' => 'SYNTHETIC only new summary']])->assertOk();
+ $saved = $this->payload($record->id);
+ $this->assertSame($original['availability'], $saved['availability']);
+ $this->assertSame($original['mandatory'], $saved['mandatory']);
+ $this->assertTrue($saved['consent']);
+ $version = DB::table('portal_partnerships')->where('id', $record->id)->value('version');
+ $this->putJson('/parcerias/'.$record->id, ['version' => $version, 'kind' => 'seeking', 'payload' => ['mandatory' => [], 'consent' => false, 'requirements' => '']])->assertOk();
+ $saved = $this->payload($record->id);
+ $this->assertSame([], $saved['mandatory']);
+ $this->assertFalse($saved['consent']);
+ $this->assertNull($saved['requirements']);
+ $this->assertSame($original['_creation_hash'], $saved['_creation_hash']);
+ }
+
+ public function test_creation_replay_requires_current_representation_after_the_record_moves_to_another_organization(): void
+ {
+ $a = $this->organization('original organization');
+ $b = $this->organization('current organization');
+ $representative = User::factory()->create();
+ foreach ([[$this->owner->id, $a], [$representative->id, $a], [$representative->id, $b]] as [$user, $organization]) {
+ DB::table('memberships')->insert(['user_id' => $user, 'organization_id' => $organization, 'role' => 'officer']);
+ }
+ $input = $this->input(['organization_id' => $a]);
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ app(PartnershipExchange::class)->save($representative, [...$input, 'version' => $record->version, 'organization_id' => $b], $record->id);
+ $before = (array) DB::table('portal_partnerships')->where('id', $record->id)->first();
+ $this->postJson('/parcerias/rascunhos', $input)->assertForbidden();
+ $this->assertSame($before, (array) DB::table('portal_partnerships')->where('id', $record->id)->first());
+ $this->get('/parcerias/'.$record->id.'/editar')->assertForbidden();
+ }
+
+ public function test_identical_creation_replay_is_read_only_even_when_its_sector_is_no_longer_active(): void
+ {
+ $sector = Sector::create(['name' => 'SYNTHETIC old sector', 'slug' => 'synthetic-'.Str::uuid(), 'is_active' => true]);
+ $input = $this->input(['sector_id' => $sector->id]);
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $sector->update(['is_active' => false]);
+ $before = (array) DB::table('portal_partnerships')->where('id', $record->id)->first();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson('/parcerias/rascunhos', $input)->assertOk()->assertJsonPath('id', $record->id)->assertJsonPath('version', $record->version);
+ $this->assertSame($before, (array) DB::table('portal_partnerships')->where('id', $record->id)->first());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->postJson('/parcerias/rascunhos', [...$input, 'client_key' => (string) Str::uuid()])->assertUnprocessable()->assertJsonValidationErrors('sector_id')->assertJsonPath('errors.sector_id.0', 'Seleccione um sector activo ou deixe a classificação por definir.');
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version])->assertUnprocessable()->assertJsonValidationErrors('sector_id');
+ }
+
+ public function test_stale_version_and_invalid_fields_cannot_overwrite_current_payload(): void
+ {
+ $input = $this->input();
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version, 'title' => 'SYNTHETIC current revision'])->assertOk();
+ $current = (array) DB::table('portal_partnerships')->where('id', $record->id)->first();
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version, 'title' => 'SYNTHETIC stale revision'])->assertConflict();
+ $this->assertSame($current, (array) DB::table('portal_partnerships')->where('id', $record->id)->first());
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $current['version'], 'payload' => ['availability' => str_repeat('a', 1001)]])->assertUnprocessable()->assertJsonValidationErrors('payload.availability')->assertJsonPath('errors', fn ($errors) => ($errors['payload.availability'][0] ?? null) === 'Indique a disponibilidade em até 1000 caracteres.');
+ $this->assertSame($current, (array) DB::table('portal_partnerships')->where('id', $record->id)->first());
+ }
+
+ public function test_editing_a_published_record_still_returns_to_draft_and_preserves_omitted_availability(): void
+ {
+ $manager = User::factory()->create();
+ config(['portal.managers' => [$manager->email]]);
+ $input = $this->input();
+ $record = app(PartnershipExchange::class)->save($this->owner, $input);
+ $exchange = app(PartnershipExchange::class);
+ $record = $exchange->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submission');
+ $record = $exchange->transition($manager, $record->id, $record->version, 'publish', 'SYNTHETIC independent publication');
+ unset($input['payload']['availability']);
+ $this->putJson('/parcerias/'.$record->id, [...$input, 'version' => $record->version, 'title' => 'SYNTHETIC revision for review'])->assertOk()->assertJsonPath('status', 'draft');
+ $this->assertSame('SYNTHETIC resources available from November', $this->payload($record->id)['availability']);
+ }
+
+ public function test_unverified_personal_drafts_and_editor_remain_available_without_organization_or_mfa(): void
+ {
+ $this->owner->update(['email_verified_at' => null]);
+ $record = $this->postJson('/parcerias/rascunhos', $this->input(['title' => '']))->assertOk()->json('id');
+ $this->get('/parcerias/'.$record.'/editar')->assertOk();
+ Http::assertNothingSent();
+ Mail::assertNothingSent();
+ }
+}
diff --git a/tests/Feature/PartnershipParticipantsTest.php b/tests/Feature/PartnershipParticipantsTest.php
new file mode 100644
index 00000000..897debdb
--- /dev/null
+++ b/tests/Feature/PartnershipParticipantsTest.php
@@ -0,0 +1,186 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ }
+
+ private function organization(string $name): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC '.$name, 'source_system' => 'unit-synthetic', 'organization_type' => 'private']);
+
+ return $id;
+ }
+
+ private function member(User $user, string $organization, string $role = 'officer'): void
+ {
+ DB::table('memberships')->insert(['user_id' => $user->id, 'organization_id' => $organization, 'role' => $role]);
+ }
+
+ private function room(?string $proponentOrganization = null, ?string $candidateOrganization = null): array
+ {
+ $owner = User::factory()->create(['name' => 'SYNTHETIC original proponent']);
+ $candidate = User::factory()->create(['name' => 'SYNTHETIC original candidate']);
+ if ($proponentOrganization) {
+ $this->member($owner, $proponentOrganization);
+ }
+ if ($candidateOrganization) {
+ $this->member($candidate, $candidateOrganization);
+ }
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC partnership', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'organization_id' => $proponentOrganization, 'offer' => 'SYNTHETIC offer', 'seeking' => 'SYNTHETIC cooperation', 'payload' => ['consent' => true]]);
+ $service->transition($owner, $record->id, $record->version, 'submit', 'SYNTHETIC consent to review');
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+ $record = $service->find($record->id);
+ $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC reviewed');
+ $interest = $service->interest($candidate, $record->id, ['organization_id' => $candidateOrganization, 'proposal' => 'SYNTHETIC proposal', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC consideration');
+ $service->decideInterest($owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connection');
+ $room = DB::table('partnership_rooms')->where('interest_id', $interest->id)->first();
+ $this->actingAs($owner)->postJson('/parcerias/salas/'.$room->id.'/acordo', ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC plan', 'terms' => 'SYNTHETIC terms', 'reason' => 'SYNTHETIC record'])->assertOk();
+
+ return [$room->id, $owner, $candidate];
+ }
+
+ public function test_authorized_representatives_are_selectable_and_accepted_without_exposing_account_secrets(): void
+ {
+ $proponentOrganization = $this->organization('proponent');
+ $candidateOrganization = $this->organization('candidate');
+ [$room, $owner, $candidate] = $this->room($proponentOrganization, $candidateOrganization);
+ $officer = User::factory()->create(['name' => 'SYNTHETIC current proponent officer']);
+ $manager = User::factory()->create(['name' => 'SYNTHETIC current candidate manager']);
+ $viewer = User::factory()->create();
+ $outsider = User::factory()->create();
+ $this->member($officer, $proponentOrganization);
+ $this->member($manager, $candidateOrganization, 'manager');
+ $this->member($viewer, $proponentOrganization, 'viewer');
+ $otherOrganization = $this->organization('unrelated');
+ $this->member($outsider, $otherOrganization);
+ $response = $this->actingAs($officer)->getJson('/parcerias/salas/'.$room)->assertOk();
+ $choices = collect($response->json('participants'))->keyBy('id');
+ $this->assertEqualsCanonicalizing([$owner->id, $candidate->id, $officer->id, $manager->id], $choices->keys()->all());
+ $this->assertSame(['proponent'], $choices[$officer->id]['parties']);
+ $this->assertSame(['candidate'], $choices[$manager->id]['parties']);
+ foreach ($choices as $choice) {
+ $this->assertEqualsCanonicalizing(['id', 'name', 'parties'], array_keys($choice));
+ }
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC representative deliverable', 'responsible_id' => $manager->id, 'status' => 'pending'])->assertOk();
+ $this->assertDatabaseHas('partnership_milestones', ['room_id' => $room, 'responsible_id' => $manager->id]);
+ $this->getJson('/parcerias/salas/'.$room)->assertJsonPath('milestones.0.responsible_name', $manager->name)->assertJsonPath('milestones.0.responsible_is_participant', true);
+ }
+
+ public function test_revoked_author_is_historical_but_not_silently_reassigned_or_selectable(): void
+ {
+ $organization = $this->organization('revocation');
+ [$room, $owner] = $this->room($organization);
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC assigned before revocation', 'responsible_id' => $owner->id, 'status' => 'pending'])->assertOk();
+ $milestone = DB::table('partnership_milestones')->where('room_id', $room)->first();
+ $officer = User::factory()->create(['name' => 'SYNTHETIC replacement representative']);
+ $this->member($officer, $organization);
+ DB::table('memberships')->where('user_id', $owner->id)->where('organization_id', $organization)->update(['deleted_at' => now()]);
+ $events = DB::table('partnership_events')->count();
+ $response = $this->actingAs($officer)->getJson('/parcerias/salas/'.$room)->assertOk()->assertJsonPath('milestones.0.responsible_name', $owner->name)->assertJsonPath('milestones.0.responsible_is_participant', false);
+ $this->assertNotContains($owner->id, array_column($response->json('participants'), 'id'));
+ $this->assertDatabaseHas('partnership_milestones', ['id' => $milestone->id, 'responsible_id' => $owner->id, 'version' => 1]);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $input = ['version' => 1, 'title' => $milestone->title, 'responsible_id' => $owner->id, 'status' => 'pending'];
+ $this->putJson('/parcerias/salas/'.$room.'/marcos/'.$milestone->id, $input)->assertUnprocessable();
+ $this->putJson('/parcerias/salas/'.$room.'/marcos/'.$milestone->id, [...$input, 'responsible_id' => $officer->id])->assertOk();
+ $this->assertDatabaseHas('partnership_milestones', ['id' => $milestone->id, 'responsible_id' => $officer->id, 'version' => 2]);
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_milestone.changed.v1')->orderByDesc('aggregate_version')->first();
+ $payload = json_decode($event->payload, true)['payload'];
+ $this->assertSame($owner->id, $payload['previous_responsible_id']);
+ $this->assertSame($officer->id, $payload['responsible_id']);
+ $this->actingAs($owner)->getJson('/parcerias/salas/'.$room)->assertForbidden();
+ }
+
+ public function test_personal_parties_are_not_expanded_by_unrelated_memberships_and_dual_representation_is_deduplicated(): void
+ {
+ [$room, $owner, $candidate] = $this->room();
+ $organization = $this->organization('unrelated personal membership');
+ $this->member($owner, $organization);
+ $other = User::factory()->create();
+ $this->member($other, $organization);
+ $response = $this->getJson('/parcerias/salas/'.$room)->assertOk();
+ $this->assertEqualsCanonicalizing([$owner->id, $candidate->id], array_column($response->json('participants'), 'id'));
+ $this->actingAs($other)->getJson('/parcerias/salas/'.$room)->assertForbidden();
+ $a = $this->organization('dual a');
+ $b = $this->organization('dual b');
+ [$secondRoom] = $this->room($a, $b);
+ $dual = User::factory()->create();
+ $this->member($dual, $a);
+ $this->member($dual, $b);
+ $choices = $this->actingAs($dual)->getJson('/parcerias/salas/'.$secondRoom)->assertOk()->json('participants');
+ $matching = array_values(array_filter($choices, fn ($choice) => $choice['id'] === $dual->id));
+ $this->assertCount(1, $matching);
+ $this->assertSame(['proponent', 'candidate'], $matching[0]['parties']);
+ }
+
+ public function test_read_only_and_closed_rooms_do_not_offer_assignment_choices_and_unrelated_users_are_denied(): void
+ {
+ $organization = $this->organization('read only');
+ [$room, $owner] = $this->room($organization);
+ $viewer = User::factory()->create();
+ $this->member($viewer, $organization, 'viewer');
+ $this->actingAs($viewer)->getJson('/parcerias/salas/'.$room)->assertOk()->assertJsonPath('canWrite', false)->assertJsonPath('participants', []);
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC refused', 'responsible_id' => $owner->id, 'status' => 'pending'])->assertForbidden();
+ $this->actingAs(User::factory()->create())->getJson('/parcerias/salas/'.$room)->assertForbidden();
+ $this->actingAs($owner)->postJson('/parcerias/salas/'.$room.'/acordo', ['version' => 2, 'action' => 'cancel', 'reason' => 'SYNTHETIC cancelled'])->assertOk();
+ $this->getJson('/parcerias/salas/'.$room)->assertOk()->assertJsonPath('participants', []);
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC refused', 'responsible_id' => $owner->id, 'status' => 'pending'])->assertConflict();
+ }
+
+ public function test_cached_choices_do_not_authorize_assignment_after_downgrade_and_unrelated_ids_are_refused(): void
+ {
+ $organization = $this->organization('cached selection');
+ [$room, $owner, $candidate] = $this->room($organization);
+ $officer = User::factory()->create();
+ $this->member($officer, $organization);
+ $this->getJson('/parcerias/salas/'.$room)->assertOk()->assertJsonFragment(['id' => $officer->id, 'name' => $officer->name, 'parties' => ['proponent']]);
+ DB::table('memberships')->where('user_id', $officer->id)->where('organization_id', $organization)->update(['role' => 'viewer']);
+ $input = ['title' => 'SYNTHETIC rejected cached assignment', 'responsible_id' => $officer->id, 'status' => 'pending'];
+ $events = DB::table('partnership_events')->count();
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', $input)->assertUnprocessable();
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', [...$input, 'responsible_id' => User::factory()->create()->id])->assertUnprocessable();
+ $this->assertDatabaseCount('partnership_milestones', 0);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', [...$input, 'responsible_id' => $candidate->id])->assertOk();
+ $milestone = DB::table('partnership_milestones')->where('room_id', $room)->first();
+ $this->putJson('/parcerias/salas/'.$room.'/marcos/'.$milestone->id, [...$input, 'responsible_id' => $owner->id, 'version' => 99])->assertConflict();
+ $this->assertDatabaseHas('partnership_milestones', ['id' => $milestone->id, 'responsible_id' => $candidate->id, 'version' => 1]);
+ }
+
+ public function test_deleted_organizations_are_not_assignment_sources_and_personal_participant_remains_available(): void
+ {
+ $organization = $this->organization('deleted');
+ [$room, $owner, $candidate] = $this->room($organization);
+ DB::table('organizations')->where('id', $organization)->update(['deleted_at' => now()]);
+ $response = $this->actingAs($candidate)->getJson('/parcerias/salas/'.$room)->assertOk();
+ $this->assertSame([['id' => $candidate->id, 'name' => $candidate->name, 'parties' => ['candidate']]], $response->json('participants'));
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC unavailable organization', 'responsible_id' => $owner->id, 'status' => 'pending'])->assertUnprocessable();
+ $this->postJson('/parcerias/salas/'.$room.'/marcos', ['title' => 'SYNTHETIC personal participant', 'responsible_id' => $candidate->id, 'status' => 'pending'])->assertOk();
+ $this->actingAs($owner)->getJson('/parcerias/salas/'.$room)->assertForbidden();
+ }
+}
diff --git a/tests/Feature/PartnershipPublicationHistoryTest.php b/tests/Feature/PartnershipPublicationHistoryTest.php
new file mode 100644
index 00000000..4f1b3252
--- /dev/null
+++ b/tests/Feature/PartnershipPublicationHistoryTest.php
@@ -0,0 +1,223 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->moderator = User::factory()->create();
+ config(['portal.managers' => [$this->moderator->email]]);
+ $this->record = app(PartnershipExchange::class)->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC original history title', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC original offer', 'payload' => ['consent' => true, 'confidentiality' => 'private', 'mandatory' => ['capacity']]]);
+ $this->actingAs($this->owner);
+ }
+
+ private function url(?int $id = null): string
+ {
+ return '/parcerias/'.($id ?? $this->record->id).'/historico';
+ }
+
+ private function edit(array $data = []): object
+ {
+ $current = app(PartnershipExchange::class)->find($this->record->id);
+
+ return app(PartnershipExchange::class)->save($this->owner, ['version' => $current->version, 'kind' => 'seeking', ...$data], $current->id);
+ }
+
+ private function organization(User $person, string $role = 'officer'): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC versions organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $person->id, 'organization_id' => $id, 'role' => $role]);
+
+ return $id;
+ }
+
+ public function test_creation_edit_and_transition_have_real_before_and_after_versions_without_a_placeholder(): void
+ {
+ $edit = $this->edit(['title' => 'SYNTHETIC revised title']);
+ app(PartnershipExchange::class)->transition($this->owner, $edit->id, $edit->version, 'submit', 'SYNTHETIC reviewed content', (string) Str::uuid());
+ $this->getJson($this->url())->assertOk()->assertJsonCount(3, 'entries')->assertJsonPath('entries.0.action', 'submit')->assertJsonPath('entries.0.previous.fields.title', 'SYNTHETIC revised title')->assertJsonPath('entries.0.after.status', 'submitted')->assertJsonPath('entries.1.previous.fields.title', 'SYNTHETIC original history title')->assertJsonPath('entries.1.after.fields.title', 'SYNTHETIC revised title')->assertJsonPath('entries.2.action', 'create')->assertJsonPath('entries.2.previous.availability', 'not_recorded')->assertJsonPath('entries.2.after.version', $this->record->version);
+ }
+
+ public function test_publication_is_not_historical_access_for_another_candidate_or_anonymous_reader(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $record = $service->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ $record = $service->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $candidate = User::factory()->create();
+ $service->interest($candidate, $record->id, ['proposal' => 'SYNTHETIC candidate', 'payload' => ['consent' => true]]);
+ $this->actingAs($candidate)->getJson($this->url())->assertForbidden();
+ $this->actingAs($this->moderator)->getJson($this->url())->assertOk();
+ auth()->forgetGuards();
+ $this->getJson($this->url())->assertUnauthorized();
+ }
+
+ public function test_changing_organizations_does_not_transfer_the_prior_private_snapshot(): void
+ {
+ $orgA = $this->organization($this->owner);
+ $this->edit(['organization_id' => $orgA, 'offer' => 'SYNTHETIC A-only offer']);
+ $orgB = $this->organization($this->owner);
+ $this->edit(['organization_id' => $orgB, 'offer' => 'SYNTHETIC B offer']);
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $orgB, 'role' => 'viewer']);
+ $response = $this->actingAs($viewer)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.after.fields.offer', 'SYNTHETIC B offer')->assertJsonPath('entries.0.previous.availability', 'restricted')->assertJsonPath('entries.1.restricted', true)->assertJsonPath('entries.2.restricted', true);
+ $this->assertStringNotContainsString('SYNTHETIC A-only offer', $response->getContent());
+ $this->postJson('/parcerias/'.$this->record->id.'/estado', ['version' => $this->record->version + 2, 'action' => 'archive', 'reason' => 'SYNTHETIC unauthorized action'])->assertForbidden();
+ $this->actingAs($this->moderator)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.previous.fields.offer', 'SYNTHETIC A-only offer');
+ }
+
+ public function test_revoked_author_and_deleted_organization_do_not_keep_owner_history_access(): void
+ {
+ $org = $this->organization($this->owner);
+ $this->edit(['organization_id' => $org]);
+ DB::table('memberships')->where('user_id', $this->owner->id)->where('organization_id', $org)->update(['deleted_at' => now()]);
+ $this->getJson($this->url())->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->owner->id)->where('organization_id', $org)->update(['deleted_at' => null]);
+ DB::table('organizations')->where('id', $org)->update(['deleted_at' => now()]);
+ $this->getJson($this->url())->assertForbidden();
+ $this->actingAs($this->moderator)->getJson($this->url())->assertOk();
+ }
+
+ public function test_legacy_unknown_scope_is_partial_for_moderation_and_not_reconstructed_from_current_content(): void
+ {
+ app(PartnershipExchange::class)->event($this->record, $this->owner, 'partnership_opportunity.changed.v1', ['previous_status' => 'published'], 'SYNTHETIC legacy event');
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['title' => 'SYNTHETIC current-only private title']);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.restricted', true)->assertJsonPath('entries.0.after.availability', 'scope_unknown');
+ $response = $this->actingAs($this->moderator)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.action', null)->assertJsonPath('entries.0.previous.status', 'published')->assertJsonPath('entries.0.previous.version', null)->assertJsonPath('entries.0.after.complete', false)->assertJsonPath('entries.0.after.status', null)->assertJsonPath('entries.0.after.scope_known', false);
+ $this->assertArrayNotHasKey('title', $response->json('entries.0.after.fields'));
+ $this->assertStringNotContainsString('SYNTHETIC current-only private title', $response->getContent());
+ }
+
+ public function test_known_legacy_context_authorizes_only_a_partial_recorded_state_and_reason(): void
+ {
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['status' => 'returned']);
+ $record = app(PartnershipExchange::class)->find($this->record->id);
+ app(PartnershipExchange::class)->event($record, $this->owner, 'partnership_opportunity.returned.v1', ['from' => 'submitted', 'to' => 'returned', 'reason' => 'SYNTHETIC legacy recorded reason'], 'SYNTHETIC legacy notice', [$this->owner->id]);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.reason', 'SYNTHETIC legacy recorded reason')->assertJsonPath('entries.0.action', null)->assertJsonPath('entries.0.after.status', 'returned')->assertJsonPath('entries.0.after.complete', false)->assertJsonPath('entries.0.previous.availability', 'scope_unknown');
+ }
+
+ public function test_pagination_is_stable_when_new_versions_arrive_and_never_includes_candidacy_events(): void
+ {
+ for ($i = 1; $i <= 20; $i++) {
+ $this->edit(['title' => 'SYNTHETIC revision '.$i]);
+ }app(PartnershipExchange::class)->event(app(PartnershipExchange::class)->find($this->record->id), $this->owner, 'partnership_interest.changed.v1', [], 'SYNTHETIC other aggregate');
+ $first = $this->getJson($this->url())->assertOk()->assertJsonCount(10, 'entries')->assertJsonPath('entries.0.version', 22)->assertJsonPath('entries.9.version', 13);
+ $next = $first->json('next_url');
+ $this->edit(['title' => 'SYNTHETIC later revision']);
+ $second = $this->getJson($next)->assertOk()->assertJsonCount(10, 'entries')->assertJsonPath('entries.0.version', 12)->assertJsonPath('entries.9.version', 3);
+ $this->getJson($second->json('next_url'))->assertOk()->assertJsonCount(1, 'entries')->assertJsonPath('entries.0.version', 2)->assertJsonPath('next_url', null);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.version', 23);
+ }
+
+ public function test_cursor_is_bound_to_actor_process_and_purpose_and_never_grants_access_after_revocation(): void
+ {
+ $org = $this->organization($this->owner);
+ $this->edit(['organization_id' => $org]);
+ for ($i = 0; $i < 10; $i++) {
+ $this->edit(['title' => 'SYNTHETIC cursor revision '.$i]);
+ }$cursor = $this->getJson($this->url())->assertOk()->json('next_url');
+ $this->assertIsString($cursor);
+ $this->actingAs($this->moderator)->getJson($cursor)->assertUnprocessable();
+ $this->actingAs($this->owner);
+ $other = app(PartnershipExchange::class)->save($this->owner, ['client_key' => (string) Str::uuid(), 'kind' => 'seeking']);
+ $this->getJson($this->url($other->id).'?'.parse_url($cursor, PHP_URL_QUERY))->assertUnprocessable();
+ $this->getJson($this->url().'?before=invalid-token')->assertUnprocessable();
+ $token = Crypt::encryptString(json_encode(['actor' => $this->owner->id, 'interest' => $this->record->id, 'before' => 999]));
+ $this->getJson($this->url().'?before='.rawurlencode($token))->assertUnprocessable();
+ DB::table('memberships')->where('organization_id', $org)->where('user_id', $this->owner->id)->update(['deleted_at' => now()]);
+ $this->getJson($cursor)->assertForbidden();
+ }
+
+ public function test_native_history_is_read_only_private_and_does_not_serialize_command_or_event_envelopes(): void
+ {
+ app(PartnershipExchange::class)->transition($this->owner, $this->record->id, $this->record->version, 'archive', 'SYNTHETIC archive', (string) Str::uuid());
+ $row = DB::table('portal_partnerships')->where('id', $this->record->id)->first();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $version = app(HandleInertiaRequests::class)->version(Request::create($this->url()));
+ $response = $this->get($this->url(), ['X-Inertia' => 'true', 'X-Inertia-Version' => $version ?? ''])->assertOk()->assertJsonPath('component', 'partnerships/publication-history')->assertJsonPath('encryptHistory', true);
+ $this->assertTrue($response->headers->hasCacheControlDirective('private'));
+ $this->assertTrue($response->headers->hasCacheControlDirective('no-store'));
+ foreach (['command_hash', 'client_key', 'aggregate_version', '_notification_context', '_creation_hash'] as $private) {
+ $this->assertStringNotContainsString($private, $response->getContent());
+ }
+ $this->assertEquals($row, DB::table('portal_partnerships')->where('id', $this->record->id)->first());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+
+ public function test_recorded_references_and_declarations_survive_current_catalogue_changes_and_explicit_clearing(): void
+ {
+ $place = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $place, 'code' => $place, 'name' => 'SYNTHETIC location', 'location_type' => 'country', 'data_classification' => 'public', 'source_system' => 'cartografia-workbook', 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:synthetic-'.substr($place, 0, 8)]);
+ $project = Project::factory()->create();
+ InvestmentDossier::create(['project_id' => $project->id, 'title' => 'SYNTHETIC source', 'source' => 'Synthetic fixture only', 'content' => [], 'publication_status' => 'published', 'published_at' => now()->subMinute(), 'data_classification' => 'public', 'approval_basis' => 'document_owner', 'approval_evidence' => 'Synthetic QA fixture only']);
+ $sector = Sector::create(['name' => 'SYNTHETIC sector', 'slug' => 'synthetic-'.Str::uuid(), 'is_active' => true]);
+ $this->edit(['sector_id' => $sector->id, 'origins' => [['type' => 'project', 'target_id' => $project->id]], 'locations' => [['geo_location_id' => $place, 'role' => 'coverage', 'source_reference' => 'SYNTHETIC original declared source']]]);
+ $this->edit(['sector_id' => null, 'offer' => null, 'origins' => [], 'locations' => [], 'payload' => ['consent' => false, 'mandatory' => []]]);
+ DB::table('geo_locations')->where('id', $place)->update(['name' => 'SYNTHETIC renamed current location']);
+ $sector->update(['is_active' => false]);
+ $response = $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.previous.sector_id', (string) $sector->id)->assertJsonPath('entries.0.previous.origins.0.target_id', $project->id)->assertJsonPath('entries.0.previous.locations.0.source_reference', 'SYNTHETIC original declared source')->assertJsonPath('entries.0.after.fields.offer', '')->assertJsonPath('entries.0.after.consent', false)->assertJsonPath('entries.0.after.mandatory_known', true)->assertJsonPath('entries.0.after.mandatory', [])->assertJsonPath('entries.0.after.origins', []);
+ $this->assertStringNotContainsString('SYNTHETIC renamed current location', $response->getContent());
+ }
+
+ public function test_malformed_scope_or_references_are_unknown_instead_of_a_different_proposal_or_an_empty_source_list(): void
+ {
+ $event = DB::table('partnership_events')->where('partnership_id', $this->record->id)->first();
+ $payload = json_decode($event->payload, true);
+ $original = $payload['payload']['applied'];
+ $payload['payload']['applied']['id'] = $this->record->id + 999;
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $this->actingAs($this->moderator)->getJson($this->url())->assertOk()->assertJsonPath('entries.0.after.availability', 'scope_unknown');
+ $payload['payload']['applied'] = $original;
+ $payload['payload']['applied']['origins'] = [['invalid' => true]];
+ $payload['payload']['applied']['locations'] = [['geo_location_id' => 'invalid identity']];
+ $payload['payload']['applied']['sector_id'] = ['invalid'];
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('entries.0.after.origins_incomplete', true)->assertJsonPath('entries.0.after.locations_incomplete', true)->assertJsonPath('entries.0.after.complete', false)->assertJsonPath('entries.0.after.sector_recorded', false);
+ }
+
+ public function test_repeating_creation_does_not_add_a_false_revision_or_rewrite_a_snapshot(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $input = ['client_key' => (string) Str::uuid(), 'kind' => 'seeking', 'title' => 'SYNTHETIC replay'];
+ $record = $service->save($this->owner, $input);
+ $before = DB::table('partnership_events')->where('partnership_id', $record->id)->first();
+ $service->save($this->owner, $input);
+ $this->assertSame(1, DB::table('partnership_events')->where('partnership_id', $record->id)->count());
+ $this->assertEquals($before, DB::table('partnership_events')->where('partnership_id', $record->id)->first());
+ }
+}
diff --git a/tests/Feature/PartnershipPublicationRecoveryTest.php b/tests/Feature/PartnershipPublicationRecoveryTest.php
new file mode 100644
index 00000000..e0ab1bce
--- /dev/null
+++ b/tests/Feature/PartnershipPublicationRecoveryTest.php
@@ -0,0 +1,189 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->moderator = User::factory()->create();
+ config(['portal.managers' => [$this->moderator->email]]);
+ $this->record = app(PartnershipExchange::class)->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC publication proposal', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'payload' => ['consent' => true, 'confidentiality' => 'private']]);
+ $this->actingAs($this->owner);
+ }
+
+ private function command(string $action, ?int $version = null): array
+ {
+ return ['client_key' => (string) Str::uuid(), 'version' => $version ?? $this->record->version, 'action' => $action, 'reason' => 'SYNTHETIC documented action'];
+ }
+
+ private function url(): string
+ {
+ return '/parcerias/'.$this->record->id.'/estado';
+ }
+
+ public function test_repeating_a_committed_transition_is_a_read_after_a_later_transition(): void
+ {
+ $data = $this->command('archive');
+ $this->postJson($this->url(), $data)->assertOk();
+ $version = (int) DB::table('portal_partnerships')->where('id', $this->record->id)->value('version');
+ $this->postJson($this->url(), $this->command('renew', $version))->assertOk();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('status', 'draft');
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_current_authority_precedes_a_stale_version_conflict(): void
+ {
+ $this->actingAs(User::factory()->create())->postJson($this->url(), $this->command('archive', $this->record->version + 99))->assertForbidden();
+ }
+
+ public function test_publication_actions_match_existing_server_authority_including_suspension(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $submitted = $service->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ $published = $service->transition($this->moderator, $this->record->id, $submitted->version, 'publish', 'SYNTHETIC publish');
+ $this->actingAs($this->moderator)->getJson('/parcerias/'.$published->id)->assertOk()->assertJsonPath('publicationActions', ['suspend']);
+ }
+
+ public function test_same_nonce_with_changed_action_or_reason_is_refused_without_new_writes(): void
+ {
+ $data = $this->command('archive');
+ $this->postJson($this->url(), $data)->assertOk()->assertJsonPath('replayed', false);
+ $events = DB::table('partnership_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->postJson($this->url(), [...$data, 'reason' => 'SYNTHETIC different reason'])->assertConflict();
+ $this->postJson($this->url(), [...$data, 'action' => 'renew'])->assertConflict();
+ $this->postJson($this->url(), [...$data, 'client_key' => strtoupper($data['client_key']), 'reason' => ' '.$data['reason'].' '])->assertOk()->assertJsonPath('replayed', true);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+
+ public function test_audit_keeps_the_proposal_used_before_and_after_transition_without_child_cascades(): void
+ {
+ $data = $this->command('submit');
+ $this->postJson($this->url(), $data)->assertOk();
+ $event = DB::table('partnership_events')->where('event_type', 'partnership_opportunity.submitted.v1')->first();
+ $metadata = json_decode($event->payload, true)['payload'];
+ $this->assertSame('SYNTHETIC publication proposal', $metadata['previous']['title']);
+ $this->assertSame('SYNTHETIC offer', $metadata['applied']['offer']);
+ $this->assertSame('draft', $metadata['previous']['status']);
+ $this->assertSame('submitted', $metadata['applied']['status']);
+ $this->assertSame($this->record->version, $metadata['previous']['version']);
+ $this->assertSame($this->record->version + 1, $metadata['result_version']);
+ $this->assertSame('private', $metadata['previous']['payload']['confidentiality']);
+ $this->assertArrayNotHasKey('_creation_hash', $metadata['previous']['payload']);
+ $this->assertSame(0, DB::table('partnership_interests')->count());
+ $this->assertSame(0, DB::table('partnership_rooms')->count());
+ }
+
+ public function test_revoked_organization_author_cannot_replay_even_a_committed_transition(): void
+ {
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC publisher organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $this->owner->id, 'organization_id' => $org, 'role' => 'officer']);
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['organization_id' => $org]);
+ $data = $this->command('archive');
+ $this->postJson($this->url(), $data)->assertOk();
+ DB::table('memberships')->where('user_id', $this->owner->id)->where('organization_id', $org)->update(['deleted_at' => now()]);
+ $this->postJson($this->url(), $data)->assertForbidden();
+ }
+
+ public function test_owner_cannot_publish_their_own_proposal_even_with_the_moderation_gate(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $record = $service->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ config(['portal.managers' => [$this->owner->email]]);
+ $this->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('publicationActions', []);
+ $this->postJson($this->url(), $this->command('publish', $record->version))->assertForbidden();
+ }
+
+ public function test_command_keys_are_private_to_the_current_authorized_actor_and_raw_events_stay_private(): void
+ {
+ $data = $this->command('submit');
+ $this->postJson($this->url(), $data)->assertOk();
+ $response = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('publicationCommands.0.key', strtolower($data['client_key']));
+ $response->assertJsonMissingPath('history');
+ $summary = $response->json('historySummary.entries.0');
+ $this->assertIsArray($summary);
+ foreach (['payload', 'event_type', 'actor_id', 'command_hash'] as $private) {
+ $this->assertArrayNotHasKey($private, $summary);
+ }
+ $this->assertStringNotContainsString('command_hash', $response->getContent());
+ $this->assertStringNotContainsString('_notification_context', $response->getContent());
+ $this->actingAs($this->moderator)->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('publicationCommands', []);
+ $record = app(PartnershipExchange::class)->find($this->record->id);
+ app(PartnershipExchange::class)->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $this->actingAs(User::factory()->create())->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('publicationCommands', [])->assertJsonPath('publicationActions', [])->assertJsonPath('historySummary', null)->assertJsonMissingPath('history');
+ }
+
+ public function test_validation_and_legacy_requests_preserve_existing_submission_requirements(): void
+ {
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url(), [...$this->command('submit'), 'reason' => ' '])->assertUnprocessable();
+ $this->postJson($this->url(), [...$this->command('submit'), 'client_key' => 'invalid'])->assertUnprocessable();
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['payload' => json_encode(['consent' => false])]);
+ $this->postJson($this->url(), $this->command('submit'))->assertUnprocessable();
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ DB::table('portal_partnerships')->where('id', $this->record->id)->update(['payload' => json_encode(['consent' => true])]);
+ $legacy = $this->command('submit');
+ unset($legacy['client_key']);
+ $this->postJson($this->url(), $legacy)->assertOk()->assertJsonPath('replayed', false);
+ }
+
+ public function test_losing_moderation_authority_prevents_replay_and_removes_its_command_metadata(): void
+ {
+ $service = app(PartnershipExchange::class);
+ $record = $service->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ $data = $this->command('publish', $record->version);
+ $this->actingAs($this->moderator)->postJson($this->url(), $data)->assertOk();
+ config(['portal.managers' => []]);
+ $this->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('publicationCommands', []);
+ $this->postJson($this->url(), $data)->assertForbidden();
+ }
+
+ public function test_stale_version_does_not_write_and_suspension_uses_the_existing_state_graph(): void
+ {
+ $this->postJson($this->url(), $this->command('archive', $this->record->version + 1))->assertConflict();
+ $service = app(PartnershipExchange::class);
+ $record = $service->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ $record = $service->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $this->actingAs($this->moderator)->postJson($this->url(), $this->command('suspend', $record->version))->assertOk()->assertJsonPath('status', 'suspended');
+ $this->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('publicationActions', []);
+ $this->actingAs($this->owner)->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('publicationActions', ['archive', 'renew']);
+ }
+
+ public function test_nonce_is_scoped_to_process_and_actor_and_another_owner_cannot_recover_it(): void
+ {
+ $data = $this->command('archive');
+ $this->postJson($this->url(), $data)->assertOk();
+ $other = User::factory()->create();
+ $record = app(PartnershipExchange::class)->save($other, ['client_key' => (string) Str::uuid(), 'kind' => 'seeking']);
+ $this->actingAs($other)->postJson('/parcerias/'.$record->id.'/estado', [...$data, 'version' => $record->version])->assertOk()->assertJsonPath('replayed', false);
+ $this->postJson($this->url(), $data)->assertForbidden();
+ }
+}
diff --git a/tests/Feature/PartnershipPublicationSummaryTest.php b/tests/Feature/PartnershipPublicationSummaryTest.php
new file mode 100644
index 00000000..af4def38
--- /dev/null
+++ b/tests/Feature/PartnershipPublicationSummaryTest.php
@@ -0,0 +1,171 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ $this->owner = User::factory()->create();
+ $this->moderator = User::factory()->create();
+ config(['portal.managers' => [$this->moderator->email]]);
+ $this->record = app(PartnershipExchange::class)->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC original history title', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC original offer', 'payload' => ['consent' => true, 'confidentiality' => 'private', 'mandatory' => ['capacity']]]);
+ $this->actingAs($this->owner);
+ }
+
+ private function url(?int $id = null): string
+ {
+ return '/parcerias/'.($id ?? $this->record->id).'/historico';
+ }
+
+ private function edit(array $data = []): object
+ {
+ $current = app(PartnershipExchange::class)->find($this->record->id);
+
+ return app(PartnershipExchange::class)->save($this->owner, ['version' => $current->version, 'kind' => 'seeking', ...$data], $current->id);
+ }
+
+ private function organization(User $person, string $role = 'officer'): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $id, 'name' => 'SYNTHETIC versions organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['user_id' => $person->id, 'organization_id' => $id, 'role' => $role]);
+
+ return $id;
+ }
+
+ public function test_detail_exposes_a_bounded_summary_instead_of_raw_event_rows(): void
+ {
+ for ($i = 0; $i < 9; $i++) {
+ $this->edit(['title' => 'SYNTHETIC revision '.$i]);
+ }
+ $response = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonMissingPath('history')->assertJsonPath('historySummary.limit', 5)->assertJsonCount(5, 'historySummary.entries')->assertJsonPath('historySummary.has_more', true);
+ $entries = $response->json('historySummary.entries');
+ $current = app(PartnershipExchange::class)->find($this->record->id);
+ $this->assertSame([(int) $current->version, (int) $current->version - 1, (int) $current->version - 2, (int) $current->version - 3, (int) $current->version - 4], array_column($entries, 'version'));
+ $this->getJson($response->json('historySummary.href'))->assertOk()->assertJsonCount(10, 'entries');
+ }
+
+ public function test_summary_metadata_and_states_match_the_authorized_full_reader_without_snapshots(): void
+ {
+ $record = $this->edit(['title' => 'SYNTHETIC newer title']);
+ app(PartnershipExchange::class)->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC reviewed reason');
+ $summary = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->json('historySummary');
+ $full = $this->getJson($this->url())->assertOk()->json('entries');
+ foreach ($summary['entries'] as $index => $entry) {
+ foreach (['version', 'restricted', 'action', 'actor_name', 'occurred_at', 'reason'] as $field) {
+ $this->assertSame($full[$index][$field], $entry[$field]);
+ }
+ $this->assertSame(($full[$index]['previous']['availability'] === 'available' ? $full[$index]['previous']['status'] ?? null : null), $entry['status_before']);
+ $this->assertSame(($full[$index]['after']['availability'] === 'available' ? $full[$index]['after']['status'] ?? null : null), $entry['status_after']);
+ }
+ foreach (['event_type', 'actor_id', 'previous', 'after', 'payload', 'offer', 'client_key', 'operation_hash'] as $private) {
+ $this->assertStringNotContainsString('"'.$private.'"', json_encode($summary));
+ }
+ $this->assertSame('SYNTHETIC reviewed reason', $summary['entries'][0]['reason']);
+ $this->assertFalse($summary['has_more']);
+ }
+
+ public function test_a_new_organization_representative_does_not_receive_old_actor_or_decision_metadata(): void
+ {
+ $a = $this->organization($this->owner);
+ $this->edit(['organization_id' => $a]);
+ $oldActor = User::factory()->create(['name' => 'SYNTHETIC OLD PRIVATE ACTOR']);
+ DB::table('memberships')->insert(['user_id' => $oldActor->id, 'organization_id' => $a, 'role' => 'officer']);
+ $current = app(PartnershipExchange::class)->find($this->record->id);
+ app(PartnershipExchange::class)->save($oldActor, ['version' => $current->version, 'kind' => 'seeking', 'title' => 'SYNTHETIC A draft'], $current->id);
+ $b = $this->organization($this->owner);
+ $this->edit(['organization_id' => $b]);
+ $viewer = User::factory()->create();
+ DB::table('memberships')->insert(['user_id' => $viewer->id, 'organization_id' => $b, 'role' => 'viewer']);
+ $response = $this->actingAs($viewer)->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('canEdit', false)
+ ->assertJsonPath('historySummary.entries.0.restricted', false)->assertJsonPath('historySummary.entries.0.status_before', null)
+ ->assertJsonPath('historySummary.entries.1.restricted', true)->assertJsonPath('historySummary.entries.1.actor_name', null)
+ ->assertJsonPath('historySummary.entries.1.occurred_at', null)->assertJsonPath('historySummary.entries.1.action', null)->assertJsonPath('historySummary.entries.1.reason', null);
+ $this->assertStringNotContainsString('OLD PRIVATE ACTOR', $response->getContent());
+ $this->postJson('/parcerias/'.$this->record->id.'/estado', ['version' => 99, 'action' => 'archive', 'reason' => 'SYNTHETIC viewer cannot decide'])->assertForbidden();
+ DB::table('memberships')->where('user_id', $viewer->id)->update(['deleted_at' => now()]);
+ $this->getJson('/parcerias/'.$this->record->id)->assertNotFound();
+ }
+
+ public function test_moderation_keeps_its_existing_historical_access(): void
+ {
+ $a = $this->organization($this->owner);
+ $this->edit(['organization_id' => $a]);
+ $b = $this->organization($this->owner);
+ $this->edit(['organization_id' => $b]);
+ $this->actingAs($this->moderator)->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('moderator', true)
+ ->assertJsonPath('historySummary.entries.1.restricted', false)->assertJsonPath('historySummary.entries.1.actor_name', $this->owner->name);
+ }
+
+ public function test_public_and_candidate_reads_have_no_historical_summary_even_after_publication(): void
+ {
+ $exchange = app(PartnershipExchange::class);
+ $record = $exchange->transition($this->owner, $this->record->id, $this->record->version, 'submit', 'SYNTHETIC submit');
+ $record = $exchange->transition($this->moderator, $record->id, $record->version, 'publish', 'SYNTHETIC publish');
+ $candidate = User::factory()->create();
+ $exchange->interest($candidate, $record->id, ['proposal' => 'SYNTHETIC candidacy', 'payload' => ['consent' => true]]);
+ $this->actingAs($candidate)->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('historySummary', null)->assertJsonMissingPath('history');
+ $this->getJson($this->url())->assertForbidden();
+ auth()->forgetGuards();
+ $this->getJson('/parcerias/'.$record->id)->assertOk()->assertJsonPath('historySummary', null)->assertJsonMissingPath('history');
+ }
+
+ public function test_legacy_scope_unknown_does_not_become_current_authority_or_an_inferred_action(): void
+ {
+ $event = DB::table('partnership_events')->where('partnership_id', $this->record->id)->first();
+ $payload = json_decode($event->payload, true);
+ unset($payload['payload']['previous'],$payload['payload']['applied'],$payload['payload']['_notification_context']);
+ $payload['payload']['reason'] = 'SYNTHETIC RESERVED REASON';
+ DB::table('partnership_events')->where('id', $event->id)->update(['payload' => json_encode($payload)]);
+ $result = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonPath('historySummary.entries.0.restricted', true)
+ ->assertJsonPath('historySummary.entries.0.action', null)->assertJsonPath('historySummary.entries.0.status_after', null)->assertJsonPath('historySummary.entries.0.actor_name', null);
+ $this->assertStringNotContainsString('RESERVED REASON', $result->getContent());
+ }
+
+ public function test_no_publication_events_is_an_explicit_empty_summary_with_a_valid_history_link(): void
+ {
+ DB::table('partnership_events')->where('partnership_id', $this->record->id)->update(['event_type' => 'synthetic_unrelated.v1']);
+ $response = $this->getJson('/parcerias/'.$this->record->id)->assertOk()->assertJsonCount(0, 'historySummary.entries')->assertJsonPath('historySummary.has_more', false)
+ ->assertJsonPath('historySummary.href', '/parcerias/'.$this->record->id.'/historico');
+ $this->getJson($response->json('historySummary.href'))->assertOk()->assertJsonCount(0, 'entries');
+ }
+
+ public function test_native_and_json_summary_reads_do_not_change_versions_audit_or_notifications(): void
+ {
+ $before = DB::table('portal_partnerships')->where('id', $this->record->id)->first();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notices = DB::table('partnership_notifications')->count();
+ $this->get('/parcerias/'.$this->record->id)->assertOk()->assertInertia(fn (Assert $p) => $p->component('partnerships/detail')->where('historySummary.limit', 5)->missing('history'));
+ $this->getJson('/parcerias/'.$this->record->id)->assertOk();
+ $this->assertEquals($before, DB::table('portal_partnerships')->where('id', $this->record->id)->first());
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->assertSame($audits, DB::table('audit_events')->count());
+ $this->assertSame($notices, DB::table('partnership_notifications')->count());
+ }
+}
diff --git a/tests/Feature/PartnershipRoomRecoveryTest.php b/tests/Feature/PartnershipRoomRecoveryTest.php
new file mode 100644
index 00000000..ac6c6a97
--- /dev/null
+++ b/tests/Feature/PartnershipRoomRecoveryTest.php
@@ -0,0 +1,214 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ Storage::fake('local');
+ $this->owner = User::factory()->create();
+ $this->candidate = User::factory()->create();
+ $service = app(PartnershipExchange::class);
+ $record = $service->save($this->owner, ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC recovery', 'kind' => 'seeking', 'partnership_type' => 'joint_venture', 'offer' => 'SYNTHETIC offer', 'seeking' => 'SYNTHETIC cooperation', 'payload' => ['consent' => true]]);
+ $record = $service->transition($this->owner, $record->id, $record->version, 'submit', 'SYNTHETIC submission');
+ $moderator = User::factory()->create();
+ config(['portal.managers' => [$moderator->email]]);
+ $service->transition($moderator, $record->id, $record->version, 'publish', 'SYNTHETIC moderation');
+ $interest = $service->interest($this->candidate, $record->id, ['proposal' => 'SYNTHETIC proposal', 'payload' => ['consent' => true]]);
+ $interest = $service->decideInterest($this->owner, $interest->id, $interest->version, 'shortlist', 'SYNTHETIC shortlist');
+ $service->decideInterest($this->owner, $interest->id, $interest->version, 'connect', 'SYNTHETIC connection');
+ $this->roomId = (int) DB::table('partnership_rooms')->where('interest_id', $interest->id)->value('id');
+ $this->actingAs($this->owner)->postJson($this->url('acordo'), ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC plan', 'terms' => 'SYNTHETIC terms', 'reason' => 'SYNTHETIC record'])->assertOk();
+ }
+
+ private function url(string $suffix = ''): string
+ {
+ return '/parcerias/salas/'.$this->roomId.($suffix ? '/'.$suffix : '');
+ }
+
+ private function milestone(): array
+ {
+ return ['client_key' => (string) Str::uuid(), 'title' => 'SYNTHETIC deliverable', 'responsible_id' => $this->candidate->id, 'due_date' => null, 'status' => 'pending', 'evidence' => null];
+ }
+
+ private function upload(string $key, bool $shared = false, string $content = 'SYNTHETIC PDF', string $name = 'synthetic-proof.pdf'): array
+ {
+ return ['client_key' => $key, 'shared' => $shared, 'file' => UploadedFile::fake()->createWithContent($name, "%PDF-1.4\n".$content."\n%%EOF")];
+ }
+
+ private function closeRoom(): void
+ {
+ $this->postJson($this->url('acordo'), ['version' => 2, 'action' => 'cancel', 'reason' => 'SYNTHETIC closed while response uncertain'])->assertOk();
+ }
+
+ public function test_creation_replay_has_one_milestone_event_audit_and_notification_set(): void
+ {
+ $input = $this->milestone();
+ $events = DB::table('partnership_events')->count();
+ $audits = DB::table('audit_events')->count();
+ $notifications = DB::table('partnership_notifications')->count();
+ $first = $this->postJson($this->url('marcos'), $input)->assertOk()->assertJsonPath('replayed', false)->json('milestone_id');
+ $this->postJson($this->url('marcos'), $input)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('milestone_id', $first)->assertJsonPath('version', 1);
+ $this->postJson($this->url('marcos'), [...$input, 'client_key' => strtoupper($input['client_key'])])->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('milestone_id', $first);
+ $this->assertDatabaseCount('partnership_milestones', 1);
+ $this->assertSame($events + 1, DB::table('partnership_events')->count());
+ $this->assertSame($audits + 1, DB::table('audit_events')->count());
+ $this->assertSame($notifications + 2, DB::table('partnership_notifications')->count());
+ $this->getJson($this->url())->assertOk()->assertJsonPath('milestones.0.client_key', $input['client_key']);
+ $this->actingAs($this->candidate)->getJson($this->url())->assertOk()->assertJsonPath('milestones.0.client_key', null);
+ }
+
+ public function test_creation_replay_after_update_and_closure_never_rewrites_the_milestone(): void
+ {
+ $input = $this->milestone();
+ $id = $this->postJson($this->url('marcos'), $input)->assertOk()->json('milestone_id');
+ $this->putJson($this->url('marcos/'.$id), [...$input, 'title' => 'SYNTHETIC revised deliverable', 'version' => 1])->assertOk();
+ $this->closeRoom();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url('marcos'), $input)->assertOk()->assertJsonPath('milestone_id', $id)->assertJsonPath('version', 2)->assertJsonPath('replayed', true);
+ $this->assertDatabaseHas('partnership_milestones', ['id' => $id, 'title' => 'SYNTHETIC revised deliverable', 'version' => 2]);
+ $this->postJson($this->url('marcos'), [...$input, 'client_key' => (string) Str::uuid()])->assertConflict();
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_milestone_keys_are_content_bound_scoped_per_actor_and_legacy_requests_still_work(): void
+ {
+ $input = $this->milestone();
+ $this->postJson($this->url('marcos'), $input)->assertOk();
+ $this->postJson($this->url('marcos'), [...$input, 'title' => 'SYNTHETIC different command'])->assertConflict();
+ $this->postJson($this->url('marcos'), [...$input, 'client_key' => 'not-a-uuid'])->assertUnprocessable();
+ $this->actingAs($this->candidate)->postJson($this->url('marcos'), $input)->assertOk()->assertJsonPath('replayed', false);
+ unset($input['client_key']);
+ $this->postJson($this->url('marcos'), $input)->assertOk();
+ $this->assertDatabaseCount('partnership_milestones', 3);
+ }
+
+ public function test_recovery_does_not_restore_revoked_representation_or_allow_a_read_only_actor(): void
+ {
+ $input = $this->milestone();
+ $this->postJson($this->url('marcos'), $input)->assertOk();
+ $record = DB::table('partnership_rooms as r')->join('partnership_interests as i', 'i.id', '=', 'r.interest_id')->where('r.id', $this->roomId)->value('i.partnership_id');
+ $org = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $org, 'name' => 'SYNTHETIC new representation', 'organization_type' => 'private']);
+ DB::table('portal_partnerships')->where('id', $record)->update(['organization_id' => $org]);
+ DB::table('memberships')->insert(['organization_id' => $org, 'user_id' => $this->owner->id, 'role' => 'viewer']);
+ $this->getJson($this->url())->assertOk()->assertJsonPath('canWrite', false);
+ $this->postJson($this->url('marcos'), $input)->assertForbidden();
+ DB::table('memberships')->where('user_id', $this->owner->id)->update(['deleted_at' => now()]);
+ $this->postJson($this->url('marcos'), $input)->assertForbidden();
+ $this->assertDatabaseCount('partnership_milestones', 1);
+ }
+
+ public function test_upload_replay_preserves_original_bytes_one_link_and_one_scan_dispatch(): void
+ {
+ $key = (string) Str::uuid();
+ $events = DB::table('partnership_events')->count();
+ $id = $this->postJson($this->url('documentos'), $this->upload($key))->assertOk()->assertJsonPath('replayed', false)->json('document_id');
+ $this->postJson($this->url('documentos'), $this->upload($key))->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('document_id', $id);
+ $this->postJson($this->url('documentos'), $this->upload(strtoupper($key)))->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('document_id', $id);
+ $this->postJson($this->url('documentos'), $this->upload($key, true))->assertConflict();
+ $this->postJson($this->url('documentos'), $this->upload($key, false, 'SYNTHETIC different bytes'))->assertConflict();
+ $this->postJson($this->url('documentos'), $this->upload($key, false, 'SYNTHETIC PDF', 'renamed.pdf'))->assertConflict();
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('partnership_documents', 1);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ Queue::assertPushed(ScanDocumentForMalware::class, 1);
+ $this->assertSame($events + 1, DB::table('partnership_events')->count());
+ $document = DB::table('documents')->where('id', $id)->first();
+ $this->assertSame('quarantined', $document->status);
+ $this->assertSame($document->sha256, hash_file('sha256', Storage::disk('local')->path($document->storage_key)));
+ }
+
+ public function test_upload_recovery_after_revocation_and_closure_does_not_reshare_or_requeue(): void
+ {
+ $key = (string) Str::uuid();
+ $id = $this->postJson($this->url('documentos'), $this->upload($key, true))->assertOk()->json('document_id');
+ $link = DB::table('partnership_documents')->where('document_id', $id)->first();
+ $this->postJson($this->url('documentos/'.$link->id.'/partilha'), ['shared' => false])->assertOk();
+ $this->closeRoom();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url('documentos'), $this->upload($key, true))->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('document_id', $id);
+ $this->assertDatabaseHas('partnership_documents', ['id' => $link->id, 'shared' => false]);
+ Queue::assertPushed(ScanDocumentForMalware::class, 1);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ $this->postJson($this->url('documentos'), $this->upload((string) Str::uuid()))->assertConflict();
+ $this->actingAs($this->candidate)->getJson($this->url())->assertOk()->assertJsonCount(0, 'documents');
+ $this->postJson($this->url('documentos'), $this->upload($key, true))->assertConflict();
+ }
+
+ public function test_message_recovery_after_closure_is_read_only_and_keys_are_not_disclosed_to_the_other_party(): void
+ {
+ $input = ['client_key' => (string) Str::uuid(), 'body' => 'SYNTHETIC uncertain message'];
+ $this->postJson($this->url('mensagens'), $input)->assertOk();
+ $this->getJson($this->url())->assertOk()->assertJsonPath('messages.0.client_key', $input['client_key']);
+ $this->actingAs($this->candidate)->getJson($this->url())->assertOk()->assertJsonPath('messages.0.client_key', null);
+ $this->actingAs($this->owner);
+ $this->closeRoom();
+ $events = DB::table('partnership_events')->count();
+ $this->postJson($this->url('mensagens'), $input)->assertOk();
+ $this->postJson($this->url('mensagens'), [...$input, 'body' => 'SYNTHETIC different content'])->assertConflict();
+ $this->postJson($this->url('mensagens'), [...$input, 'client_key' => (string) Str::uuid()])->assertConflict();
+ $this->assertDatabaseCount('partnership_messages', 1);
+ $this->assertSame($events, DB::table('partnership_events')->count());
+ }
+
+ public function test_stale_agreement_and_milestone_updates_preserve_the_current_state_and_evidence(): void
+ {
+ $input = $this->milestone();
+ $id = $this->postJson($this->url('marcos'), $input)->assertOk()->json('milestone_id');
+ $this->putJson($this->url('marcos/'.$id), [...$input, 'version' => 1, 'status' => 'completed', 'evidence' => 'SYNTHETIC frozen result'])->assertOk();
+ $this->putJson($this->url('marcos/'.$id), [...$input, 'version' => 1])->assertConflict();
+ $this->postJson($this->url('acordo'), ['version' => 1, 'action' => 'record', 'title' => 'SYNTHETIC stale', 'terms' => 'SYNTHETIC stale terms', 'reason' => 'SYNTHETIC stale attempt'])->assertConflict();
+ $this->assertDatabaseHas('partnership_milestones', ['id' => $id, 'version' => 2, 'status' => 'completed', 'evidence' => 'SYNTHETIC frozen result']);
+ $this->assertDatabaseHas('partnership_rooms', ['id' => $this->roomId, 'version' => 2, 'status' => 'agreement_recorded']);
+ }
+
+ public function test_failed_document_event_rolls_back_the_new_file_without_removing_an_existing_original(): void
+ {
+ $id = $this->postJson($this->url('documentos'), $this->upload((string) Str::uuid()))->assertOk()->json('document_id');
+ $original = DB::table('documents')->where('id', $id)->first();
+ $exchange = \Mockery::mock(PartnershipExchange::class)->makePartial();
+ $exchange->shouldReceive('event')->once()->andThrow(new \RuntimeException('SYNTHETIC event failure'));
+ $this->app->instance(PartnershipExchange::class, $exchange);
+ $input = $this->upload((string) Str::uuid(), false, 'SYNTHETIC failed second upload');
+ try {
+ app(PartnershipRoomUploads::class)->save($this->owner, $this->roomId, $input['file'], false, $input['client_key']);
+ $this->fail('The synthetic event failure should abort the new upload.');
+ } catch (\RuntimeException $error) {
+ $this->assertSame('SYNTHETIC event failure', $error->getMessage());
+ }
+ $this->assertDatabaseCount('documents', 1);
+ $this->assertDatabaseCount('partnership_documents', 1);
+ $this->assertCount(1, Storage::disk('local')->allFiles());
+ $this->assertSame($original->sha256, hash_file('sha256', Storage::disk('local')->path($original->storage_key)));
+ Queue::assertPushed(ScanDocumentForMalware::class, 1);
+ }
+}
diff --git a/tests/Feature/ProactiveSupplyReviewTest.php b/tests/Feature/ProactiveSupplyReviewTest.php
new file mode 100644
index 00000000..0c940025
--- /dev/null
+++ b/tests/Feature/ProactiveSupplyReviewTest.php
@@ -0,0 +1,188 @@
+withoutVite();
+ config(['portal.profile_access_enabled' => true, 'portal.managers' => [], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->actor = F::operator();
+ $this->login($this->actor);
+ $parent = null;
+ foreach (['country', 'province', 'district'] as $level) {
+ $id = (string) Str::uuid();
+ DB::table('geo_locations')->insert(['id' => $id, 'name' => 'SYNTHETIC review '.$level, 'code' => $id, 'location_type' => $level,
+ 'parent_id' => $parent, 'data_classification' => 'public', 'source_system' => 'cartografia-workbook',
+ 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$id]);
+ $parent = $id;
+ }
+ $this->territory = $parent;
+ $this->source = hash('sha256', 'SYNTHETIC-SUPPLY-REVIEW-20261102');
+ DB::table('proactive_supply_sources')->insert(['sha256' => $this->source, 'name' => 'SYNTHETIC review source.xlsx', 'period' => 'Synthetic historical data',
+ 'limitations' => 'Synthetic observations, not actual establishments', 'receipt' => json_encode(['private_contact' => 'SYNTHETIC PRIVATE CONTACT', 'nuit' => 'SYNTHETIC PRIVATE IDENTIFIER']), 'imported_at' => now()]);
+ $base = ['source_hash' => $this->source, 'sheet' => 'SYNTHETIC QA', 'entity_key' => hash('sha256', 'SYNTHETIC ENTITY'),
+ 'name' => 'SYNTHETIC 100% Algodão', 'province' => 'Zambézia', 'district' => 'Gurué', 'cae' => '01610', 'activity' => 'Cultivo de algodão', 'sector' => 'Synthetic agriculture',
+ 'source_date' => 'Serial Excel original: 45000', 'duplicate_of' => null, 'identity_conflict' => false, 'territory_id' => $this->territory, 'territory_resolution' => 'exact_normalized_province_district'];
+ foreach ([
+ 2 => [], 3 => ['name' => 'SYNTHETIC 1000', 'activity' => '', 'territory_id' => null, 'territory_resolution' => 'unresolved'],
+ 4 => ['name' => 'Denominação não indicada', 'territory_id' => null, 'territory_resolution' => 'ambiguous'],
+ 5 => ['name' => 'SYNTHETIC other denomination', 'identity_conflict' => true, 'territory_id' => '10000000-0000-4000-8000-000000000001'],
+ 6 => ['duplicate_of' => $this->id(2)], 7 => ['name' => 'SYNTHETIC_UNDER_SCORE', 'territory_id' => null, 'territory_resolution' => 'unresolved'],
+ ] as $number => $changes) {
+ DB::table('proactive_supply_observations')->insert([...$base, 'id' => $this->id($number), 'row_number' => $number,
+ 'fingerprint' => hash('sha256', 'SYNTHETIC-FINGERPRINT-'.($number === 6 ? 2 : $number)), ...$changes]);
+ }
+ }
+
+ private function login(User $actor): void
+ {
+ $this->actingAs($actor)->withSession(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'portal.access_revision' => (int) $actor->portal_access_revision]);
+ }
+
+ private function id(int $row): string
+ {
+ return hash('sha256', $this->source.'|SYNTHETIC QA|'.$row);
+ }
+
+ private function url(array $filters = []): string
+ {
+ return $this->base.'?'.http_build_query(['source_hash' => $this->source, ...$filters]);
+ }
+
+ public function test_unmapped_and_ambiguous_rows_are_recoverable_without_mutation_or_a_guessed_territory(): void
+ {
+ $before = DB::table('proactive_supply_observations')->where('source_hash', $this->source)->orderBy('id')->get()->toJson();
+ $response = $this->getJson($this->url())->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertJsonPath('total', 3)->assertJsonPath('coverage.observations', 6)->assertJsonPath('coverage.distinct_observations', 5)
+ ->assertJsonPath('coverage.repeated', 1)->assertJsonPath('coverage.unmapped', 3)->assertJsonPath('coverage.ambiguous', 1)
+ ->assertJsonPath('coverage.territory_unavailable', 1)->assertJsonPath('coverage.identity_conflict', 1)
+ ->assertJsonPath('coverage.unclassified', 1)->assertJsonPath('coverage.unnamed', 1);
+ foreach ($response->json('rows') as $row) {
+ $this->assertNull($row['territory_id']);
+ $this->assertNull($row['canonical_territory']);
+ }
+ $this->getJson($this->url(['status' => 'ambiguous']))->assertOk()->assertJsonPath('total', 1)->assertJsonPath('rows.0.id', $this->id(4));
+ $this->getJson($this->url(['status' => 'all', 'observation_id' => $this->id(4)]))->assertOk()
+ ->assertJsonPath('rows.0.sheet', 'SYNTHETIC QA')->assertJsonPath('rows.0.row_number', 4)->assertJsonPath('rows.0.source_hash', $this->source)
+ ->assertJsonPath('rows.0.source_date', 'Serial Excel original: 45000');
+ $this->assertSame($before, DB::table('proactive_supply_observations')->where('source_hash', $this->source)->orderBy('id')->get()->toJson());
+ }
+
+ public function test_private_receipts_identity_hashes_contacts_and_private_territories_are_not_projected(): void
+ {
+ $response = $this->getJson($this->url(['status' => 'all']))->assertOk()->assertDontSee('SYNTHETIC PRIVATE CONTACT')->assertDontSee('SYNTHETIC PRIVATE IDENTIFIER');
+ foreach ($response->json('rows') as $row) {
+ foreach (['entity_key', 'fingerprint', 'receipt', 'contact', 'nuit', 'geom'] as $key) {
+ $this->assertArrayNotHasKey($key, $row);
+ }
+ }
+ foreach ($response->json('sources') as $source) {
+ $this->assertArrayNotHasKey('receipt', $source);
+ }
+ $this->getJson($this->url(['status' => 'territory_unavailable']))->assertOk()->assertJsonCount(1, 'rows')->assertJsonPath('rows.0.canonical_territory', null);
+ $this->getJson('/minhas-oportunidades/oferta-interna?territory_id='.$this->territory)->assertOk()->assertJsonMissingPath('rows.0.entity_key');
+ }
+
+ public function test_repeated_sightings_identity_conflicts_and_activity_gaps_are_distinct_and_not_consolidated(): void
+ {
+ $this->getJson($this->url(['status' => 'repeated']))->assertOk()->assertJsonPath('total', 1)->assertJsonPath('rows.0.duplicate_of', $this->id(2));
+ $this->getJson($this->url(['status' => 'identity_conflict']))->assertOk()->assertJsonPath('rows.0.id', $this->id(5));
+ $this->getJson($this->url(['status' => 'unclassified']))->assertOk()->assertJsonPath('rows.0.id', $this->id(3));
+ $this->getJson($this->url(['status' => 'unnamed']))->assertOk()->assertJsonPath('rows.0.id', $this->id(4));
+ $this->assertSame(6, DB::table('proactive_supply_observations')->where('source_hash', $this->source)->count());
+ }
+
+ public function test_text_search_is_accent_insensitive_and_wildcards_are_literal(): void
+ {
+ foreach (['algodao', 'ALGODÃO', '100%'] as $q) {
+ $response = $this->getJson($this->url(['status' => 'all', 'q' => $q]))->assertOk();
+ $this->assertGreaterThan(0, $response->json('total'));
+ $this->assertNotContains($this->id(3), array_column($response->json('rows'), 'id'));
+ }
+ $this->getJson($this->url(['status' => 'all', 'q' => 'UNDER_']))->assertOk()->assertJsonPath('total', 1)->assertJsonPath('rows.0.id', $this->id(7));
+ $this->getJson($this->url(['status' => 'all', 'q' => 'NO-SYNTHETIC-MATCH']))->assertOk()->assertJsonPath('total', 0)->assertJsonPath('status', 'Informação insuficiente nesta base e nestes filtros.');
+ }
+
+ public function test_pagination_and_direct_reference_recover_the_same_source_line(): void
+ {
+ $base = (array) DB::table('proactive_supply_observations')->where('id', $this->id(2))->first();
+ for ($row = 100; $row < 126; $row++) {
+ DB::table('proactive_supply_observations')->insert([...$base, 'id' => $this->id($row), 'row_number' => $row,
+ 'name' => 'SYNTHETIC PAGE '.$row, 'fingerprint' => hash('sha256', 'SYNTHETIC-PAGE-'.$row)]);
+ }
+ $this->getJson($this->url(['status' => 'all', 'q' => 'SYNTHETIC PAGE']))->assertOk()->assertJsonPath('total', 26)->assertJsonCount(25, 'rows')->assertJsonPath('rows.0.row_number', 100);
+ $this->getJson($this->url(['status' => 'all', 'q' => 'SYNTHETIC PAGE', 'page' => 2]))->assertOk()->assertJsonCount(1, 'rows')->assertJsonPath('rows.0.row_number', 125);
+ $this->getJson($this->url(['status' => 'all', 'observation_id' => $this->id(125), 'page' => 999]))->assertOk()->assertJsonPath('filters.page', 1)->assertJsonPath('rows.0.row_number', 125);
+ }
+
+ public function test_unassigned_users_cannot_enumerate_or_validate_private_inventory_and_invalid_filters_are_explicit(): void
+ {
+ $this->getJson($this->url(['status' => 'not-a-state']))->assertUnprocessable();
+ $this->getJson($this->url(['source_hash' => str_repeat('f', 64)]))->assertUnprocessable()->assertJsonValidationErrors('source_hash');
+ $this->login(User::factory()->create());
+ $this->getJson($this->url())->assertForbidden();
+ $this->getJson($this->base.'?record_id=999999999&source_hash=invalid')->assertForbidden();
+ $this->getJson('/minhas-oportunidades/oferta-interna?record_id=999999999')->assertForbidden();
+ }
+
+ public function test_private_page_is_wired_and_preserves_applied_filters(): void
+ {
+ $this->get($this->url(['status' => 'ambiguous']))->assertOk()->assertHeader('Cache-Control', 'no-store, private')
+ ->assertInertia(fn ($page) => $page->component('management/proactive-supply-review')->where('filters.status', 'ambiguous')->where('rows.0.id', $this->id(4)));
+ }
+
+ public function test_existing_comparison_keeps_server_side_lineage_and_rejects_repetitions(): void
+ {
+ $service = app(ProactiveSupply::class);
+ $evidence = $service->evidence($this->actor, $this->id(2), null);
+ $this->assertSame('internal', $evidence['access']);
+ $this->assertStringContainsString($this->source, $evidence['source']);
+ $this->assertSame('SYNTHETIC QA!linha 2', $evidence['locator']);
+ $comparison = ['observation_id' => $this->id(2), 'relationship' => 'uncertain', 'rationale' => 'SYNTHETIC comparison', 'limitations' => 'SYNTHETIC unknown current operation'];
+ $this->assertSame([$comparison], $service->comparisons($this->actor, [$comparison], null));
+ $this->expectException(ValidationException::class);
+ $service->comparisons($this->actor, [[...$comparison, 'observation_id' => $this->id(6)]], null);
+ }
+
+ public function test_database_policy_requires_actor_context_for_sources_and_observations(): void
+ {
+ $role = 'supply_review_qa_'.bin2hex(random_bytes(6));
+ DB::statement('CREATE ROLE '.$role.' NOLOGIN');
+ DB::statement('GRANT USAGE ON SCHEMA public TO '.$role);
+ DB::statement('GRANT SELECT ON proactive_supply_sources,proactive_supply_observations TO '.$role);
+ DB::select("select set_config('app.actor_user_id','',true),set_config('app.proactive_supply_read','',true)");
+ try {
+ DB::statement('SET LOCAL ROLE '.$role);
+ $this->assertSame(0, DB::table('proactive_supply_observations')->count());
+ $this->assertSame(0, DB::table('proactive_supply_sources')->count());
+ DB::select("select set_config('app.actor_user_id',?,true),set_config('app.proactive_supply_read','internal',true)", [(string) $this->actor->id]);
+ $this->assertSame(6, DB::table('proactive_supply_observations')->where('source_hash', $this->source)->count());
+ $this->assertSame(1, DB::table('proactive_supply_sources')->where('sha256', $this->source)->count());
+ } finally {
+ DB::statement('RESET ROLE');
+ }
+ }
+}
diff --git a/tests/Feature/ProductExperimentsTest.php b/tests/Feature/ProductExperimentsTest.php
new file mode 100644
index 00000000..a7bb8fdf
--- /dev/null
+++ b/tests/Feature/ProductExperimentsTest.php
@@ -0,0 +1,272 @@
+withoutVite();
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 12:00:00.123456', 'UTC'));
+ Http::preventStrayRequests();
+ $this->manager = User::factory()->create();
+ $this->other = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false]);
+ }
+
+ protected function tearDown(): void
+ {
+ $this->travelBack();
+ parent::tearDown();
+ }
+
+ private function body(array $values = [], int $version = 0, array $extra = []): array
+ {
+ return [...['version' => $version, 'operation_key' => (string) Str::uuid(), 'reason' => $version > 0 ? 'SYNTHETIC revision, no real experiment' : '', 'values' => ['state' => 'draft', 'title' => 'PRIVATE SYNTHETIC experiment', ...$values], 'indicator_definition_version' => config('product-metrics.version')], ...$extra];
+ }
+
+ private function plan(string $state = 'planned'): array
+ {
+ $values = array_fill_keys(['reference', 'hypothesis', 'segment', 'control', 'variant', 'assignment', 'criterion', 'transparency', 'consent', 'security', 'equality'], 'PRIVATE SYNTHETIC description; not production evidence');
+
+ return [...$values, 'title' => 'PRIVATE SYNTHETIC plan', 'state' => $state, 'change_kind' => 'form', 'indicator_id' => 'manual', 'indicator_title' => 'SYNTHETIC proportion', 'indicator_definition' => 'SYNTHETIC numerator / denominator, only observed sample', 'indicator_unit' => '%', 'preserves_requirements' => 'yes', 'period_from' => '2026-11-02', 'period_to' => '2026-11-04'];
+ }
+
+ private function observation(): array
+ {
+ return ['observed_from' => '2026-11-02', 'observed_to' => '2026-11-02', 'control_result' => 'SYNTHETIC 0; not an actual user sample', 'variant_result' => 'SYNTHETIC unknown; no inferred zero', 'result' => 'SYNTHETIC inconclusive comparison', 'limitations' => 'SYNTHETIC fixture, no real allocation or causal claim', 'evidence' => 'SYNTHETIC isolated QA receipt', 'decision' => 'inconclusive', 'decision_reason' => 'No real experiment or customer acceptance is claimed.'];
+ }
+
+ private function create(array $body): string
+ {
+ return $this->actingAs($this->manager)->postJson($this->url, $body)->assertCreated()->json('id');
+ }
+
+ public function test_existing_manager_authority_private_transport_and_read_only_views_are_preserved(): void
+ {
+ $this->getJson($this->url)->assertUnauthorized();
+ $this->actingAs($this->other)->getJson($this->url)->assertForbidden();
+ $this->postJson($this->url, $this->body())->assertForbidden();
+ $this->actingAs($this->manager)->getJson($this->url)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('total', 0);
+ $this->get($this->url)->assertOk()->assertInertia(fn ($p) => $p->component('management/experiments/index'));
+ $this->get($this->url.'/new')->assertOk()->assertInertia(fn ($p) => $p->component('management/experiments/edit'));
+ $this->assertDatabaseCount('product_experiments', 0);
+ $this->assertDatabaseCount('product_experiment_revisions', 0);
+ $this->assertSame(0, DB::table('audit_events')->where('source_system', 'product-experiments')->count());
+ config(['portal.managers' => []]);
+ $this->getJson($this->url)->assertForbidden();
+ $this->manager->forceFill(['email_verified_at' => null])->save();
+ config(['portal.managers' => [$this->manager->email]]);
+ $this->getJson($this->url)->assertForbidden();
+ }
+
+ public function test_incomplete_drafts_are_encrypted_replayable_and_version_conflicts_never_overwrite_history(): void
+ {
+ $first = $this->body(['hypothesis' => 'PRIVATE SYNTHETIC original']);
+ $id = $this->create($first);
+ $this->postJson($this->url, $first)->assertCreated()->assertJsonPath('replayed', true)->assertJsonPath('id', $id);
+ $this->postJson($this->url, [...$first, 'values' => [...$first['values'], 'title' => 'Changed']])->assertConflict();
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', DB::table('product_experiment_revisions')->value('snapshot'));
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', DB::table('audit_events')->where('source_system', 'product-experiments')->get()->toJson());
+ $changed = $this->body(['hypothesis' => 'PRIVATE SYNTHETIC changed'], 1);
+ $this->postJson($this->url.'/'.$id.'/revisions', $changed)->assertOk()->assertJsonPath('version', 2);
+ $this->postJson($this->url.'/'.$id.'/revisions', $changed)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body(['title' => 'Stale edit'], 1))->assertConflict();
+ $this->postJson($this->url, $first)->assertCreated()->assertJsonPath('version', 1);
+ $this->getJson($this->url.'/'.$id)->assertOk()->assertJsonPath('values.hypothesis', 'PRIVATE SYNTHETIC changed')->assertJsonPath('currentVersion', 2);
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('historical', true)->assertJsonPath('values.hypothesis', 'PRIVATE SYNTHETIC original');
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($changed['values'], 2))->assertOk()->assertJsonPath('unchanged', true);
+ $this->postJson($this->url, $this->body(['server_snapshot' => 'FORGED']))->assertUnprocessable();
+ $this->assertDatabaseCount('product_experiment_revisions', 2);
+ $this->assertDatabaseCount('desk_cases', 0);
+ DB::statement('SET CONSTRAINTS product_experiment_current_revision IMMEDIATE');
+ }
+
+ public function test_registered_plans_require_actual_definition_and_all_four_protections_without_backdating_authorship(): void
+ {
+ $this->actingAs($this->manager);
+ foreach (['transparency', 'consent', 'security', 'equality', 'preserves_requirements'] as $key) {
+ $this->postJson($this->url, $this->body([...$this->plan(), $key => '']))->assertUnprocessable()->assertJsonValidationErrors('values.'.$key);
+ }
+ $this->postJson($this->url, $this->body(['state' => 'planned']))->assertUnprocessable();
+ $this->assertDatabaseCount('product_experiments', 0);
+ $id = $this->create($this->body($this->plan(), extra: ['actor' => ['id' => $this->other->id], 'registration' => ['first_at' => '2000-01-01']]));
+ $r = $this->getJson($this->url.'/'.$id)->assertOk()->json('document');
+ $this->assertSame('2026-11-03T12:00:00.123456+00:00', $r['registration']['first_at']);
+ $this->assertSame($this->manager->id, $r['actor']['id']);
+ $this->assertSame(0, $r['registration']['amendments']);
+ $this->assertSame(config('product-experiments.fields'), $r['vocabulary']['fields']);
+ $this->assertSame('manual', $r['indicator']['id']);
+ config(['product-experiments.version' => 'SYNTHETIC new registry edition', 'product-experiments.fields.title' => 'SYNTHETIC changed field label']);
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body([...$this->plan(), 'title' => 'SYNTHETIC title only correction'], 1))->assertOk();
+ $this->assertSame($r['indicator'], $this->getJson($this->url.'/'.$id)->json('document.indicator'));
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('labels.title', $r['vocabulary']['fields']['title'])->assertJsonPath('document.definition_version', $r['definition_version']);
+ }
+
+ public function test_observation_decision_and_optional_report_preserve_unknowns_and_do_not_claim_variant_measurement(): void
+ {
+ $values = [...$this->plan('reviewed'), ...$this->observation()];
+ $id = $this->create($this->body($values, extra: ['attach_report' => true, 'operational_report' => ['FORGED' => 99]]));
+ $r = $this->getJson($this->url.'/'.$id)->assertOk()->json('document');
+ $this->assertSame('operational_cohort_not_experiment_arm', $r['report_scope']);
+ $this->assertTrue($r['report_matches_observation']);
+ $this->assertNull(collect($r['operational_report']['metrics'])->firstWhere('id', 'submission_rate')['value']);
+ $this->assertSame(0, collect($r['operational_report']['metrics'])->firstWhere('id', 'requests_created')['value']);
+ $this->assertSame('inconclusive', $r['values']['decision']);
+ $this->assertArrayNotHasKey('FORGED', $r['operational_report']);
+ $this->travelTo(CarbonImmutable::parse('2026-11-04 12:00:00', 'UTC'));
+ $values['observed_to'] = '2026-11-03';
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 1))->assertOk();
+ $new = $this->getJson($this->url.'/'.$id)->assertOk()->json('document');
+ $this->assertSame($r['operational_report'], $new['operational_report']);
+ $this->assertFalse($new['report_matches_observation']);
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 2, ['remove_report' => true]))->assertOk();
+ $this->getJson($this->url.'/'.$id)->assertOk()->assertJsonPath('document.operational_report', null);
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('document.operational_report.filters.to', '2026-11-02');
+ $this->assertDatabaseCount('desk_cases', 0);
+ $this->assertDatabaseCount('desk_requests', 0);
+ $this->assertSame(0, InterestRequest::query()->count());
+ }
+
+ public function test_amending_a_registered_plan_keeps_prior_observations_bound_until_explicit_review(): void
+ {
+ $values = [...$this->plan('reviewed'), ...$this->observation()];
+ $id = $this->create($this->body($values));
+ $original = $this->getJson($this->url.'/'.$id)->json('document');
+ $values = [...$values, 'state' => 'planned', 'hypothesis' => 'SYNTHETIC changed hypothesis'];
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 1))->assertUnprocessable()->assertJsonValidationErrors('confirm_plan_change');
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 1, ['confirm_plan_change' => true]))->assertOk();
+ $new = $this->getJson($this->url.'/'.$id)->json('document');
+ $this->assertSame(1, $new['registration']['amendments']);
+ $this->assertTrue($new['registration']['amended_after_observation']);
+ $this->assertSame($original['plan_sha256'], $new['observation_plan_sha256']);
+ $this->assertNotSame($new['plan_sha256'], $new['observation_plan_sha256']);
+ $values['state'] = 'reviewed';
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 2))->assertUnprocessable()->assertJsonValidationErrors('values.result');
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 2, ['confirm_observation_plan' => true]))->assertOk();
+ $last = $this->getJson($this->url.'/'.$id)->json('document');
+ $this->assertSame($last['plan_sha256'], $last['observation_plan_sha256']);
+ $this->assertTrue($last['observation_reaffirmed_for_plan']);
+ $this->assertSame($original['registration']['first_at'], $last['registration']['first_at']);
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('values.hypothesis', $original['values']['hypothesis']);
+ }
+
+ public function test_catalogue_definitions_remain_frozen_and_refresh_requires_explicit_plan_revision(): void
+ {
+ $body = $this->body([...$this->plan(), 'indicator_id' => 'submission_rate']);
+ $id = $this->create($body);
+ $old = $this->getJson($this->url.'/'.$id)->json('document.indicator');
+ config(['product-metrics.version' => 'SYNTHETIC new definition edition']);
+ $values = [...$body['values'], 'title' => 'SYNTHETIC title correction'];
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 1))->assertOk();
+ $this->assertSame($old, $this->getJson($this->url.'/'.$id)->json('document.indicator'));
+ $this->postJson($this->url, $body)->assertCreated()->assertJsonPath('version', 1)->assertJsonPath('replayed', true);
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 2, ['refresh_indicator' => true]))->assertUnprocessable()->assertJsonValidationErrors('confirm_plan_change');
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 2, ['refresh_indicator' => true, 'confirm_plan_change' => true]))->assertOk();
+ $this->getJson($this->url.'/'.$id)->assertOk()->assertJsonPath('document.indicator.definition_version', 'SYNTHETIC new definition edition');
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('document.indicator.definition_version', $old['definition_version']);
+ }
+
+ public function test_amended_period_can_preserve_old_observation_dates_without_reclassifying_them_as_new_results(): void
+ {
+ $values = [...$this->plan('reviewed'), ...$this->observation()];
+ $id = $this->create($this->body($values));
+ $old = $this->getJson($this->url.'/'.$id)->json('document');
+ $values = [...$values, 'state' => 'planned', 'period_from' => '2026-11-03', 'period_to' => '2026-11-05'];
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body($values, 1, ['confirm_plan_change' => true]))->assertOk();
+ $current = $this->getJson($this->url.'/'.$id)->json('document');
+ $this->assertSame('2026-11-02', $current['values']['observed_from']);
+ $this->assertSame($old['plan_sha256'], $current['observation_plan_sha256']);
+ $this->assertNotSame($current['plan_sha256'], $current['observation_plan_sha256']);
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body([...$values, 'state' => 'reviewed'], 2, ['confirm_observation_plan' => true]))->assertUnprocessable()->assertJsonValidationErrors('values.observed_from');
+ $this->getJson($this->url.'/'.$id.'?revision=1')->assertOk()->assertJsonPath('values.period_from', '2026-11-02')->assertJsonPath('values.observed_from', '2026-11-02');
+ $this->assertDatabaseCount('product_experiment_revisions', 2);
+ }
+
+ public function test_invalid_dates_unknown_indicators_and_incomplete_results_cannot_be_recorded_as_complete(): void
+ {
+ $this->actingAs($this->manager);
+ foreach ([['period_from' => '2026-11-05'], ['indicator_id' => 'forged'], ['indicator_definition' => ''], ['state' => 'observing', 'observed_from' => '2026-11-04'], ['state' => 'reviewed'], ['observed_from' => '2026-11-01']] as $bad) {
+ $this->postJson($this->url, $this->body([...$this->plan(), ...$bad]))->assertUnprocessable();
+ }
+ $this->postJson($this->url, $this->body($this->plan(), extra: ['attach_report' => true]))->assertUnprocessable();
+ $this->postJson($this->url, $this->body([...$this->plan('reviewed'), ...$this->observation(), 'report_service' => 'invented'], extra: ['attach_report' => true]))->assertUnprocessable();
+ $this->assertDatabaseCount('product_experiments', 0);
+ $this->assertDatabaseCount('product_experiment_revisions', 0);
+ }
+
+ public function test_database_enforces_append_only_history_immutable_origin_and_current_revision_integrity(): void
+ {
+ $id = $this->create($this->body());
+ DB::statement('SET CONSTRAINTS product_experiment_current_revision IMMEDIATE');
+ foreach ([fn () => DB::table('product_experiment_revisions')->where('experiment_id', $id)->update(['snapshot' => 'FORGED']), fn () => DB::table('product_experiments')->where('id', $id)->delete(), fn () => DB::statement('TRUNCATE product_experiment_revisions CASCADE'), fn () => DB::table('product_experiments')->where('id', $id)->update(['version' => 9]), fn () => DB::table('product_experiments')->where('id', $id)->update(['version' => 2, 'created_by' => $this->other->id]), function () use ($id) {
+ DB::table('product_experiments')->where('id', $id)->update(['version' => 2]);
+ DB::statement('SET CONSTRAINTS product_experiment_current_revision IMMEDIATE');
+ }] as $mutation) {
+ try {
+ DB::transaction($mutation);
+ $this->fail('History/identity integrity must reject this mutation.');
+ } catch (QueryException $error) {
+ $this->assertContains($error->getCode(), ['23514', '23503']);
+ }
+ }
+ DB::statement('SET CONSTRAINTS product_experiment_current_revision DEFERRED');
+ $this->postJson($this->url.'/'.$id.'/revisions', $this->body(['title' => 'SYNTHETIC valid next version'], 1))->assertOk()->assertJsonPath('version', 2);
+ DB::statement('SET CONSTRAINTS product_experiment_current_revision IMMEDIATE');
+ $this->assertDatabaseCount('product_experiment_revisions', 2);
+ }
+
+ public function test_history_and_listing_are_paginated_and_historical_reads_do_not_create_revisions(): void
+ {
+ $id = $this->create($this->body());
+ $service = app(ProductExperiments::class);
+ for ($v = 1; $v < 28; $v++) {
+ $service->save($this->manager, $id, $this->body(['title' => 'SYNTHETIC version '.($v + 1)], $v));
+ }
+ for ($v = 1; $v < 26; $v++) {
+ $service->save($this->manager, null, $this->body(['title' => 'SYNTHETIC additional '.$v]));
+ }
+ $this->getJson($this->url.'/'.$id)->assertOk()->assertJsonCount(25, 'history')->assertJsonPath('historyNext', 4)->assertJsonPath('history.0.version', 28);
+ $this->getJson($this->url.'/'.$id.'?history_before=4&revision=1')->assertOk()->assertJsonCount(3, 'history')->assertJsonPath('historyNext', null)->assertJsonPath('historical', true);
+ $this->getJson($this->url.'?page=999')->assertOk()->assertJsonPath('page', 2)->assertJsonPath('total', 26)->assertJsonCount(1, 'items');
+ $this->getJson($this->url.'?state=planned')->assertOk()->assertJsonPath('total', 0);
+ $this->getJson($this->url.'/'.$id.'?revision=999')->assertNotFound();
+ $this->assertDatabaseCount('product_experiment_revisions', 53);
+ }
+
+ public function test_missing_registry_schema_does_not_disable_the_operational_metrics_or_create_records(): void
+ {
+ $this->actingAs($this->manager);
+ Schema::rename('product_experiment_revisions', 'product_experiment_revisions_qa_temporarily_unavailable');
+ try {
+ $this->getJson($this->url)->assertOk()->assertJsonPath('installed', false)->assertJsonCount(0, 'items');
+ $this->getJson($this->url.'/new')->assertOk()->assertJsonPath('installed', false)->assertJsonPath('values.state', 'draft');
+ $this->postJson($this->url, $this->body())->assertStatus(503);
+ $this->getJson('/management/product-usage')->assertOk()->assertJsonCount(13, 'report.unmeasured');
+ $this->assertDatabaseCount('product_experiments', 0);
+ } finally {
+ Schema::rename('product_experiment_revisions_qa_temporarily_unavailable', 'product_experiment_revisions');
+ }
+ }
+}
diff --git a/tests/Feature/ProductUsageMetricsTest.php b/tests/Feature/ProductUsageMetricsTest.php
new file mode 100644
index 00000000..5c0c5607
--- /dev/null
+++ b/tests/Feature/ProductUsageMetricsTest.php
@@ -0,0 +1,206 @@
+withoutVite();
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 12:00:00.123456', 'UTC'));
+ Http::preventStrayRequests();
+ $this->manager = User::factory()->create();
+ $this->owner = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'portal.notifications_enabled' => false, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->service = $this->service('synthetic-service', 1);
+ }
+
+ protected function tearDown(): void
+ {
+ $this->travelBack();
+ parent::tearDown();
+ }
+
+ private function service(string $code, int $version): string
+ {
+ $id = (string) Str::uuid();
+ DB::table('desk_service_versions')->insert(['id' => $id, 'code' => $code, 'version' => $version, 'status' => 'published', 'definition' => json_encode(['title' => 'SYNTHETIC service', 'fields' => ['title' => ['type' => 'text', 'label' => 'Title', 'required' => true]]]), 'source' => '{}', 'author_id' => $this->manager->id, 'published_at' => now()->subDays(10), 'created_at' => now()->subDays(10), 'updated_at' => now()->subDays(10)]);
+
+ return $id;
+ }
+
+ /** @param list}> $events */
+ private function request(array $events, string $created = '2026-11-02 10:00:00', ?string $service = null, ?int $version = null): string
+ {
+ $case = (string) Str::uuid();
+ $id = (string) Str::uuid();
+ $desk = app(VirtualDesk::class);
+ DB::table('desk_cases')->insert(['id' => $case, 'user_id' => $this->owner->id, 'title' => 'PRIVATE SYNTHETIC title', 'client_key' => (string) Str::uuid(), 'payload' => $desk->encode(['private' => 'PRIVATE SYNTHETIC DATA']), 'workflow' => '[]', 'created_at' => $created, 'updated_at' => $created]);
+ $latest = $events === [] ? $created : $events[array_key_last($events)][2];
+ DB::table('desk_requests')->insert(['id' => $id, 'case_id' => $case, 'service_version_id' => $service ?? $this->service, 'client_key' => (string) Str::uuid(), 'payload' => $desk->encode(['title' => 'PRIVATE SYNTHETIC DATA']), 'version' => $version ?? max(array_column($events, 0) ?: [1]), 'created_at' => $created, 'updated_at' => $latest]);
+ foreach ($events as [$v, $action, $date, $payload]) {
+ $this->event($id, $v, $action, $date, $payload ?? []);
+ }
+
+ return $id;
+ }
+
+ private function event(string $id, int $version, string $action, string $date, array $payload = []): void
+ {
+ DB::table('desk_events')->insert(['id' => (string) Str::uuid(), 'case_id' => DB::table('desk_requests')->where('id', $id)->value('case_id'), 'request_id' => in_array($action, ['company_comparison_saved', 'investment_guide_saved'], true) ? null : $id, 'actor_id' => $this->manager->id, 'action' => $action, 'version' => $version, 'payload' => app(VirtualDesk::class)->encode($payload), 'created_at' => $date]);
+ }
+
+ private function report(array $filters = []): array
+ {
+ return $this->actingAs($this->manager)->getJson('/management/product-usage?'.http_build_query(['from' => '2026-11-02', 'to' => '2026-11-02', ...$filters]))->assertOk()->assertHeader('Cache-Control', 'no-store, private')->json('report');
+ }
+
+ private function metric(array $report, string $id): array
+ {
+ return collect($report['metrics'])->firstWhere('id', $id);
+ }
+
+ public function test_report_is_authorised_read_only_and_contains_no_private_records_or_invented_empty_rates(): void
+ {
+ $this->getJson('/management/product-usage')->assertUnauthorized();
+ $this->actingAs($this->owner)->getJson('/management/product-usage')->assertForbidden();
+ $before = DB::table('audit_events')->count();
+ $r = $this->report();
+ $this->assertSame(0, $this->metric($r, 'requests_created')['value']);
+ $this->assertNull($this->metric($r, 'submission_rate')['value']);
+ $this->assertSame(0, $this->metric($r, 'not_submitted')['value']);
+ $this->assertSame($before, DB::table('audit_events')->count());
+ $this->assertDatabaseCount('desk_cases', 0);
+ $this->assertDatabaseCount('desk_events', 0);
+ $this->assertSame(13, count($r['unmeasured']));
+ $this->get('/management/product-usage')->assertOk()->assertInertia(fn ($page) => $page->component('management/product-usage'));
+ config(['portal.managers' => []]);
+ $this->getJson('/management/product-usage')->assertForbidden();
+ $this->manager->forceFill(['email_verified_at' => null])->save();
+ config(['portal.managers' => [$this->manager->email]]);
+ $this->getJson('/management/product-usage')->assertForbidden();
+ }
+
+ public function test_first_submission_and_return_rates_deduplicate_versions_and_exclude_incomplete_histories(): void
+ {
+ $id = $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:01:00', []], [3, 'request_returned', '2026-11-02 10:02:00', ['return_reason_code' => 'missing_documents']], [4, 'submitted', '2026-11-02 11:00:00', []], [4, 'request_context_reviewed', '2026-11-02 11:00:00', []], [5, 'request_returned', '2026-11-02 11:01:00', []]]);
+ // The mutable latest-submission field must never replace the first immutable event.
+ DB::table('desk_requests')->where('id', $id)->update(['submitted_at' => '2026-11-02 11:00:00']);
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []]]);
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [3, 'submitted', '2026-11-02 10:02:00', []]]);
+ $legacy = $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []]], version: 3);
+ DB::table('desk_requests')->where('id', $legacy)->update(['updated_at' => null]);
+ $r = $this->report();
+ $this->assertSame(4, $r['coverage']['cohort_requests']);
+ $this->assertSame(2, $r['coverage']['complete_histories']);
+ $this->assertSame(2, $r['coverage']['unknown_histories']);
+ $this->assertEquals(50, $this->metric($r, 'submission_rate')['value']);
+ $this->assertEquals(100, $this->metric($r, 'return_rate')['value']);
+ $this->assertEquals(100, $this->metric($r, 'error_document_return_rate')['value']);
+ $this->assertEquals(60, $this->metric($r, 'first_submission_seconds')['value']);
+ $this->assertSame('partial', $this->metric($r, 'submission_rate')['state']);
+ $this->assertSame(1, $this->metric($r, 'not_submitted')['value']);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC', json_encode($r));
+ $this->assertStringNotContainsString($id, json_encode($r));
+ }
+
+ public function test_historical_unclassified_returns_remain_unknown_and_free_text_does_not_classify_them(): void
+ {
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:01:00', []], [3, 'request_returned', '2026-11-02 10:02:00', ['reason' => 'Documentação em falta, erro nos dados']]]);
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:01:00', []], [3, 'request_returned', '2026-11-02 10:02:00', ['return_reason_code' => 'other']]]);
+ $r = $this->report();
+ $this->assertNull($this->metric($r, 'error_document_return_rate')['value']);
+ $this->assertSame(0, $this->metric($r, 'error_document_return_rate')['numerator']);
+ $this->assertSame(2, $this->metric($r, 'error_document_return_rate')['denominator']);
+ $this->assertSame(1, $r['coverage']['unclassified_returned_requests']);
+ $this->assertEquals(100, $this->metric($r, 'return_rate')['value']);
+ }
+
+ public function test_inclusive_days_cutoff_historical_service_versions_and_distinct_saved_dossiers(): void
+ {
+ $v2 = $this->service('synthetic-service', 2);
+ $other = $this->service('other-service', 1);
+ $a = $this->request([[1, 'draft_created', '2026-11-02 00:00:00', []], [2, 'submitted', '2026-11-03 00:00:00', []]], '2026-11-02 00:00:00');
+ $this->request([[1, 'draft_created', '2026-11-02 23:59:59', []]], '2026-11-02 23:59:59', $v2);
+ $this->request([], '2026-11-01 23:59:59');
+ $this->request([], '2026-11-03 00:00:00');
+ $this->request([], '2026-11-02 12:00:00', $other);
+ $this->event($a, 2, 'company_comparison_saved', '2026-11-02 11:00:00');
+ $this->event($a, 3, 'company_comparison_saved', '2026-11-02 12:00:00');
+ $this->event($a, 3, 'investment_guide_saved', '2026-11-02 13:00:00');
+ $r = $this->report(['service_code' => 'synthetic-service']);
+ $this->assertSame(2, $this->metric($r, 'requests_created')['value']);
+ $this->assertSame(2, $this->metric($r, 'dossiers_created')['value']);
+ $this->assertSame(1, $this->metric($r, 'saved_comparison')['value']);
+ $this->assertSame(1, $this->metric($r, 'saved_guide')['value']);
+ $this->assertSame('2026-11-03T00:00:00.000000+00:00', $r['observed_before']);
+ $this->assertSame(2, collect($r['services'])->firstWhere('code', 'synthetic-service')['version']);
+ $this->assertSame(0, $this->metric($r, 'submission_rate')['numerator']);
+ }
+
+ public function test_negative_event_clock_intervals_are_excluded_without_turning_zero_duration_into_unknown(): void
+ {
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 09:59:59', []]]);
+ $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:00:00', []]]);
+ $r = $this->report();
+ $this->assertEquals(0, $this->metric($r, 'first_submission_seconds')['value']);
+ $this->assertSame('partial', $this->metric($r, 'first_submission_seconds')['state']);
+ $this->assertSame(1, $r['coverage']['invalid_duration_requests']);
+ $this->assertSame(1, $r['coverage']['valid_duration_requests']);
+ }
+
+ public function test_transition_keeps_optional_versioned_category_and_application_event_time_without_changing_authority(): void
+ {
+ $id = $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:01:00', []]]);
+ DB::table('desk_requests')->where('id', $id)->update(['status' => 'submitted', 'protocol' => 'SYNTHETIC-'.$id, 'submitted_snapshot' => app(VirtualDesk::class)->encode([]), 'submitted_at' => '2026-11-02 10:01:00']);
+ $url = '/balcao-virtual/pedidos/'.$id.'/estado';
+ $data = ['version' => 2, 'status' => 'returned', 'reason' => 'SYNTHETIC correction', 'editable_fields' => ['title'], 'return_reason_code' => 'validation_error'];
+ $this->actingAs($this->owner)->postJson($url, $data)->assertForbidden();
+ $this->actingAs($this->manager)->postJson($url, [...$data, 'return_reason_code' => 'invented'])->assertUnprocessable();
+ $this->postJson($url, $data)->assertOk();
+ $event = DB::table('desk_events')->where('request_id', $id)->where('action', 'request_returned')->first();
+ $p = app(VirtualDesk::class)->decode($event->payload);
+ $this->assertSame('validation_error', $p['return_reason_code']);
+ $this->assertSame(config('product-metrics.return_reasons.validation_error'), $p['return_reason_label']);
+ $this->assertSame(config('product-metrics.version'), $p['return_reason_definition']);
+ $this->assertSame(now()->toDateTimeString(), CarbonImmutable::parse($event->created_at)->toDateTimeString());
+ $this->postJson($url, $data)->assertConflict();
+ $this->assertSame(1, DB::table('desk_events')->where('action', 'request_returned')->count());
+ $other = $this->request([[1, 'draft_created', '2026-11-02 10:00:00', []], [2, 'submitted', '2026-11-02 10:01:00', []]]);
+ DB::table('desk_requests')->where('id', $other)->update(['status' => 'submitted', 'protocol' => 'SYNTHETIC-'.$other, 'submitted_snapshot' => app(VirtualDesk::class)->encode([]), 'submitted_at' => '2026-11-02 10:01:00']);
+ unset($data['return_reason_code']);
+ $this->postJson('/balcao-virtual/pedidos/'.$other.'/estado', $data)->assertOk();
+ $legacy = DB::table('desk_events')->where('request_id', $other)->where('action', 'request_returned')->value('payload');
+ $this->assertSame('unspecified', app(VirtualDesk::class)->decode($legacy)['return_reason_code']);
+ }
+
+ public function test_report_rejects_invalid_periods_services_and_does_not_fall_back_to_another_scope(): void
+ {
+ $this->actingAs($this->manager);
+ foreach ([['from' => 'bad'], ['from' => '2026-11-03', 'to' => '2026-11-02'], ['to' => '2026-11-04'], ['service_code' => 'invented']] as $bad) {
+ $this->getJson('/management/product-usage?'.http_build_query(['from' => '2026-11-02', 'to' => '2026-11-02', ...$bad]))->assertUnprocessable();
+ }
+ $r = app(ProductUsageMetrics::class)->report($this->manager, []);
+ $this->assertSame('existing_transaction', $r['read_consistency']);
+ $this->assertSame('2026-11-03T12:00:00.123456+00:00', $r['observed_before']);
+ }
+}
diff --git a/tests/Feature/PublicSearchMetricsTest.php b/tests/Feature/PublicSearchMetricsTest.php
new file mode 100644
index 00000000..2140df4d
--- /dev/null
+++ b/tests/Feature/PublicSearchMetricsTest.php
@@ -0,0 +1,275 @@
+withoutVite();
+ $this->travelTo(CarbonImmutable::parse('2026-11-02 12:00:00.123456', 'UTC'));
+ Http::preventStrayRequests();
+ $this->manager = User::factory()->create();
+ config(['portal.managers' => [$this->manager->email], 'investmoz_ai.enabled' => false, 'suitecrm.enabled' => false, 'portal.notifications_enabled' => false, 'search-metrics.enabled' => true, 'search-metrics.capture_lock_timeout_ms' => 1500, 'search-metrics.capture_statement_timeout_ms' => 3000]);
+ }
+
+ protected function tearDown(): void
+ {
+ $this->travelBack();
+ parent::tearDown();
+ }
+
+ private function opportunity(string $description = 'Cultivo de algodão'): Opportunity
+ {
+ $sector = Sector::create(['name' => 'SYNTHETIC sector', 'slug' => 'synthetic-'.Str::uuid(), 'is_active' => true, 'published_at' => now()]);
+
+ return Opportunity::create(['sector_id' => $sector->id, 'reference' => 'SYNTHETIC-'.Str::uuid(), 'slug' => 'synthetic-'.Str::uuid(), 'title' => 'SYNTHETIC opportunity', 'summary' => $description, 'status' => 'published', 'published_at' => now()->subDay()]);
+ }
+
+ private function report(array $filters = []): array
+ {
+ return $this->actingAs($this->manager)->getJson('/management/product-usage?'.http_build_query(['from' => '2026-11-02', 'to' => '2026-11-02', ...$filters]))->assertOk()->assertHeader('Cache-Control', 'no-store, private')->json('report');
+ }
+
+ private function legacyFixture(): void
+ {
+ Storage::fake('local');
+ config(['portal.legacy_content_qa_enabled' => true]);
+ $bytes = json_encode(['format' => 'investmoz-legacy-article-v1', 'source_url' => 'https://investemoz.tempo.co.mz/agronegocio', 'title' => 'SYNTHETIC article', 'content_html' => 'SYNTHETIC content for isolated QA only
', 'author' => 'SYNTHETIC author', 'legacy_id' => 171985, 'legacy_category' => 'SYNTHETIC QA', 'published_at' => '2026-11-02T09:00:00+00:00', 'modified_at' => '2026-11-02T10:00:00+00:00'], JSON_THROW_ON_ERROR);
+ $id = (string) Str::uuid();
+ Storage::disk('local')->put('legacy/'.$id, $bytes);
+ DB::table('documents')->insert(['id' => $id, 'source_system' => 'synthetic-test', 'external_id' => 'legacy-tempo-post-171985-20260420', 'file_name' => 'synthetic.json', 'media_type' => 'application/json', 'storage_key' => 'legacy/'.$id, 'sha256' => hash('sha256', $bytes), 'malware_scanned_sha256' => hash('sha256', $bytes), 'malware_scan_status' => 'clean', 'size_bytes' => strlen($bytes), 'status' => 'active', 'rights_status' => 'authorized', 'data_classification' => 'public']);
+ DB::table('portal_resources')->insert(['document_id' => $id, 'title' => 'SYNTHETIC article', 'category' => 'education', 'topic' => 'agronegocio', 'published' => true, 'rights_status' => 'authorized', 'source_url' => 'https://investemoz.tempo.co.mz/agronegocio', 'source_reference' => 'SYNTHETIC isolated QA fixture; not official.', 'metadata_version' => 1]);
+ }
+
+ public function test_primary_search_totals_are_recorded_without_terms_identifiers_or_changes_to_opportunities(): void
+ {
+ $crop = $this->opportunity();
+ $before = DB::table('opportunities')->orderBy('id')->get()->toJson();
+ $this->getJson('/api/v1/investment/search?q=plantio+de+algodao')->assertOk()->assertJsonPath('total', 1)->assertJsonPath('data.0.id', $crop->id);
+ $this->getJson('/api/v1/opportunities/search?q=PRIVATE-SYNTHETIC-EMAIL%40example.invalid&total=999')->assertOk()->assertJsonPath('total', 0);
+ $this->get('/oportunidades?q=plantio+de+algodao')->assertOk();
+ $api = DB::table('product_search_counts')->where('channel', 'opportunities_api')->first();
+ $this->assertSame(2, $api->responses);
+ $this->assertSame(1, $api->zero_responses);
+ $this->assertSame(1, DB::table('product_search_counts')->where('channel', 'opportunities_page')->value('responses'));
+ $this->assertSame(1, DB::table('product_search_definitions')->count());
+ $this->assertStringNotContainsString('PRIVATE-SYNTHETIC', DB::table('product_search_counts')->get()->toJson().DB::table('product_search_definitions')->get()->toJson());
+ $this->assertEqualsCanonicalizing(['day', 'channel', 'definition_version', 'responses', 'zero_responses', 'first_recorded_at', 'last_recorded_at'], Schema::getColumnListing('product_search_counts'));
+ $this->assertSame($before, DB::table('opportunities')->orderBy('id')->get()->toJson());
+ $this->assertDatabaseCount('interest_requests', 0);
+ }
+
+ public function test_each_instrumented_public_catalogue_records_its_own_actual_primary_total(): void
+ {
+ $this->legacyFixture();
+ foreach (['/oportunidades', '/api/v1/investment/search', '/educacao', '/negocios', '/documentos', '/parcerias', '/carteira', '/zonas', '/explorar/agronegocio'] as $url) {
+ $this->assertSame(200, $this->get($url.'?q=SYNTHETIC')->status(), 'Expected available synthetic public catalogue: '.$url);
+ }
+ $this->assertDatabaseCount('product_search_counts', 9);
+ $this->assertEqualsCanonicalizing(array_keys(config('search-metrics.channels')), DB::table('product_search_counts')->pluck('channel')->all());
+ foreach (['documents', 'sector_content'] as $channel) {
+ $this->assertSame(0, DB::table('product_search_counts')->where('channel', $channel)->value('zero_responses'));
+ }
+ $this->assertSame(9, (int) DB::table('product_search_counts')->sum('responses'));
+ $this->assertSame(7, (int) DB::table('product_search_counts')->sum('zero_responses'));
+ }
+
+ public function test_browsing_pagination_prefetch_privacy_signals_auxiliary_routes_and_failed_responses_are_excluded(): void
+ {
+ $this->get('/oportunidades')->assertOk();
+ $this->get('/oportunidades?sort=title&view=list')->assertOk();
+ $this->get('/oportunidades?q=SYNTHETIC&page=2')->assertOk();
+ foreach (['suggest', 'references', 'map', 'export'] as $action) {
+ $this->get('/api/v1/investment/'.$action.'?q=SYNTHETIC')->assertOk();
+ }
+ $this->call('HEAD', '/oportunidades?q=SYNTHETIC')->assertOk();
+ foreach ([['Purpose' => 'prefetch'], ['Sec-Purpose' => 'prefetch;prerender'], ['X-Inertia-Prefetch' => 'true'], ['DNT' => '1'], ['Sec-GPC' => '1']] as $headers) {
+ $this->withHeaders(['Purpose' => '', 'Sec-Purpose' => '', 'X-Inertia-Prefetch' => '', 'DNT' => '0', 'Sec-GPC' => '0', ...$headers])->get('/oportunidades?q=SYNTHETIC')->assertOk();
+ }
+ $this->withHeaders(['Purpose' => '', 'Sec-Purpose' => '', 'X-Inertia-Prefetch' => '', 'DNT' => '0', 'Sec-GPC' => '0'])->getJson('/api/v1/investment/search?'.http_build_query(['q' => str_repeat('x', 121)]))->assertUnprocessable();
+ $this->assertDatabaseCount('product_search_counts', 0);
+ $this->assertDatabaseCount('product_search_definitions', 0);
+ }
+
+ public function test_related_suggestions_do_not_turn_an_empty_primary_search_into_a_positive_result(): void
+ {
+ $this->opportunity('Descaroçamento e transformação de algodão');
+ $this->get('/oportunidades?q=plantio+de+algodao')->assertOk()->assertInertia(fn ($p) => $p->where('results.total', 0)->has('relatedSearch.items', 1));
+ $this->assertSame(1, DB::table('product_search_counts')->value('zero_responses'));
+ $this->assertSame(1, DB::table('product_search_counts')->value('responses'));
+ }
+
+ public function test_reports_distinguish_no_measurement_zero_results_and_unrelated_service_filters(): void
+ {
+ $r = $this->report();
+ $this->assertNull($r['search']['responses']);
+ $this->assertNull($r['search']['zero_rate']);
+ $this->opportunity();
+ $this->getJson('/api/v1/investment/search?q=algodao')->assertOk();
+ $r = $this->report();
+ $this->assertSame(1, $r['search']['responses']);
+ $this->assertSame(0, $r['search']['zero_responses']);
+ $this->assertEquals(0, $r['search']['zero_rate']);
+ $this->assertFalse($r['search']['definition_conflict_now']);
+ $this->assertSame('daily_aggregate_at_report_snapshot', $r['search']['temporal_basis']);
+ $this->assertSame('partial', collect($r['metrics'])->firstWhere('id', 'recorded_zero_search_rate')['state']);
+ $this->assertNull(collect($r['search']['channels'])->firstWhere('id', 'documents')['responses']);
+ DB::table('desk_service_versions')->insert(['id' => (string) Str::uuid(), 'code' => 'synthetic-service', 'version' => 1, 'definition' => '{"title":"SYNTHETIC service"}', 'source' => '{}', 'author_id' => $this->manager->id]);
+ $filtered = $this->report(['service_code' => 'synthetic-service']);
+ $this->assertFalse($filtered['search']['applicable']);
+ $this->assertNull($filtered['search']['responses']);
+ $this->getJson('/management/product-usage?search_definition=invented')->assertUnprocessable();
+ }
+
+ public function test_missing_collection_schema_preserves_search_and_never_claims_zero_measurement(): void
+ {
+ Schema::rename('product_search_counts', 'product_search_counts_qa_unavailable');
+ try {
+ $this->get('/oportunidades?q=SYNTHETIC')->assertOk();
+ $r = $this->report();
+ $this->assertFalse($r['search']['installed']);
+ $this->assertNull($r['search']['responses']);
+ $this->assertSame(0, DB::table('product_search_counts_qa_unavailable')->count());
+ } finally {
+ Schema::rename('product_search_counts_qa_unavailable', 'product_search_counts');
+ }
+ }
+
+ public function test_collection_and_diagnostic_failures_cannot_poison_a_search_or_its_outer_transaction(): void
+ {
+ $logged = [];
+ Log::shouldReceive('warning')->twice()->andReturnUsing(function ($message, $context) use (&$logged) {
+ $logged[] = [$message, $context];
+ if (count($logged) === 2) {
+ throw new \RuntimeException('SYNTHETIC unavailable log');
+ }
+ });
+ DB::statement('ALTER TABLE product_search_counts ADD CONSTRAINT synthetic_capture_failure CHECK(responses<0) NOT VALID');
+ try {
+ for ($n = 0; $n < 2; $n++) {
+ $this->getJson('/api/v1/investment/search?q=PRIVATE-SYNTHETIC-TERM')->assertOk()->assertJsonPath('total', 0);
+ }
+ $this->assertSame(0, DB::table('opportunities')->count());
+ $this->assertDatabaseCount('product_search_counts', 0);
+ $this->assertDatabaseCount('product_search_definitions', 0);
+ $this->assertCount(2, $logged);
+ $this->assertSame(['channel', 'definition_version', 'exception_class'], array_keys($logged[0][1]));
+ $this->assertStringNotContainsString('PRIVATE-SYNTHETIC', json_encode($logged));
+ } finally {
+ DB::statement('ALTER TABLE product_search_counts DROP CONSTRAINT synthetic_capture_failure');
+ }
+ }
+
+ public function test_editions_are_not_summed_and_registered_definitions_remain_immutable_and_readable(): void
+ {
+ $collector = app(PublicSearchMetrics::class);
+ $v1 = config('search-metrics.version');
+ $oldLabel = config('search-metrics.channels.opportunities_api');
+ $collector->record('opportunities_api', false);
+ config(['search-metrics.version' => 'SYNTHETIC-v2', 'search-metrics.channels.opportunities_api' => 'SYNTHETIC second edition']);
+ $collector->record('opportunities_api', true);
+ $current = $this->report();
+ $this->assertSame(1, $current['search']['responses']);
+ $this->assertEquals(100, $current['search']['zero_rate']);
+ $old = $this->report(['search_definition' => $v1]);
+ $this->assertSame(1, $old['search']['responses']);
+ $this->assertEquals(0, $old['search']['zero_rate']);
+ $this->assertSame($oldLabel, collect($old['search']['channels'])->firstWhere('id', 'opportunities_api')['label']);
+ Log::spy();
+ config(['search-metrics.channels.opportunities_api' => 'SYNTHETIC conflicting unversioned change']);
+ $collector->record('opportunities_api', false);
+ $this->assertSame(1, $this->report()['search']['responses']);
+ $this->assertTrue($this->report()['search']['definition_conflict_now']);
+ Log::shouldHaveReceived('warning')->once();
+ try {
+ DB::transaction(fn () => DB::table('product_search_definitions')->where('version', $v1)->update(['sha256' => str_repeat('0', 64)]));
+ $this->fail('Definitions cannot be rewritten.');
+ } catch (QueryException $error) {
+ $this->assertSame('23514', $error->getCode());
+ }
+ }
+
+ public function test_daily_boundaries_and_disabled_collection_preserve_the_existing_history(): void
+ {
+ $collector = app(PublicSearchMetrics::class);
+ $this->travelTo(CarbonImmutable::parse('2026-11-01 23:59:59.999999', 'UTC'));
+ $collector->record('opportunities_api', false);
+ $this->travelTo(CarbonImmutable::parse('2026-11-02 00:00:00.000001', 'UTC'));
+ $collector->record('opportunities_api', true);
+ $this->travelTo(CarbonImmutable::parse('2026-11-03 00:00:00.000001', 'UTC'));
+ $collector->record('opportunities_api', false);
+ config(['search-metrics.enabled' => false]);
+ $this->get('/oportunidades?q=SYNTHETIC')->assertOk();
+ $r = $this->report();
+ $this->assertFalse($r['search']['enabled_now']);
+ $this->assertSame(1, $r['search']['responses']);
+ $this->assertSame(1, $r['search']['zero_responses']);
+ $this->assertDatabaseCount('product_search_counts', 3);
+ }
+
+ public function test_collector_respects_and_restores_the_callers_stricter_query_budgets(): void
+ {
+ config(['search-metrics.capture_lock_timeout_ms' => 1000, 'search-metrics.capture_statement_timeout_ms' => 2000]);
+ DB::statement("SET LOCAL lock_timeout='500ms'");
+ DB::statement("SET LOCAL statement_timeout='1000ms'");
+ $during = [];
+ DB::listen(function ($event) use (&$during) {
+ if (str_contains($event->sql, 'INSERT INTO product_search_counts')) {
+ $pdo = DB::connection()->getPdo();
+ $during[] = [$pdo->query('SHOW lock_timeout')->fetchColumn(), $pdo->query('SHOW statement_timeout')->fetchColumn()];
+ }
+ });
+ app(PublicSearchMetrics::class)->record('opportunities_api', false);
+ $this->assertSame([['500ms', '1s']], $during);
+ $this->assertSame('500ms', DB::selectOne('SHOW lock_timeout')->lock_timeout);
+ $this->assertSame('1s', DB::selectOne('SHOW statement_timeout')->statement_timeout);
+ $this->assertDatabaseCount('product_search_counts', 1);
+ }
+
+ public function test_a_real_competing_database_lock_does_not_hold_the_collector_indefinitely(): void
+ {
+ $this->assertTrue(IsolatedQaDatabase::allowsSchemaChanges());
+ $c = config('database.connections.pgsql');
+ $other = new PDO('pgsql:host='.$c['host'].';port='.$c['port'].';dbname='.$c['database'], $c['username'], $c['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
+ $other->beginTransaction();
+ $other->exec("SET LOCAL lock_timeout='1000ms'");
+ $other->exec('LOCK TABLE product_search_counts IN ACCESS EXCLUSIVE MODE');
+ config(['search-metrics.capture_lock_timeout_ms' => 50, 'search-metrics.capture_statement_timeout_ms' => 500]);
+ Log::spy();
+ $before = microtime(true);
+ try {
+ app(PublicSearchMetrics::class)->record('opportunities_api', true);
+ } finally {
+ $other->rollBack();
+ }
+ $this->assertLessThan(5, microtime(true) - $before);
+ $this->assertDatabaseCount('product_search_counts', 0);
+ $this->assertDatabaseCount('product_search_definitions', 0);
+ Log::shouldHaveReceived('warning')->once();
+ app(PublicSearchMetrics::class)->record('opportunities_api', true);
+ $this->assertSame(1, DB::table('product_search_counts')->value('responses'));
+ }
+}
diff --git a/tests/Feature/ResourceTechnicalIncidentsTest.php b/tests/Feature/ResourceTechnicalIncidentsTest.php
new file mode 100644
index 00000000..188f1372
--- /dev/null
+++ b/tests/Feature/ResourceTechnicalIncidentsTest.php
@@ -0,0 +1,247 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ Storage::fake('local');
+ config(['portal.profile_access_enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->actor = User::factory()->create();
+ $this->support = User::factory()->create();
+ $approver = User::factory()->create();
+ $organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $organization, 'name' => 'SYNTHETIC upload QA organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'user_id' => $this->actor->id, 'organization_id' => $organization, 'role' => 'officer']);
+ foreach ([[$this->actor, 'promoter'], [$this->support, 'technical_support']] as [$user,$role]) {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $approver, ['user_id' => $user->id, 'role' => $role, 'organization_id' => $organization, 'opportunity_types' => ['investment_project'], 'source' => 'synthetic-resource-incident-fixture']);
+ }
+ $id = (string) Str::uuid();
+ $this->opportunity = new Opportunity(['reference' => $id, 'slug' => $id, 'title' => 'PRIVATE SYNTHETIC upload investment', 'status' => 'draft']);
+ $this->opportunity->forceFill(['owner_user_id' => $this->actor->id, 'organization_id' => $organization, 'opportunity_category' => 'investment_project', 'management_version' => 4, 'workflow_context' => ['working_state' => 'draft']])->save();
+ $this->actingAs($this->actor);
+ }
+
+ private function url(string $kind = 'documents'): string
+ {
+ return '/minhas-oportunidades/'.$this->opportunity->id.'/resources/'.$kind;
+ }
+
+ private function input(): array
+ {
+ return ['etag' => app(OpportunityManagement::class)->etag($this->opportunity->fresh()), 'creation_key' => (string) Str::uuid(), 'reason' => 'PRIVATE SYNTHETIC upload reason', 'payload' => ['title' => 'PRIVATE SYNTHETIC original', 'classification' => 'confidential'], 'file' => UploadedFile::fake()->createWithContent('PRIVATE-synthetic.pdf', "%PDF-1.7\nSYNTHETIC private bytes\n%%EOF")];
+ }
+
+ private function incidentCount(): int
+ {
+ return DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->count();
+ }
+
+ public function test_database_failure_rolls_back_upload_preserves_prior_originals_and_routes_private_metadata_to_support(): void
+ {
+ $before = $this->opportunity->fresh()->getRawOriginal();
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_upload_failure CHECK (source_system <> 'opportunity-resources')");
+ $response = $this->post($this->url(), $this->input(), ['Accept' => 'application/json'])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ $reference = $response->json('reference');
+ $this->assertTrue(Str::isUuid($reference));
+ $this->assertStringNotContainsString('SQLSTATE', $response->getContent());
+ $this->assertStringNotContainsString('PRIVATE-synthetic', $response->getContent());
+ $this->assertSame($before, $this->opportunity->fresh()->getRawOriginal());
+ $this->assertSame(0, DB::table('documents')->count());
+ $this->assertSame(0, DB::table('opportunity_documents')->count());
+ $this->assertSame([], Storage::disk('local')->allFiles());
+ $data = json_decode(DB::table('audit_events')->where('id', $reference)->value('after_data'), true)['incident'];
+ $this->assertSame('upload_document', $data['operation']);
+ $this->assertSame(4, $data['observed_version']);
+ $this->assertSame('database_failure', $data['error_code']);
+ $this->assertStringNotContainsString('PRIVATE', json_encode($data));
+ $this->get('/minhas-oportunidades/'.$this->opportunity->id.'/resources')->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $page) => $page->where('technicalIncidents.0.reference', $reference)->where('technicalIncidents.0.operation', 'upload_document'));
+ $this->actingAs($this->support)->get('/suporte-tecnico/incidentes?unread=1')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.operation', 'upload_document'));
+ $this->get('/minhas-oportunidades/'.$this->opportunity->id.'/resources')->assertForbidden();
+ DB::statement('ALTER TABLE audit_events DROP CONSTRAINT qa_upload_failure');
+ $this->actingAs($this->actor)->post($this->url(), $this->input(), ['Accept' => 'application/json'])->assertCreated();
+ $this->assertSame(1, $this->incidentCount());
+ }
+
+ public function test_expected_validation_scope_version_and_quarantine_errors_do_not_create_incidents(): void
+ {
+ $bad = $this->input();
+ $bad['file'] = UploadedFile::fake()->createWithContent('bad.pdf', 'not a pdf')->mimeType('text/plain');
+ $this->post($this->url(), $bad, ['Accept' => 'application/json'])->assertUnprocessable();
+ $stale = $this->input();
+ $stale['etag'] = str_repeat('0', 64);
+ $this->post($this->url(), $stale, ['Accept' => 'application/json'])->assertConflict();
+ $this->actingAs($this->support)->post($this->url(), $this->input(), ['Accept' => 'application/json'])->assertForbidden();
+ $this->actingAs($this->actor)->postJson($this->url('images').'/'.Str::uuid().'/prepare', ['etag' => app(OpportunityManagement::class)->etag($this->opportunity), 'version' => 1, 'reason' => 'SYNTHETIC missing image request'])->assertStatus(function_exists('imagecreatefromstring') ? 404 : 423);
+ $this->assertSame(0, $this->incidentCount());
+ $this->assertSame([], Storage::disk('local')->allFiles());
+ }
+
+ public function test_partial_storage_failure_is_reported_and_cleanup_failure_does_not_hide_the_original_result(): void
+ {
+ $disk = Storage::disk('local');
+ $fault = Mockery::mock($disk);
+ $fault->shouldReceive('putFileAs')->andReturnUsing(function ($path, $file, $name) use ($disk) {
+ $disk->put($path.'/'.$name, 'SYNTHETIC partial bytes');
+
+ return false;
+ });
+ $fault->shouldReceive('delete')->andThrow(new \RuntimeException('PRIVATE cleanup failure'));
+ Storage::shouldReceive('disk')->with('local')->andReturn($fault);
+ $response = $this->post($this->url(), $this->input(), ['Accept' => 'application/json'])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ $this->assertStringNotContainsString('PRIVATE', $response->getContent());
+ $this->assertCount(1, $disk->allFiles());
+ $this->assertSame(0, DB::table('documents')->count());
+ $this->assertSame(1, $this->incidentCount());
+ }
+
+ public function test_cleanup_preserves_referenced_originals_uncertain_commit_bytes_and_failed_reference_checks(): void
+ {
+ $cleanup = app(OpportunityResourceFileCleanup::class);
+ $disk = Storage::disk('local');
+ $key = 'opportunity-resources/'.Str::uuid();
+ $disk->put($key, Crypt::encryptString('SYNTHETIC preserved original'));
+ $hash = hash('sha256', $disk->get($key));
+ DB::table('documents')->insert(['id' => (string) Str::uuid(), 'source_system' => 'opportunity-resources', 'file_name' => 'synthetic.pdf', 'media_type' => 'application/pdf', 'storage_key' => $key, 'sha256' => str_repeat('a', 64), 'status' => 'quarantined', 'storage_encryption' => 'laravel', 'data_classification' => 'restricted', 'size_bytes' => 1, 'uploaded_by' => $this->actor->id]);
+ $cleanup->afterFailure([$key], new \RuntimeException('SYNTHETIC failure after committed document'));
+ $this->assertSame($hash, hash('sha256', $disk->get($key)));
+ $unknown = 'opportunity-resources/'.Str::uuid();
+ $disk->put($unknown, 'SYNTHETIC uncertain bytes');
+ $cleanup->afterFailure([$unknown], new \PDOException('server closed the connection unexpectedly'));
+ $this->assertTrue($disk->exists($unknown));
+ DB::statement('ALTER TABLE documents RENAME COLUMN storage_key TO qa_unavailable_storage_key');
+ $cleanup->afterFailure([$unknown], new \RuntimeException('SYNTHETIC failed reference lookup'));
+ $this->assertTrue($disk->exists($unknown));
+ $this->assertGreaterThan(0, DB::table('users')->count());
+ DB::statement('ALTER TABLE documents RENAME COLUMN qa_unavailable_storage_key TO storage_key');
+ $cleanup->afterFailure([$unknown], new \RuntimeException('SYNTHETIC confirmed rollback'));
+ $this->assertFalse($disk->exists($unknown));
+ }
+
+ public function test_failed_incident_persistence_is_reported_honestly_and_does_not_leak_the_upload(): void
+ {
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_no_resource_audit CHECK (source_system NOT IN ('opportunity-resources','portal-opportunity-incident'))");
+ $response = $this->post($this->url(), $this->input(), ['Accept' => 'application/json'])->assertStatus(503)->assertJsonPath('incident_recorded', false);
+ $this->assertTrue(Str::isUuid($response->json('reference')));
+ $this->assertSame(0, $this->incidentCount());
+ $this->assertSame([], Storage::disk('local')->allFiles());
+ $this->assertStringNotContainsString('PRIVATE', $response->getContent());
+ }
+
+ public function test_filtered_rls_visibility_never_authorizes_removal_of_a_referenced_original(): void
+ {
+ $key = 'opportunity-resources/'.Str::uuid();
+ $disk = Storage::disk('local');
+ $disk->put($key, 'SYNTHETIC original behind RLS');
+ DB::table('documents')->insert(['id' => (string) Str::uuid(), 'source_system' => 'opportunity-resources', 'file_name' => 'synthetic-rls.pdf', 'media_type' => 'application/pdf', 'storage_key' => $key, 'sha256' => hash('sha256', 'SYNTHETIC original behind RLS'), 'status' => 'quarantined', 'size_bytes' => 1, 'uploaded_by' => $this->actor->id]);
+ DB::statement('ALTER TABLE documents ENABLE ROW LEVEL SECURITY');
+ DB::statement('ALTER TABLE documents FORCE ROW LEVEL SECURITY');
+ DB::statement('SET LOCAL ROLE pg_read_all_data');
+ try {
+ $this->assertTrue(DB::selectOne("SELECT row_security_active('documents'::regclass) AS active")->active);
+ $this->assertSame(0, DB::table('documents')->where('storage_key', $key)->count());
+ app(OpportunityResourceFileCleanup::class)->afterFailure([$key], new \RuntimeException('SYNTHETIC failure with filtered reference visibility'));
+ $this->assertTrue($disk->exists($key));
+ } finally {
+ DB::statement('RESET ROLE');
+ }
+ $this->assertSame(1, DB::table('documents')->where('storage_key', $key)->count());
+ $this->assertSame('investmoz_test', DB::selectOne('SELECT current_user AS role')->role);
+ }
+
+ private function png(): string
+ {
+ $chunk = fn ($name, $bytes) => pack('N', strlen($bytes)).$name.$bytes.pack('N', crc32($name.$bytes));
+
+ return "\x89PNG\r\n\x1a\n".$chunk('IHDR', pack('NNCCCCC', 500, 500, 8, 2, 0, 0, 0)).$chunk('IDAT', gzcompress(str_repeat("\0", 500 * 1501))).$chunk('IEND', '');
+ }
+
+ public function test_image_upload_and_preparation_failures_have_distinct_labels_and_no_automatic_retry(): void
+ {
+ $input = $this->input();
+ $input['payload'] = ['title' => 'SYNTHETIC image', 'alt_text' => 'SYNTHETIC plain image', 'caption' => 'SYNTHETIC image caption', 'rights_status' => 'owned'];
+ $input['file'] = UploadedFile::fake()->createWithContent('synthetic.png', $this->png());
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_image_upload_failure CHECK (source_system <> 'opportunity-resources')");
+ $this->post($this->url('images'), $input, ['Accept' => 'application/json'])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ DB::statement('ALTER TABLE audit_events DROP CONSTRAINT qa_image_upload_failure');
+ $this->assertSame('upload_image', app(OpportunityTechnicalIncidents::class)->recent($this->actor, $this->opportunity)[0]['operation']);
+ $processor = Mockery::mock(OpportunityImageProcessor::class);
+ $processor->shouldReceive('prepare')->once()->andThrow(new \RuntimeException('PRIVATE SYNTHETIC processor failure'));
+ $this->app->instance(OpportunityImageProcessor::class, $processor);
+ $this->postJson($this->url('images').'/'.Str::uuid().'/prepare', ['etag' => app(OpportunityManagement::class)->etag($this->opportunity), 'version' => 1, 'reason' => 'SYNTHETIC explicit image processing'])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ $operations = array_column(app(OpportunityTechnicalIncidents::class)->recent($this->actor, $this->opportunity), 'operation');
+ $this->assertContains('prepare_image', $operations);
+ $this->assertContains('upload_image', $operations);
+ $this->assertSame(2, $this->incidentCount());
+ }
+
+ public function test_derivative_partial_storage_failure_preserves_original_and_cleans_new_unreferenced_bytes(): void
+ {
+ if (! app(OpportunityImageProcessor::class)->available()) {
+ $this->postJson($this->url('images').'/'.Str::uuid().'/prepare', ['etag' => app(OpportunityManagement::class)->etag($this->opportunity), 'version' => 1, 'reason' => 'SYNTHETIC unavailable processing'])->assertStatus(423);
+ $this->assertSame(0, $this->incidentCount());
+
+ return;
+ }
+ $input = $this->input();
+ $input['payload'] = ['title' => 'SYNTHETIC image', 'alt_text' => 'SYNTHETIC plain image', 'caption' => 'SYNTHETIC image caption', 'rights_status' => 'owned'];
+ $input['file'] = UploadedFile::fake()->createWithContent('synthetic.png', $this->png());
+ $id = $this->post($this->url('images'), $input, ['Accept' => 'application/json'])->assertCreated()->json('id');
+ $image = DB::table('opportunity_images')->where('id', $id)->first();
+ (new ScanDocumentForMalware($image->document_id))->handle(new CleanScannerFixture);
+ $original = DB::table('documents')->where('id', $image->document_id)->first();
+ $disk = Storage::disk('local');
+ $before = $disk->get($original->storage_key);
+ $opportunityBefore = $this->opportunity->fresh()->getRawOriginal();
+ $fault = Mockery::mock($disk);
+ $fault->shouldReceive('put')->andReturnUsing(function ($key, $bytes) use ($disk) {
+ $disk->put($key, $bytes);
+
+ return false;
+ });
+ Storage::shouldReceive('disk')->with('local')->andReturn($fault);
+ $this->postJson($this->url('images').'/'.$id.'/prepare', ['etag' => app(OpportunityManagement::class)->etag($this->opportunity->fresh()), 'version' => 1, 'reason' => 'SYNTHETIC derivative storage failure'])->assertStatus(503)->assertJsonPath('incident_recorded', true);
+ $this->assertSame([$original->storage_key], $disk->allFiles());
+ $this->assertSame($before, $disk->get($original->storage_key));
+ $this->assertEquals($image, DB::table('opportunity_images')->where('id', $id)->first());
+ $this->assertSame($opportunityBefore, $this->opportunity->fresh()->getRawOriginal());
+ $this->assertSame(1, DB::table('documents')->count());
+ $this->assertSame('prepare_image', app(OpportunityTechnicalIncidents::class)->recent($this->actor, $this->opportunity)[0]['operation']);
+ }
+}
diff --git a/tests/Feature/ScanTechnicalIncidentsTest.php b/tests/Feature/ScanTechnicalIncidentsTest.php
new file mode 100644
index 00000000..10ac9c80
--- /dev/null
+++ b/tests/Feature/ScanTechnicalIncidentsTest.php
@@ -0,0 +1,422 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ Queue::fake();
+ Storage::fake('local');
+ config(['portal.profile_access_enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->actor = User::factory()->create();
+ $this->support = User::factory()->create();
+ $approver = User::factory()->create();
+ $organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $organization, 'name' => 'SYNTHETIC upload QA organization', 'organization_type' => 'private']);
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'user_id' => $this->actor->id, 'organization_id' => $organization, 'role' => 'officer']);
+ foreach ([[$this->actor, 'promoter'], [$this->support, 'technical_support']] as [$user,$role]) {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $approver, ['user_id' => $user->id, 'role' => $role, 'organization_id' => $organization, 'opportunity_types' => ['investment_project'], 'source' => 'synthetic-resource-incident-fixture']);
+ }
+ $id = (string) Str::uuid();
+ $this->opportunity = new Opportunity(['reference' => $id, 'slug' => $id, 'title' => 'PRIVATE SYNTHETIC upload investment', 'status' => 'draft']);
+ $this->opportunity->forceFill(['owner_user_id' => $this->actor->id, 'organization_id' => $organization, 'opportunity_category' => 'investment_project', 'management_version' => 4, 'workflow_context' => ['working_state' => 'draft']])->save();
+ $this->actingAs($this->actor);
+ }
+
+ private function upload(): array
+ {
+ $input = ['etag' => app(OpportunityManagement::class)->etag($this->opportunity->fresh()), 'creation_key' => (string) Str::uuid(), 'reason' => 'PRIVATE SYNTHETIC scan upload reason', 'payload' => ['title' => 'PRIVATE SYNTHETIC scan original', 'classification' => 'confidential'], 'file' => UploadedFile::fake()->createWithContent('PRIVATE-synthetic.pdf', "%PDF-1.7\nSYNTHETIC scan bytes\n%%EOF")];
+ $id = $this->post('/minhas-oportunidades/'.$this->opportunity->id.'/resources/documents', $input, ['Accept' => 'application/json'])->assertCreated()->json('id');
+ $resource = DB::table('opportunity_documents')->where('id', $id)->first();
+
+ return [$resource, DB::table('documents')->where('id', $resource->document_id)->first()];
+ }
+
+ private function queued(): ScanDocumentForMalware
+ {
+ $captured = null;
+ Queue::assertPushed(ScanDocumentForMalware::class, function ($job) use (&$captured) {
+ $captured = $job;
+
+ return true;
+ });
+ $this->assertInstanceOf(ScanDocumentForMalware::class, $captured);
+
+ return $captured;
+ }
+
+ private function scannerResult(string $state = 'clean'): array
+ {
+ return ['result' => $state, 'reason_code' => match ($state) {
+ 'clean' => null, 'infected' => 'threat_detected', default => 'scanner_unavailable'
+ }, 'engine' => 'QA-Test-Double', 'engine_version' => 'fixture', 'signatures_at' => null, 'duration_ms' => 1, 'detail' => 'PRIVATE SYNTHETIC engine detail'];
+ }
+
+ private function scanner(\Closure $callback): MalwareScanner
+ {
+ return new class($callback) implements MalwareScanner
+ {
+ public function __construct(private \Closure $callback) {}
+
+ public function scan(string $path, int $fileSizeBytes, string $storageRoot): array
+ {
+ return ($this->callback)($path, $fileSizeBytes, $storageRoot);
+ }
+
+ public function health(): array
+ {
+ return ['available' => true, 'engine' => 'QA-Test-Double', 'engine_version' => 'fixture', 'signatures_at' => null, 'signature_age_hours' => null, 'reason_code' => null];
+ }
+ };
+ }
+
+ private function roots(): int
+ {
+ return DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->count();
+ }
+
+ private function freshJob(ScanDocumentForMalware $job): ScanDocumentForMalware
+ {
+ return unserialize(serialize($job), ['allowed_classes' => [ScanDocumentForMalware::class]]);
+ }
+
+ private function delivery(int $attempt, string $uuid): QueueJob
+ {
+ $job = Mockery::mock(QueueJob::class);
+ $job->shouldReceive('attempts')->andReturn($attempt);
+ $job->shouldReceive('uuid')->andReturn($uuid);
+
+ return $job;
+ }
+
+ public function test_dispatch_failure_keeps_the_saved_resource_and_notifies_without_impersonating_the_initiator(): void
+ {
+ Bus::shouldReceive('dispatch')->once()->with(Mockery::type(ScanDocumentForMalware::class))->andThrow(new \RuntimeException('PRIVATE queue credentials and body'));
+ [$resource,$document] = $this->upload();
+ $this->assertSame(1, DB::table('documents')->count());
+ $this->assertSame(5, $this->opportunity->fresh()->management_version);
+ $this->assertSame('failed', $document->malware_scan_status);
+ $this->assertSame('quarantined', $document->status);
+ $this->assertStringContainsString('SYNTHETIC scan bytes', Crypt::decryptString(Storage::disk('local')->get($document->storage_key)));
+ $event = DB::table('audit_events')->where('source_system', 'portal-opportunity-incident')->first();
+ $data = json_decode($event->after_data, true)['incident'];
+ $this->assertNull($event->actor_user_id);
+ $this->assertSame($this->actor->id, $data['reported_for_user_id']);
+ $this->assertSame('scan_dispatch_unconfirmed', $data['error_code']);
+ $this->assertSame('scan_document', $data['operation']);
+ $this->assertSame(5, $data['observed_version']);
+ $this->assertStringNotContainsString('PRIVATE', $event->after_data);
+ $this->assertSame('scan_document', app(OpportunityTechnicalIncidents::class)->recent($this->actor, $this->opportunity->fresh())[0]['operation']);
+ $this->actingAs($this->support)->get('/suporte-tecnico/incidentes?unread=1')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.error_code', 'scan_dispatch_unconfirmed'));
+ $this->get('/minhas-oportunidades/'.$this->opportunity->id.'/resources')->assertForbidden();
+ }
+
+ public function test_an_uncertain_dispatch_after_a_sync_result_never_quarantines_an_already_clean_document(): void
+ {
+ Bus::shouldReceive('dispatch')->once()->with(Mockery::type(ScanDocumentForMalware::class))->andReturnUsing(function ($job) {
+ $job->handle(new CleanScannerFixture);
+ throw new \RuntimeException('PRIVATE dispatch acknowledgement lost');
+ });
+ [$resource,$document] = $this->upload();
+ $this->assertSame('clean', $document->malware_scan_status);
+ $this->assertSame('active', $document->status);
+ $this->assertSame(trim($document->sha256), $document->malware_scanned_sha256);
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertSame(1, $this->roots());
+ $this->assertSame(5, $this->opportunity->fresh()->management_version);
+ }
+
+ public function test_dispatch_is_deferred_until_commit_and_a_rollback_never_enqueues_the_resource(): void
+ {
+ DB::beginTransaction();
+ $this->upload();
+ Queue::assertNothingPushed();
+ DB::rollBack();
+ $this->assertSame(0, DB::table('documents')->count());
+ $this->assertSame(0, $this->roots());
+ DB::beginTransaction();
+ $this->upload();
+ Queue::assertNothingPushed();
+ DB::commit();
+ $job = $this->queued();
+ $this->assertSame($this->actor->id, $job->opportunityContext['reported_for_user_id']);
+ $this->assertSame(5, $job->opportunityContext['observed_version']);
+ $this->assertSame(0, $this->roots());
+ }
+
+ public function test_inconclusive_scan_is_quarantined_has_one_system_incident_and_replay_does_not_rescan(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $before = Storage::disk('local')->get($document->storage_key);
+ $business = $this->opportunity->fresh()->getRawOriginal();
+ $calls = 0;
+ $scanner = $this->scanner(function () use (&$calls) {
+ $calls++;
+
+ return $this->scannerResult('inconclusive');
+ });
+ $job->handle($scanner);
+ $this->freshJob($job)->handle($scanner);
+ $job->failed(new \RuntimeException('PRIVATE late failure'));
+ $current = DB::table('documents')->where('id', $document->id)->first();
+ $this->assertSame(1, $calls);
+ $this->assertSame('inconclusive', $current->malware_scan_status);
+ $this->assertSame('quarantined', $current->status);
+ $this->assertSame(1, $current->malware_scan_attempts);
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertSame(1, $this->roots());
+ $this->assertSame($before, Storage::disk('local')->get($document->storage_key));
+ $this->assertSame([$document->storage_key], Storage::disk('local')->allFiles());
+ $this->assertSame($business, $this->opportunity->fresh()->getRawOriginal());
+ $root = DB::table('audit_events')->where('id', $job->runIdentifier())->first();
+ $data = json_decode($root->after_data, true)['incident'];
+ $this->assertNull($root->actor_user_id);
+ $this->assertSame('scan_inconclusive', $data['error_code']);
+ $this->assertStringNotContainsString('PRIVATE', $root->after_data);
+ app(OpportunityTechnicalIncidents::class)->recordScan($job->opportunityContext, $job->runIdentifier(), 'scan_worker_failed');
+ $this->assertEquals($root, DB::table('audit_events')->where('id', $job->runIdentifier())->first());
+ $this->get('/minhas-oportunidades/'.$this->opportunity->id.'/resources/documents/'.$resource->id.'/download')->assertStatus(423);
+ }
+
+ public function test_a_late_inconclusive_result_cannot_replace_a_newer_clean_scan(): void
+ {
+ [$resource,$document] = $this->upload();
+ $old = $this->queued();
+ $new = new ScanDocumentForMalware($document->id, $old->opportunityContext);
+ $old->handle($this->scanner(function () use ($new) {
+ $new->handle(new CleanScannerFixture);
+
+ return $this->scannerResult('inconclusive');
+ }));
+ $current = DB::table('documents')->where('id', $document->id)->first();
+ $this->assertSame('clean', $current->malware_scan_status);
+ $this->assertSame('active', $current->status);
+ $this->assertSame(2, $current->malware_scan_attempts);
+ $this->assertSame(trim($current->sha256), $current->malware_scanned_sha256);
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertSame(0, $this->roots());
+ $this->assertSame(1, DB::table('audit_events')->where('action', 'scan_result_discarded')->where('correlation_id', $old->runIdentifier())->count());
+ $this->freshJob($old)->failed(new \RuntimeException('PRIVATE old failure'));
+ $this->assertEquals($current, DB::table('documents')->where('id', $document->id)->first());
+ }
+
+ public function test_same_queue_execution_different_deliveries_cannot_apply_an_old_failure_to_the_current_attempt(): void
+ {
+ [$resource,$document] = $this->upload();
+ $old = $this->queued();
+ $fresh = $this->freshJob($old);
+ $retry = $this->freshJob($old);
+ $uuid = (string) Str::uuid();
+ $old->setJob($this->delivery(1, $uuid));
+ $fresh->setJob($this->delivery(1, $uuid));
+ $retry->setJob($this->delivery(2, $uuid));
+ $old->handle($this->scanner(function () use ($retry, $fresh, $document) {
+ try {
+ $retry->handle($this->scanner(fn () => throw new \RuntimeException('PRIVATE current worker failed')));
+ } catch (\RuntimeException $error) {
+ $this->assertSame('PRIVATE current worker failed', $error->getMessage());
+ }
+ $fresh->failed(new \RuntimeException('PRIVATE previous delivery failure'));
+ $this->assertSame('scanning', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(0, $this->roots());
+ $retry->failed(new \RuntimeException('PRIVATE current terminal failure'));
+
+ return $this->scannerResult('clean');
+ }));
+ $this->assertSame('failed', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(2, DB::table('documents')->where('id', $document->id)->value('malware_scan_attempts'));
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertSame(1, $this->roots());
+ }
+
+ public function test_infected_result_and_its_original_are_preserved_against_late_callbacks_and_queued_jobs(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $before = Storage::disk('local')->get($document->storage_key);
+ $job->handle($this->scanner(fn () => $this->scannerResult('infected')));
+ $current = DB::table('documents')->where('id', $document->id)->first();
+ $this->freshJob($job)->failed(new \RuntimeException('PRIVATE stale failure'));
+ (new ScanDocumentForMalware($document->id, $job->opportunityContext))->handle($this->scanner(fn () => throw new \RuntimeException('Scanner must not be called for infected bytes')));
+ $this->assertEquals($current, DB::table('documents')->where('id', $document->id)->first());
+ $this->assertSame('infected', $current->malware_scan_status);
+ $this->assertSame('quarantined', $current->status);
+ $this->assertSame($before, Storage::disk('local')->get($document->storage_key));
+ $this->assertSame(0, $this->roots());
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ }
+
+ public function test_document_record_changes_during_scan_are_inconclusive_and_history_keeps_the_attempted_hash(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $before = Storage::disk('local')->get($document->storage_key);
+ $job->handle($this->scanner(function () use ($document) {
+ DB::table('documents')->where('id', $document->id)->update(['sha256' => str_repeat('b', 64)]);
+
+ return $this->scannerResult('clean');
+ }));
+ $current = DB::table('documents')->where('id', $document->id)->first();
+ $this->assertSame('inconclusive', $current->malware_scan_status);
+ $this->assertSame('document_record_changed_during_scan', $current->malware_failure_reason);
+ $this->assertNull($current->malware_scanned_sha256);
+ $this->assertSame(trim($document->sha256), DB::table('document_malware_scans')->value('file_sha256'));
+ $this->assertSame($before, Storage::disk('local')->get($document->storage_key));
+ $this->assertSame('scan_inconclusive', json_decode(DB::table('audit_events')->where('id', $job->runIdentifier())->value('after_data'), true)['incident']['error_code']);
+ }
+
+ public function test_fresh_serialized_failure_callback_owns_only_its_attempt_and_an_explicit_retry_remains_possible(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $fresh = $this->freshJob($job);
+ try {
+ $job->handle($this->scanner(fn () => throw new \RuntimeException('PRIVATE engine failure')));
+ } catch (\RuntimeException $error) {
+ $this->assertSame('PRIVATE engine failure', $error->getMessage());
+ }
+ $fresh->failed(new \RuntimeException('PRIVATE terminal failure'));
+ $fresh->failed(new \RuntimeException('PRIVATE duplicate callback'));
+ $this->assertSame('failed', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(1, $this->roots());
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $fresh->handle(new CleanScannerFixture);
+ $this->assertSame('clean', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(2, DB::table('document_malware_scans')->count());
+ $this->assertSame(1, $this->roots());
+ }
+
+ public function test_legacy_serialized_payload_uses_the_real_queue_uuid_in_a_fresh_failure_callback(): void
+ {
+ [$resource,$document] = $this->upload();
+ $class = ScanDocumentForMalware::class;
+ $payload = 'O:'.strlen($class).':"'.$class.'":1:{s:10:"documentId";s:36:"'.$document->id.'";}';
+ $job = unserialize($payload, ['allowed_classes' => [$class]]);
+ $fresh = unserialize($payload, ['allowed_classes' => [$class]]);
+ $uuid = (string) Str::uuid();
+ $this->assertInstanceOf($class, $job);
+ $this->assertNull($job->executionId);
+ $job->setJob($this->delivery(1, $uuid));
+ $fresh->setJob($this->delivery(1, $uuid));
+ try {
+ $job->handle($this->scanner(fn () => throw new \RuntimeException('SYNTHETIC legacy worker failure')));
+ } catch (\RuntimeException) {
+ }
+ $fresh->failed(new \RuntimeException('SYNTHETIC legacy terminal callback'));
+ $this->assertSame($uuid, $fresh->runIdentifier());
+ $this->assertSame('failed', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(0, $this->roots());
+ }
+
+ public function test_captured_organization_is_not_replaced_when_the_opportunity_moves_before_the_worker_runs(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $captured = $job->opportunityContext;
+ $other = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $other, 'name' => 'SYNTHETIC other scan organization', 'organization_type' => 'private']);
+ $this->opportunity->forceFill(['organization_id' => $other])->save();
+ $job->handle($this->scanner(fn () => $this->scannerResult('inconclusive')));
+ $data = json_decode(DB::table('audit_events')->where('id', $job->runIdentifier())->value('after_data'), true)['incident'];
+ $this->assertSame($captured['organization_id'], $data['organization_id']);
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->actor, ['user_id' => $this->support->id, 'role' => 'technical_support', 'organization_id' => $other, 'opportunity_types' => ['investment_project']]);
+ $this->actingAs($this->support)->get('/suporte-tecnico/incidentes')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.total', 0)->where('profileAccess.technicalSupportUnread', 0));
+ $this->assertSame(1, $this->roots());
+ }
+
+ public function test_incident_persistence_failure_does_not_release_the_document_or_fail_a_completed_inconclusive_scan(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_reject_scan_incident CHECK (source_system <> 'portal-opportunity-incident')");
+ $job->handle($this->scanner(fn () => $this->scannerResult('inconclusive')));
+ $this->assertSame('quarantined', DB::table('documents')->where('id', $document->id)->value('status'));
+ $this->assertSame('inconclusive', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(1, DB::table('document_malware_scans')->count());
+ $this->assertSame(0, $this->roots());
+ }
+
+ public function test_generic_document_jobs_do_not_invent_an_opportunity_recipient(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = new ScanDocumentForMalware($document->id);
+ $job->handle($this->scanner(fn () => $this->scannerResult('inconclusive')));
+ $this->assertSame(0, $this->roots());
+ $this->assertSame('inconclusive', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ }
+
+ public function test_a_fresh_terminal_callback_preserves_the_attempted_byte_descriptor_after_a_record_change(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ $fresh = $this->freshJob($job);
+ try {
+ $job->handle($this->scanner(fn () => throw new \RuntimeException('SYNTHETIC worker interrupted')));
+ } catch (\RuntimeException) {
+ }
+ DB::table('documents')->where('id', $document->id)->update(['sha256' => str_repeat('b', 64), 'size_bytes' => 999]);
+ $fresh->failed(new \RuntimeException('SYNTHETIC terminal callback after record change'));
+ $result = DB::table('document_malware_scans')->first();
+ $this->assertSame(trim($document->sha256), $result->file_sha256);
+ $this->assertSame($document->size_bytes, $result->file_size_bytes);
+ $this->assertSame('inconclusive', $result->result);
+ $this->assertSame('document_record_changed_during_scan', $result->reason_code);
+ $this->assertSame('quarantined', DB::table('documents')->where('id', $document->id)->value('status'));
+ $this->assertSame('unknown', $result->engine);
+ }
+
+ public function test_failed_decryption_cleans_its_temporary_file_and_retains_the_original_and_attempt_context(): void
+ {
+ [$resource,$document] = $this->upload();
+ $job = $this->queued();
+ Storage::disk('local')->put($document->storage_key, 'PRIVATE SYNTHETIC invalid envelope');
+ try {
+ $job->handle(new CleanScannerFixture);
+ $this->fail('Invalid envelope must not be scanned as clean.');
+ } catch (DecryptException) {
+ }
+ $this->freshJob($job)->failed(new \RuntimeException('PRIVATE terminal decryption failure'));
+ $this->assertSame([$document->storage_key], Storage::disk('local')->allFiles());
+ $this->assertSame('PRIVATE SYNTHETIC invalid envelope', Storage::disk('local')->get($document->storage_key));
+ $this->assertSame('failed', DB::table('documents')->where('id', $document->id)->value('malware_scan_status'));
+ $this->assertSame(1, $this->roots());
+ }
+}
diff --git a/tests/Feature/SupportIncidentNoticesTest.php b/tests/Feature/SupportIncidentNoticesTest.php
new file mode 100644
index 00000000..cc5a1ecd
--- /dev/null
+++ b/tests/Feature/SupportIncidentNoticesTest.php
@@ -0,0 +1,173 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ config(['portal.profile_access_enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $approver = User::factory()->create();
+ $this->support = User::factory()->create(['name' => 'SYNTHETIC first support']);
+ $this->colleague = User::factory()->create(['name' => 'SYNTHETIC second support']);
+ $this->reporter = User::factory()->create();
+ $this->organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $this->organization, 'name' => 'SYNTHETIC incident organization', 'organization_type' => 'private']);
+ foreach ([$this->support, $this->colleague, $this->reporter] as $actor) {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $approver, ['user_id' => $actor->id, 'role' => $actor === $this->reporter ? 'promoter' : 'technical_support', 'organization_id' => $this->organization, 'opportunity_types' => ['investment_project'], 'source' => 'synthetic-support-treatment-fixture']);
+ }
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'user_id' => $this->reporter->id, 'organization_id' => $this->organization, 'role' => 'officer']);
+ $id = (string) Str::uuid();
+ $this->opportunity = new Opportunity(['title' => 'PRIVATE SYNTHETIC INVESTMENT', 'reference' => $id, 'slug' => $id, 'status' => 'draft']);
+ $this->opportunity->forceFill(['owner_user_id' => $this->reporter->id, 'organization_id' => $this->organization, 'opportunity_category' => 'investment_project', 'management_version' => 4, 'workflow_context' => ['working_state' => 'draft', 'content_revision' => 3]])->save();
+ // Synthetic root metadata fixture. Real failing HTTP submission/publication is covered by OpportunityTechnicalIncidentsTest.
+ $this->reference = app(OpportunityTechnicalIncidents::class)->record($this->reporter, $this->opportunity, 'submit', str_repeat('a', 64), new \RuntimeException('PRIVATE SYNTHETIC FAILURE'))['reference'];
+ $this->actingAs($this->support);
+ }
+
+ private function url(): string
+ {
+ return '/suporte-tecnico/incidentes/'.$this->reference.'/consultado';
+ }
+
+ private function notices(): int
+ {
+ return DB::table('audit_events')->where('source_system', 'portal-opportunity-support-notices')->count();
+ }
+
+ public function test_own_consultation_is_private_idempotent_and_changes_neither_treatment_nor_business(): void
+ {
+ $before = $this->opportunity->fresh()->getRawOriginal();
+ $root = DB::table('audit_events')->where('id', $this->reference)->first();
+ $grantCount = DB::table('portal_role_assignments')->count();
+ $this->get('/suporte-tecnico/incidentes')->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $page) => $page->where('profileAccess.technicalSupportUnread', 1)->where('incidents.data.0.unread', true));
+ $this->get('/suporte-tecnico/incidentes/'.$this->reference)->assertOk()->assertInertia(fn (Assert $page) => $page->where('notice.unread', true));
+ $this->assertSame(0, $this->notices());
+ $first = $this->postJson($this->url(), ['actor_id' => $this->colleague->id])->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('actor_id', $this->support->id)->assertJsonPath('read', true)->json();
+ $this->postJson($this->url())->assertOk()->assertExactJson($first);
+ $this->assertSame(1, $this->notices());
+ $this->get('/suporte-tecnico/incidentes?unread=1')->assertInertia(fn (Assert $page) => $page->where('incidents.total', 0)->where('profileAccess.technicalSupportUnread', 0));
+ $this->get('/suporte-tecnico/incidentes/'.$this->reference)->assertInertia(fn (Assert $page) => $page->where('notice.unread', false)->where('incident.handling.version', 0)->has('history.data', 0)->has('commands', 0));
+ $this->actingAs($this->colleague)->get('/suporte-tecnico/incidentes?unread=1')->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.unread', true)->where('profileAccess.technicalSupportUnread', 1));
+ $this->assertEquals($root, DB::table('audit_events')->where('id', $this->reference)->first());
+ $this->assertSame($before, $this->opportunity->fresh()->getRawOriginal());
+ $this->assertSame($grantCount, DB::table('portal_role_assignments')->count());
+ $this->assertSame(0, DB::table('tasks')->count());
+ }
+
+ public function test_unread_filter_runs_before_pagination_and_preserves_status_and_return_context(): void
+ {
+ $support = app(OpportunityTechnicalSupport::class);
+ for ($i = 0; $i < 24; $i++) {
+ $reference = app(OpportunityTechnicalIncidents::class)->record($this->reporter, $this->opportunity, 'submit', str_repeat('a', 64), new \RuntimeException('SYNTHETIC recent root'))['reference'];
+ $support->markConsulted($this->support, $reference);
+ }
+ app(TechnicalIncidentHandling::class)->decide($this->support, $this->reference, ['version' => 0, 'action' => 'resolve', 'note' => 'SYNTHETIC explicit technical resolution', 'operation_key' => (string) Str::uuid()]);
+ $this->get('/suporte-tecnico/incidentes?unread=1&status=resolved')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.reference', $this->reference)->where('incidents.data.0.handling.status', 'resolved')->where('filters.unread', true));
+ $this->get('/suporte-tecnico/incidentes/'.$this->reference.'?unread=1&status=resolved&page=2')->assertInertia(fn (Assert $page) => $page->where('backUrl', '/suporte-tecnico/incidentes?page=2&status=resolved&unread=1')->where('notice.unread', true));
+ $this->postJson($this->url())->assertOk();
+ $this->assertSame(0, $support->unreadCount($this->support));
+ $this->get('/suporte-tecnico/incidentes?unread=1&status=resolved')->assertInertia(fn (Assert $page) => $page->where('incidents.total', 0));
+ $this->getJson('/suporte-tecnico/incidentes?unread=invalid')->assertUnprocessable();
+ }
+
+ public function test_current_scope_revocation_expiry_and_auditor_precedence_apply_to_notices(): void
+ {
+ $support = app(OpportunityTechnicalSupport::class);
+ $this->opportunity->forceFill(['opportunity_category' => 'real_estate'])->save();
+ $this->assertSame(0, $support->unreadCount($this->support));
+ $this->postJson($this->url())->assertNotFound();
+ $this->opportunity->forceFill(['opportunity_category' => 'investment_project', 'organization_id' => null])->save();
+ $this->assertSame(0, $support->unreadCount($this->support));
+ $this->postJson($this->url())->assertNotFound();
+ $this->opportunity->forceFill(['organization_id' => $this->organization])->save();
+ DB::table('portal_role_assignments')->where('user_id', $this->support->id)->update(['starts_at' => now()->subDay(), 'expires_at' => now()->subMinute()]);
+ $this->postJson($this->url())->assertForbidden();
+ DB::table('portal_role_assignments')->where('user_id', $this->support->id)->update(['expires_at' => null, 'revoked_at' => now()]);
+ $this->postJson($this->url())->assertForbidden();
+ DB::table('portal_role_assignments')->where('user_id', $this->support->id)->update(['revoked_at' => null]);
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->reporter, ['user_id' => $this->support->id, 'role' => 'auditor', 'opportunity_types' => ['investment_project']]);
+ $this->postJson($this->url())->assertForbidden();
+ $this->assertNull(app(PortalProfileAccess::class)->navigation($this->support)['technicalSupport']);
+ $this->assertNull(app(PortalProfileAccess::class)->navigation($this->support)['technicalSupportUnread']);
+ $this->assertSame(0, $this->notices());
+ }
+
+ public function test_overlapping_grants_count_each_root_once_and_legacy_management_is_not_support(): void
+ {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->reporter, ['user_id' => $this->support->id, 'role' => 'technical_support', 'opportunity_types' => ['investment_project']]);
+ $this->assertSame(1, app(OpportunityTechnicalSupport::class)->unreadCount($this->support));
+ config(['portal.managers' => [$this->reporter->email]]);
+ $this->actingAs($this->reporter)->postJson($this->url())->assertForbidden();
+ $this->assertNull(app(PortalProfileAccess::class)->navigation($this->reporter)['technicalSupportUnread']);
+ $this->actingAs($this->support);
+ $this->support->forceFill(['email_verified_at' => null])->save();
+ $this->postJson($this->url())->assertForbidden();
+ $this->assertSame(0, $this->notices());
+ }
+
+ public function test_failed_acknowledgement_rolls_back_and_explicit_retry_can_confirm_once(): void
+ {
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_reject_notice CHECK (source_system <> 'portal-opportunity-support-notices')");
+ $this->postJson($this->url())->assertStatus(503);
+ $this->assertSame(0, $this->notices());
+ $this->assertSame(1, app(OpportunityTechnicalSupport::class)->unreadCount($this->support));
+ DB::statement('ALTER TABLE audit_events DROP CONSTRAINT qa_reject_notice');
+ $this->postJson($this->url())->assertOk();
+ $this->postJson($this->url())->assertOk();
+ $this->assertSame(1, $this->notices());
+ }
+
+ public function test_optional_count_failure_does_not_poison_the_callers_transaction(): void
+ {
+ DB::statement('ALTER TABLE audit_events RENAME COLUMN actor_user_id TO qa_missing_notice_actor');
+ $this->assertNull(app(OpportunityTechnicalSupport::class)->unreadCount($this->support));
+ $this->assertGreaterThan(0, DB::table('users')->count());
+ DB::statement('ALTER TABLE audit_events RENAME COLUMN qa_missing_notice_actor TO actor_user_id');
+ $this->assertSame(1, app(OpportunityTechnicalSupport::class)->unreadCount($this->support));
+ }
+
+ public function test_invalid_treatment_does_not_prevent_consultation_or_expose_other_actors_read_state(): void
+ {
+ DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => 'portal-opportunity-support', 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $this->reference, 'action' => 'incident_handled', 'after_data' => json_encode(['handling' => ['version' => 1, 'status' => 'invalid']], JSON_THROW_ON_ERROR)]);
+ $this->get('/suporte-tecnico/incidentes?unread=1')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.data.0.handling', null)->where('incidents.data.0.unread', true));
+ $this->postJson($this->url())->assertOk();
+ $recent = app(OpportunityTechnicalIncidents::class)->recent($this->reporter, $this->opportunity)[0];
+ $this->assertArrayNotHasKey('unread', $recent);
+ $this->assertArrayNotHasKey('read_at', $recent);
+ $this->assertSame(1, app(OpportunityTechnicalSupport::class)->unreadCount($this->colleague));
+ }
+}
diff --git a/tests/Feature/SupportProfileInstallationTest.php b/tests/Feature/SupportProfileInstallationTest.php
new file mode 100644
index 00000000..f8448d27
--- /dev/null
+++ b/tests/Feature/SupportProfileInstallationTest.php
@@ -0,0 +1,251 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ $this->admin = $this->actor();
+ $this->second = $this->actor();
+ $this->staff = $this->actor();
+ DB::table('portal_superuser_pair')->insert(['id' => 1, 'first_user_id' => $this->admin->id, 'second_user_id' => $this->second->id, 'approved_by' => $this->second->id, 'version' => 1, 'created_at' => now(), 'updated_at' => now()]);
+ $this->directory = storage_path('framework/testing/support-profile-install-'.Str::uuid());
+ mkdir($this->directory, 0700, true);
+ config(['portal_profiles.proof_directory' => $this->directory, 'portal.profile_access_enabled' => true, 'portal.managers' => [$this->admin->email, $this->staff->email], 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $this->login($this->admin);
+ }
+
+ protected function tearDown(): void
+ {
+ foreach (glob($this->directory.'/*') ?: [] as $file) {
+ unlink($file);
+ }rmdir($this->directory);
+ parent::tearDown();
+ }
+
+ private function actor(): User
+ {
+ return User::factory()->create(['two_factor_secret' => Crypt::encryptString('JBSWY3DPEHPK3PXP'), 'two_factor_confirmed_at' => now()]);
+ }
+
+ private function login(User $actor, bool $mfa = true): static
+ {
+ return $this->actingAs($actor)->withSession(['portal.mfa_actor' => $mfa ? $actor->id : null, 'portal.mfa_at' => $mfa ? time() : 0, 'portal.access_revision' => (int) $actor->fresh()->portal_access_revision]);
+ }
+
+ private function beforeSupport(bool $keepLedger = false): void
+ {
+ (require database_path('migrations/'.TechnicalSupportProfileSchema::MIGRATION.'.php'))->down();
+ if (! $keepLedger) {
+ DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->delete();
+ }
+ }
+
+ /** Synthetic files validate the existing readiness contract; these are not real deployment backups. @return array */
+ private function proof(): array
+ {
+ file_put_contents($this->directory.'/dump', 'SYNTHETIC contract fixture, not a database dump.');
+ file_put_contents($this->directory.'/files', 'SYNTHETIC contract fixture, not a private-file archive.');
+ $proof = ['verified_at' => gmdate('c'), 'target' => DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port'), 'code_hash' => app(PortalProfileInstallation::class)->fingerprint(), 'restore_verified' => true, 'files_verified' => true, 'compatibility_verified' => true, 'qa_passed' => true, 'dump_path' => $this->directory.'/dump', 'dump_sha256' => hash_file('sha256', $this->directory.'/dump'), 'files_path' => $this->directory.'/files', 'files_sha256' => hash_file('sha256', $this->directory.'/files')];
+ $this->writeProof($proof);
+
+ return $proof;
+ }
+
+ /** @param array $proof */
+ private function writeProof(array $proof): void
+ {
+ file_put_contents($this->directory.'/readiness.json', json_encode($proof, JSON_THROW_ON_ERROR));
+ }
+
+ /** @return array */
+ private function input(): array
+ {
+ return ['hash' => $this->getJson(self::URL)->assertOk()->json('hash'), 'confirm' => true, 'reason' => 'SYNTHETIC scoped support profile upgrade in isolated QA.', 'idempotency_key' => (string) Str::uuid()];
+ }
+
+ public function test_authenticated_upgrade_preserves_accounts_existing_authority_and_business_data_without_granting_support(): void
+ {
+ $this->beforeSupport();
+ $organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $organization, 'name' => 'SYNTHETIC preserved organization', 'organization_type' => 'private']);
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->admin, ['user_id' => $this->staff->id, 'role' => 'promoter', 'organization_id' => $organization, 'opportunity_types' => ['investment_project']]);
+ $id = (string) Str::uuid();
+ $opportunity = new Opportunity(['reference' => $id, 'slug' => $id, 'title' => 'PRIVATE SYNTHETIC PRESERVED INVESTMENT', 'status' => 'draft']);
+ $opportunity->forceFill(['owner_user_id' => $this->staff->id, 'organization_id' => $organization, 'opportunity_category' => 'investment_project', 'management_version' => 3, 'workflow_context' => ['working_state' => 'draft', 'history' => ['SYNTHETIC previous version']]])->save();
+ $before = [];
+ foreach (['users', 'organizations', 'portal_role_assignments', 'portal_superuser_pair', 'opportunities', 'tasks'] as $table) {
+ $before[$table] = DB::table($table)->orderBy('id')->get()->toJson();
+ }
+ $this->proof();
+ $this->getJson(self::URL)->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertJsonPath('ready', true)->assertJsonPath('action', 'install')->assertJsonPath('schema.state', 'base');
+ $input = $this->input();
+ $result = $this->postJson(self::URL, $input)->assertOk()->assertJsonPath('installed', true)->assertJsonPath('changed', true)->assertJsonPath('privileges_granted', false)->assertJsonPath('mode', 'install')->json();
+ $this->postJson(self::URL, $input)->assertOk()->assertExactJson($result);
+ $this->postJson(self::URL, [...$input, 'reason' => 'SYNTHETIC changed upgrade purpose'])->assertConflict();
+ foreach ($before as $table => $snapshot) {
+ $this->assertSame($snapshot, DB::table($table)->orderBy('id')->get()->toJson());
+ }
+ $this->assertTrue(app(OpportunityTechnicalSupport::class)->installed());
+ $this->assertFalse(app(OpportunityTechnicalSupport::class)->allows($this->staff));
+ $this->assertFalse(config('portal_profiles.authenticated_installation'));
+ $this->assertSame(1, DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->count());
+ $this->assertSame(1, DB::table('audit_events')->where('action', 'technical-support-install')->count());
+ }
+
+ public function test_already_installed_update_is_noop_and_receipts_are_visible_only_to_their_actor(): void
+ {
+ $input = $this->input();
+ $this->postJson(self::URL, $input)->assertOk()->assertJsonPath('changed', false)->assertJsonPath('mode', 'already_installed');
+ $this->getJson(self::URL)->assertOk()->assertJsonCount(1, 'commands')->assertJsonPath('commands.0.key', $input['idempotency_key'])->assertJsonMissingPath('commands.0.request_hash');
+ $this->login($this->second)->getJson(self::URL)->assertOk()->assertJsonCount(0, 'commands');
+ $this->login($this->admin, false)->postJson(self::URL, $input)->assertForbidden();
+ DB::table('portal_superuser_pair')->where('id', 1)->update(['first_user_id' => $this->staff->id]);
+ $this->login($this->admin)->getJson(self::URL)->assertForbidden();
+ $this->postJson(self::URL, $input)->assertForbidden();
+ }
+
+ public function test_final_audit_failure_rolls_back_role_constraint_and_migration_ledger_and_allows_explicit_retry(): void
+ {
+ $this->beforeSupport();
+ $this->proof();
+ $input = $this->input();
+ DB::statement("ALTER TABLE audit_events ADD CONSTRAINT qa_reject_support_install CHECK (source_system <> 'portal-profile-installation')");
+ $this->postJson(self::URL, $input)->assertStatus(503);
+ $state = app(TechnicalSupportProfileSchema::class)->inspect();
+ $this->assertSame('base', $state['state']);
+ $this->assertFalse($state['ledger']);
+ $this->assertFalse(config('portal_profiles.authenticated_installation'));
+ DB::statement('ALTER TABLE audit_events DROP CONSTRAINT qa_reject_support_install');
+ $this->postJson(self::URL, $input)->assertOk()->assertJsonPath('changed', true);
+ }
+
+ public function test_readiness_rejects_false_flags_malformed_values_expiry_future_dates_wrong_target_and_tampered_files(): void
+ {
+ $this->beforeSupport();
+ $valid = $this->proof();
+ $target = get_object_vars($valid['target']);
+ $variants = [['restore_verified' => 'false'], ['qa_passed' => 1], ['verified_at' => []], ['verified_at' => gmdate('c', time() + 3600)], ['verified_at' => gmdate('c', time() - 172800)], ['dump_path' => []], ['target' => 'invalid'], ['target' => [...$target, 'port' => 5432]], ['code_hash' => str_repeat('0', 64)]];
+ foreach ($variants as $variant) {
+ $this->writeProof([...$valid, ...$variant]);
+ $this->getJson(self::URL)->assertOk()->assertJsonPath('ready', false);
+ $this->postJson(self::URL, $this->input())->assertUnprocessable();
+ }
+ $this->writeProof($valid);
+ file_put_contents($this->directory.'/files', 'SYNTHETIC tampering');
+ $this->getJson(self::URL)->assertOk()->assertJsonPath('ready', false);
+ $this->postJson(self::URL, $this->input())->assertUnprocessable();
+ $this->assertFalse(app(OpportunityTechnicalSupport::class)->installed());
+ }
+
+ public function test_a_changed_valid_proof_invalidates_the_old_reviewed_plan_and_normalized_retry_keeps_the_same_receipt(): void
+ {
+ $this->beforeSupport();
+ $proof = $this->proof();
+ $stale = $this->input();
+ $this->writeProof([...$proof, 'snapshot_reference' => 'SYNTHETIC newer verified snapshot']);
+ $this->getJson(self::URL)->assertJsonPath('ready', true);
+ $this->postJson(self::URL, $stale)->assertConflict();
+ $input = $this->input();
+ $this->postJson(self::URL, [...$input, 'idempotency_key' => strtoupper($input['idempotency_key']), 'confirm' => 'yes', 'reason' => ' '.$input['reason'].' '])->assertOk();
+ $this->postJson(self::URL, $input)->assertOk();
+ $this->assertSame(1, DB::table('audit_events')->where('action', 'technical-support-install')->count());
+ }
+
+ public function test_known_base_constraint_with_registered_migration_has_a_scoped_authenticated_repair(): void
+ {
+ $ledger = DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->first();
+ $this->beforeSupport(true);
+ $this->assertFalse(app(OpportunityTechnicalSupport::class)->installed());
+ $this->getJson(self::URL)->assertOk()->assertJsonPath('consistent', false)->assertJsonPath('repairable', true)->assertJsonPath('ready', false);
+ $this->postJson(self::URL, $this->input())->assertUnprocessable();
+ $this->proof();
+ $this->postJson(self::URL, $this->input())->assertOk()->assertJsonPath('mode', 'repair_known_base')->assertJsonPath('changed', true);
+ $this->assertEquals($ledger, DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->first());
+ $this->assertTrue(app(OpportunityTechnicalSupport::class)->installed());
+ $this->assertSame(0, DB::table('portal_role_assignments')->count());
+ }
+
+ public function test_unknown_or_weakened_constraints_are_not_overwritten_or_reported_as_installed(): void
+ {
+ $this->proof();
+ DB::statement("ALTER TABLE portal_role_assignments DROP CONSTRAINT portal_role_name, ADD CONSTRAINT portal_role_name CHECK (role IN ('promoter','validator','publisher','auditor','technical_support') OR TRUE)");
+ $fingerprint = app(TechnicalSupportProfileSchema::class)->inspect()['fingerprint'];
+ $this->getJson(self::URL)->assertOk()->assertJsonPath('schema.state', 'unrecognised')->assertJsonPath('installed', false)->assertJsonPath('repairable', false);
+ $this->postJson(self::URL, $this->input())->assertConflict();
+ $this->assertSame($fingerprint, app(TechnicalSupportProfileSchema::class)->inspect()['fingerprint']);
+ DB::statement('ALTER TABLE portal_role_assignments DROP CONSTRAINT portal_role_name');
+ $this->postJson(self::URL, $this->input())->assertConflict();
+ }
+
+ public function test_missing_ledger_for_existing_support_schema_does_not_implicitly_adopt_authority(): void
+ {
+ DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->delete();
+ $this->proof();
+ $this->getJson(self::URL)->assertOk()->assertJsonPath('schema.state', 'support')->assertJsonPath('installed', false)->assertJsonPath('repairable', false);
+ $this->postJson(self::URL, $this->input())->assertConflict();
+ $this->assertFalse(DB::table('migrations')->where('migration', TechnicalSupportProfileSchema::MIGRATION)->exists());
+ }
+
+ public function test_support_role_and_legacy_allowlist_do_not_grant_installation_authority_and_auditor_denial_prevails(): void
+ {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->admin, ['user_id' => $this->staff->id, 'role' => 'technical_support', 'opportunity_types' => ['investment_project']]);
+ $this->login($this->staff)->getJson(self::URL)->assertForbidden();
+ $this->postJson(self::URL, ['hash' => str_repeat('a', 64), 'confirm' => true, 'reason' => 'SYNTHETIC forbidden installation', 'idempotency_key' => (string) Str::uuid()])->assertForbidden();
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $this->second, ['user_id' => $this->admin->id, 'role' => 'auditor', 'opportunity_types' => []]);
+ $this->login($this->admin)->getJson(self::URL)->assertForbidden();
+ $this->postJson(self::URL, [])->assertForbidden();
+ }
+
+ public function test_upgrade_keeps_existing_dependency_and_historical_support_downgrade_controls(): void
+ {
+ $this->beforeSupport();
+ $this->proof();
+ DB::table('migrations')->where('migration', '2026_10_09_030000_extend_opportunity_resources')->delete();
+ $this->getJson(self::URL)->assertJsonPath('ready', false)->assertJsonPath('dependencies.resources_030000', false);
+ $this->postJson(self::URL, $this->input())->assertUnprocessable();
+ DB::table('migrations')->insert(['migration' => '2026_10_09_030000_extend_opportunity_resources', 'batch' => 1]);
+ $this->postJson(self::URL, $this->input())->assertOk();
+ $assignment = app(PortalProfileAdministration::class)->grant($this->admin, ['user_id' => $this->staff->id, 'role' => 'technical_support', 'opportunity_types' => ['investment_project'], 'reason' => 'SYNTHETIC explicit independent support assignment']);
+ app(PortalProfileAdministration::class)->revoke($this->admin, $assignment, 'SYNTHETIC explicit removal; preserve the historical assignment');
+ try {
+ (require database_path('migrations/'.TechnicalSupportProfileSchema::MIGRATION.'.php'))->down();
+ $this->fail('Historical support assignment must survive downgrade.');
+ } catch (\LogicException $error) {
+ $this->assertStringContainsString('Preserve existing and historical', $error->getMessage());
+ }
+ $this->assertTrue(app(OpportunityTechnicalSupport::class)->installed());
+ $this->assertSame(1, DB::table('portal_role_assignments')->count());
+ }
+}
diff --git a/tests/Feature/TechnicalIncidentHandlingTest.php b/tests/Feature/TechnicalIncidentHandlingTest.php
new file mode 100644
index 00000000..e40bb187
--- /dev/null
+++ b/tests/Feature/TechnicalIncidentHandlingTest.php
@@ -0,0 +1,200 @@
+withoutVite();
+ Http::fake();
+ Mail::fake();
+ config(['portal.profile_access_enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]);
+ $approver = User::factory()->create();
+ $this->support = User::factory()->create(['name' => 'SYNTHETIC first support']);
+ $this->colleague = User::factory()->create(['name' => 'SYNTHETIC second support']);
+ $this->reporter = User::factory()->create();
+ $this->organization = (string) Str::uuid();
+ DB::table('organizations')->insert(['id' => $this->organization, 'name' => 'SYNTHETIC incident organization', 'organization_type' => 'private']);
+ foreach ([$this->support, $this->colleague, $this->reporter] as $actor) {
+ app(PortalProfileAdministration::class)->insertGrant((string) Str::uuid(), $approver, ['user_id' => $actor->id, 'role' => $actor === $this->reporter ? 'promoter' : 'technical_support', 'organization_id' => $this->organization, 'opportunity_types' => ['investment_project'], 'source' => 'synthetic-support-treatment-fixture']);
+ }
+ DB::table('memberships')->insert(['id' => (string) Str::uuid(), 'user_id' => $this->reporter->id, 'organization_id' => $this->organization, 'role' => 'officer']);
+ $id = (string) Str::uuid();
+ $this->opportunity = new Opportunity(['title' => 'PRIVATE SYNTHETIC INVESTMENT', 'reference' => $id, 'slug' => $id, 'status' => 'draft']);
+ $this->opportunity->forceFill(['owner_user_id' => $this->reporter->id, 'organization_id' => $this->organization, 'opportunity_category' => 'investment_project', 'management_version' => 4, 'workflow_context' => ['working_state' => 'draft', 'content_revision' => 3]])->save();
+ // Synthetic root metadata fixture. Real failing HTTP submission/publication is covered by OpportunityTechnicalIncidentsTest.
+ $this->reference = app(OpportunityTechnicalIncidents::class)->record($this->reporter, $this->opportunity, 'submit', str_repeat('a', 64), new \RuntimeException('PRIVATE SYNTHETIC FAILURE'))['reference'];
+ $this->actingAs($this->support);
+ }
+
+ /** @return array{version:int,action:string,note:string,operation_key:string} */
+ private function input(int $version, string $action = 'note'): array
+ {
+ return ['version' => $version, 'action' => $action, 'note' => 'PRIVATE SYNTHETIC treatment note with evidence.', 'operation_key' => (string) Str::uuid()];
+ }
+
+ private function url(): string
+ {
+ return '/suporte-tecnico/incidentes/'.$this->reference;
+ }
+
+ public function test_team_treatment_preserves_business_data_and_encrypts_notes_with_a_private_history(): void
+ {
+ $before = $this->opportunity->fresh()->getRawOriginal();
+ $grantCount = DB::table('portal_role_assignments')->count();
+ $this->postJson($this->url(), $this->input(0, 'claim'))->assertOk()->assertJsonPath('handling.status', 'in_progress')->assertJsonPath('handling.assignee_user_id', $this->support->id);
+ $this->actingAs($this->colleague)->postJson($this->url(), [...$this->input(1, 'claim'), 'assignee_user_id' => $this->reporter->id])->assertOk()->assertJsonPath('handling.assignee_user_id', $this->colleague->id);
+ $this->postJson($this->url(), $this->input(2))->assertOk();
+ $this->postJson($this->url(), $this->input(3, 'resolve'))->assertOk()->assertJsonPath('handling.status', 'resolved');
+ $this->postJson($this->url(), $this->input(4, 'reopen'))->assertOk()->assertJsonPath('handling.status', 'open')->assertJsonPath('handling.assignee_user_id', null);
+ $this->postJson($this->url(), $this->input(5, 'claim'))->assertOk();
+ $this->postJson($this->url(), $this->input(6, 'release'))->assertOk()->assertJsonPath('handling.status', 'open');
+ $this->assertSame($before, $this->opportunity->fresh()->getRawOriginal());
+ $this->assertSame(0, DB::table('tasks')->count());
+ $this->assertSame($grantCount, DB::table('portal_role_assignments')->count());
+ $raw = DB::table('audit_events')->where('source_system', 'portal-opportunity-support')->get()->toJson();
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC treatment note', $raw);
+ $this->get($this->url())->assertOk()->assertHeader('Cache-Control', 'no-store, private')->assertInertia(fn (Assert $page) => $page->has('history.data', 7)->where('incident.handling.version', 7)->where('history.data.0.note_available', true)->where('history.data.0.note', 'PRIVATE SYNTHETIC treatment note with evidence.')->missing('history.data.0.operation_key')->missing('history.data.0.hash'));
+ $mine = app(OpportunityTechnicalIncidents::class)->recent($this->reporter, $this->opportunity)[0];
+ $this->assertSame('open', $mine['handling']['status']);
+ $this->assertArrayNotHasKey('note', $mine['handling']);
+ $this->assertArrayNotHasKey('assignee_user_id', $mine['handling']);
+ }
+
+ public function test_repeating_the_original_command_after_later_treatment_is_readonly_and_private_to_its_actor(): void
+ {
+ $input = $this->input(0, 'claim');
+ $this->postJson($this->url(), $input)->assertOk();
+ $this->postJson($this->url(), $this->input(1, 'resolve'))->assertOk();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('replayed', true)->assertJsonPath('result_version', 1)->assertJsonPath('handling.version', 2)->assertJsonPath('handling.status', 'resolved');
+ $this->assertSame(2, DB::table('audit_events')->where('source_system', 'portal-opportunity-support')->count());
+ $this->get($this->url())->assertInertia(fn (Assert $page) => $page->has('commands', 2)->where('commands.0.key', $input['operation_key'])->missing('commands.0.hash'));
+ $this->actingAs($this->colleague)->get($this->url())->assertInertia(fn (Assert $page) => $page->has('commands', 0)->has('history.data', 2));
+ }
+
+ public function test_changed_command_and_stale_preparation_are_rejected_while_canonical_replay_is_accepted(): void
+ {
+ $input = $this->input(0);
+ $this->postJson($this->url(), [...$input, 'operation_key' => strtoupper($input['operation_key']), 'version' => '0', 'note' => ' '.$input['note'].' '])->assertOk();
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('replayed', true);
+ $this->postJson($this->url(), [...$input, 'note' => 'SYNTHETIC different prepared note'])->assertConflict();
+ $this->postJson($this->url(), $this->input(0, 'resolve'))->assertConflict();
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-opportunity-support')->count());
+ }
+
+ public function test_invalid_state_changes_and_whitespace_only_notes_do_not_append_events(): void
+ {
+ $this->postJson($this->url(), $this->input(0, 'reopen'))->assertUnprocessable();
+ $this->postJson($this->url(), $this->input(0, 'release'))->assertUnprocessable();
+ $this->postJson($this->url(), [...$this->input(0), 'note' => str_repeat(' ', 25)])->assertUnprocessable();
+ $this->postJson($this->url(), [...$this->input(0), 'action' => 'publish'])->assertUnprocessable();
+ $this->postJson($this->url(), $this->input(0, 'claim'))->assertOk();
+ $this->postJson($this->url(), $this->input(1, 'claim'))->assertUnprocessable();
+ $this->postJson($this->url(), $this->input(1, 'resolve'))->assertOk();
+ $this->postJson($this->url(), $this->input(2, 'resolve'))->assertUnprocessable();
+ $this->postJson($this->url(), $this->input(2, 'claim'))->assertUnprocessable();
+ $this->postJson($this->url(), $this->input(2))->assertOk()->assertJsonPath('handling.status', 'resolved');
+ }
+
+ public function test_current_scope_revocation_and_auditor_restriction_apply_to_reads_and_replayed_commands(): void
+ {
+ $input = $this->input(0);
+ $this->postJson($this->url(), $input)->assertOk();
+ DB::table('portal_role_assignments')->where('user_id', $this->support->id)->update(['revoked_at' => now()]);
+ $this->get($this->url())->assertForbidden();
+ $this->postJson($this->url(), $input)->assertForbidden();
+ $this->actingAs($this->colleague);
+ $auditor = (string) Str::uuid();
+ app(PortalProfileAdministration::class)->insertGrant($auditor, $this->reporter, ['user_id' => $this->colleague->id, 'role' => 'auditor', 'opportunity_types' => ['investment_project']]);
+ $this->get($this->url())->assertForbidden();
+ $this->postJson($this->url(), $this->input(1))->assertForbidden();
+ DB::table('portal_role_assignments')->where('id', $auditor)->update(['revoked_at' => now()]);
+ DB::table('opportunities')->where('id', $this->opportunity->id)->update(['opportunity_category' => 'real_estate']);
+ $this->get($this->url())->assertNotFound();
+ $this->postJson($this->url(), $this->input(1))->assertNotFound();
+ }
+
+ public function test_reporter_sees_status_without_internal_notes_and_cannot_open_support_detail(): void
+ {
+ $this->postJson($this->url(), $this->input(0, 'resolve'))->assertOk();
+ $this->actingAs($this->reporter)->get($this->url())->assertForbidden();
+ $this->postJson($this->url(), $this->input(1, 'reopen'))->assertForbidden();
+ $rows = app(OpportunityTechnicalIncidents::class)->recent($this->reporter, $this->opportunity);
+ $this->assertSame('resolved', $rows[0]['handling']['status']);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC treatment note', json_encode($rows));
+ $this->assertArrayNotHasKey('commands', $rows[0]);
+ }
+
+ public function test_history_pagination_preserves_queue_context_and_an_unreadable_note_is_not_invented(): void
+ {
+ for ($i = 0; $i < 12; $i++) {
+ $this->postJson($this->url(), $this->input($i))->assertOk();
+ }
+ $this->get($this->url().'?page=3')->assertOk()->assertInertia(fn (Assert $page) => $page->has('history.data', 10)->where('history.total', 12)->where('history.data.0.version', 12)->where('backUrl', '/suporte-tecnico/incidentes?page=3')->where('history.next_page_url', fn (string $url) => str_contains($url, 'page=3') && str_contains($url, 'history_page=2')));
+ $this->get($this->url().'?page=3&history_page=2')->assertInertia(fn (Assert $page) => $page->has('history.data', 2)->where('history.data.0.version', 2));
+ DB::table('audit_events')->insert(['source_system' => 'portal-opportunity-support', 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $this->reference, 'action' => 'incident_handled', 'actor_user_id' => $this->support->id, 'data_classification' => 'restricted', 'after_data' => json_encode(['handling' => ['version' => 13, 'status' => 'open', 'assignee_user_id' => null, 'updated_at' => now()->toIso8601String(), 'resolved_at' => null, 'command' => 'note', 'note' => 'SYNTHETIC unreadable envelope']])]);
+ $this->get($this->url())->assertOk()->assertInertia(fn (Assert $page) => $page->where('incident.handling.version', 13)->where('history.data.0.note_available', false)->where('history.data.0.note', null));
+ }
+
+ public function test_invalid_current_state_is_preserved_and_does_not_silently_restart_treatment(): void
+ {
+ DB::table('audit_events')->insert(['source_system' => 'portal-opportunity-support', 'entity_type' => 'opportunity-technical-incident', 'entity_id' => $this->reference, 'action' => 'incident_handled', 'actor_user_id' => $this->support->id, 'data_classification' => 'restricted', 'after_data' => json_encode(['handling' => ['version' => 5, 'status' => 'unrecognized']])]);
+ $this->get($this->url())->assertStatus(503);
+ $this->postJson($this->url(), $this->input(0))->assertStatus(503);
+ $this->get('/suporte-tecnico/incidentes')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.data.0.handling', null));
+ $this->assertNull(app(OpportunityTechnicalIncidents::class)->recent($this->reporter, $this->opportunity)[0]['handling']);
+ $this->actingAs($this->reporter)->get('/minhas-oportunidades/'.$this->opportunity->id.'/view')->assertOk();
+ $this->assertSame(1, DB::table('audit_events')->where('source_system', 'portal-opportunity-support')->count());
+ }
+
+ public function test_queue_filters_use_the_latest_treatment_and_detail_keeps_the_queue_context(): void
+ {
+ $this->postJson($this->url(), $this->input(0, 'claim'))->assertOk();
+ $this->get('/suporte-tecnico/incidentes?status=in_progress')->assertOk()->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.handling.status', 'in_progress'));
+ $this->postJson($this->url(), $this->input(1, 'resolve'))->assertOk();
+ $this->postJson($this->url(), $this->input(2))->assertOk();
+ $this->get('/suporte-tecnico/incidentes?status=open')->assertInertia(fn (Assert $page) => $page->where('incidents.total', 0));
+ $this->get('/suporte-tecnico/incidentes?status=resolved')->assertInertia(fn (Assert $page) => $page->where('incidents.total', 1)->where('incidents.data.0.details_url', $this->url()));
+ $this->get($this->url().'?status=resolved&page=3')->assertInertia(fn (Assert $page) => $page->where('backUrl', '/suporte-tecnico/incidentes?page=3&status=resolved'));
+ }
+
+ public function test_audit_failure_rolls_back_the_treatment_and_the_same_command_can_be_retried_explicitly(): void
+ {
+ DB::unprepared("CREATE FUNCTION qa_fail_handling() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN IF NEW.source_system='portal-opportunity-support' THEN RAISE EXCEPTION 'PRIVATE SYNTHETIC HANDLING FAILURE'; END IF; RETURN NEW; END \$\$; CREATE TRIGGER qa_fail_handling BEFORE INSERT ON audit_events FOR EACH ROW EXECUTE FUNCTION qa_fail_handling();");
+ $input = $this->input(0, 'claim');
+ $response = $this->postJson($this->url(), $input)->assertStatus(503);
+ $this->assertStringNotContainsString('PRIVATE SYNTHETIC HANDLING FAILURE', $response->getContent());
+ $this->assertSame(0, app(TechnicalIncidentHandling::class)->stateFor($this->reference)['version']);
+ DB::unprepared('DROP TRIGGER qa_fail_handling ON audit_events; DROP FUNCTION qa_fail_handling();');
+ $this->postJson($this->url(), $input)->assertOk()->assertJsonPath('result_version',1);
+ }
+}
diff --git a/tests/frontend/business-point-publication.test.mjs b/tests/frontend/business-point-publication.test.mjs
new file mode 100644
index 00000000..56712515
--- /dev/null
+++ b/tests/frontend/business-point-publication.test.mjs
@@ -0,0 +1,426 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { createElement } from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}) {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const locations = load('../../resources/js/lib/business-locations.ts');
+const summaryModule = load(
+ '../../resources/js/components/business-point-summary.tsx',
+ { '@/lib/business-locations': locations },
+);
+const Summary = summaryModule.default;
+const sourceModule = load(
+ '../../resources/js/components/similar-businesses.tsx',
+ { '@inertiajs/react': { Link: 'a' }, '@/lib/portal-api': {} },
+);
+const paths = [
+ {
+ province_id: 'qa-province',
+ district_id: 'qa-one',
+ admin_post_id: '',
+ locality_id: '',
+ },
+ {
+ province_id: 'qa-province',
+ district_id: 'qa-two',
+ admin_post_id: '',
+ locality_id: '',
+ },
+];
+const payload = {
+ title: 'QA private preparation',
+ wizard_version: '2',
+ wizard_step: '5',
+ geography_scope: 'multiple',
+ locations_json: JSON.stringify(paths),
+ location_unknown: 'no',
+ disclosure_precision: 'exact',
+ location_point_enabled: 'yes',
+ location_latitude: '-26.0001',
+ location_longitude: '32.0001',
+ location_point_source_mode: 'listing',
+ source_reference: '',
+ source_date: '2026-10-02',
+ location_point_source_reference: 'Other private source',
+ location_point_source_date: '',
+ location_point_share_source: 'no',
+};
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+function harness(initial = payload) {
+ let cursor = 0;
+ const state = [],
+ requests = [];
+ const hooks = {
+ useState(initial) {
+ const index = cursor++;
+ if (!(index in state))
+ state[index] =
+ typeof initial === 'function' ? initial() : initial;
+ return [
+ state[index],
+ (value) => {
+ state[index] =
+ typeof value === 'function'
+ ? value(state[index])
+ : value;
+ },
+ ];
+ },
+ useRef(initial) {
+ const index = cursor++;
+ if (!(index in state)) state[index] = { current: initial };
+ return state[index];
+ },
+ useEffect() {},
+ useCallback(fn) {
+ return fn;
+ },
+ };
+ const active = {
+ geography_scope: ['specific', 'multiple'],
+ disclosure_precision: ['exact'],
+ location_unknown: ['no'],
+ location_point_enabled: ['yes'],
+ };
+ const schema = {
+ geography_scope: {
+ step: 5,
+ pt: 'Geographic scope',
+ en: 'Scope',
+ type: 'select',
+ max: 30,
+ options: {
+ multiple: 'Multiple',
+ specific: 'Specific',
+ national: 'National',
+ digital: 'Digital',
+ },
+ },
+ location_point_territory: {
+ step: 5,
+ pt: 'Primary site',
+ en: 'Primary site',
+ type: 'point_territory',
+ max: 150,
+ when: { ...active, geography_scope: ['multiple'] },
+ },
+ location_latitude: {
+ step: 5,
+ pt: 'Latitude',
+ en: 'Latitude',
+ type: 'decimal',
+ max: 16,
+ when: active,
+ },
+ location_longitude: {
+ step: 5,
+ pt: 'Longitude',
+ en: 'Longitude',
+ type: 'decimal',
+ max: 16,
+ when: active,
+ },
+ location_point_source_mode: {
+ step: 5,
+ pt: 'Coordinate source',
+ en: 'Coordinate source',
+ type: 'select',
+ max: 20,
+ options: { listing: 'Existing source', custom: 'Different source' },
+ when: active,
+ },
+ location_point_source_reference: {
+ step: 5,
+ pt: 'Point source',
+ en: 'Point source',
+ type: 'textarea',
+ max: 2000,
+ when: { ...active, location_point_source_mode: ['custom'] },
+ },
+ };
+ const record = {
+ id: 'qa-listing',
+ code: 'MNE-QA',
+ modality: 'company_sale',
+ classification: 'restricted',
+ version_no: 1,
+ payload: initial,
+ territory_paths: [
+ ['QA province', 'QA one'],
+ ['QA province', 'QA two'],
+ ],
+ };
+ const Wizard = load(
+ '../../resources/js/pages/investment/business-wizard.tsx',
+ {
+ react: hooks,
+ '@inertiajs/react': { router: { visit() {}, reload() {} } },
+ '@/components/country-select': { default: () => null },
+ '@/components/business-point-summary': summaryModule,
+ './shared': {
+ Frame: 'div',
+ Field: ({ label, children }) =>
+ createElement('label', null, label, children),
+ input: 'input',
+ button: 'button',
+ card: 'card',
+ api: async (url, body) => {
+ requests.push({ url, body });
+ return { ...record, payload: body.payload, version_no: 2 };
+ },
+ },
+ './business-types': {
+ businessModalities: { company_sale: 'Sale' },
+ },
+ './business-objects': { default: () => null },
+ '../../lib/business-locations': locations,
+ },
+ ).default;
+ return {
+ render() {
+ cursor = 0;
+ return Wizard({
+ countries: [],
+ record,
+ formSchema: schema,
+ modalityFormType: 'company_sale',
+ modalities: ['company_sale'],
+ objects: [],
+ objectKinds: [],
+ sectors: [],
+ });
+ },
+ requests,
+ };
+}
+
+await test('the existing wizard requires an explicit primary path and keeps the selected path distinct from the first site', async () => {
+ const h = harness();
+ let tree = h.render();
+ const chooser = nodes(tree).find(
+ (node) =>
+ node.type === 'select' &&
+ nodes(node).some(
+ (child) =>
+ child.type === 'option' &&
+ child.props.value ===
+ locations.businessPointTerritoryKey(paths[1]),
+ ),
+ );
+ assert.equal(chooser.props.value, '');
+ chooser.props.onChange({
+ target: { value: locations.businessPointTerritoryKey(paths[1]) },
+ });
+ tree = h.render();
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /QA two/);
+ assert.match(html, /Latitude \*/);
+ assert.match(html, /não publica o ponto/);
+ assert.match(html, /mantida no processo reservado/);
+ const save = nodes(tree).find(
+ (node) =>
+ node.type === 'button' && node.props.children === 'Guardar e sair',
+ );
+ await save.props.onClick();
+ assert.equal(
+ h.requests[0].url,
+ '/api/v1/existing-business/listings/qa-listing',
+ );
+ assert.equal(
+ h.requests[0].body.payload.location_point_territory,
+ locations.businessPointTerritoryKey(paths[1]),
+ );
+ assert.equal(h.requests[0].body.version_no, 1);
+ assert.equal(h.requests[0].body.payload.location_latitude, '-26.0001');
+});
+
+await test('switching source reuses existing fields and switching to national hides the supplement while preserving the private draft', async () => {
+ const h = harness();
+ let tree = h.render();
+ assert.equal(
+ nodes(tree).some((node) => node.type === 'textarea'),
+ false,
+ );
+ const source = nodes(tree).find(
+ (node) => node.type === 'select' && node.props.value === 'listing',
+ );
+ source.props.onChange({ target: { value: 'custom' } });
+ tree = h.render();
+ assert.equal(
+ nodes(tree).find((node) => node.type === 'textarea').props.value,
+ 'Other private source',
+ );
+ const scope = nodes(tree).find(
+ (node) => node.type === 'select' && node.props.value === 'multiple',
+ );
+ scope.props.onChange({ target: { value: 'national' } });
+ tree = h.render();
+ assert.doesNotMatch(
+ renderToStaticMarkup(tree),
+ /Ponto em preparação|Other private source|Latitude WGS84/,
+ );
+ assert.equal(
+ nodes(tree).some((node) => node.type === 'textarea'),
+ false,
+ );
+ await nodes(tree)
+ .find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Guardar e sair',
+ )
+ .props.onClick();
+ assert.equal(h.requests[0].body.payload.location_latitude, '-26.0001');
+ assert.equal(
+ h.requests[0].body.payload.location_point_source_reference,
+ 'Other private source',
+ );
+ assert.equal(
+ h.requests[0].body.payload.location_point_source_mode,
+ 'custom',
+ );
+ assert.equal(h.requests[0].body.payload.geography_scope, 'national');
+});
+
+await test('stale point path stays visible for reconciliation instead of selecting another site', () => {
+ const h = harness({
+ ...payload,
+ location_point_territory: 'qa-removed-site',
+ });
+ const html = renderToStaticMarkup(h.render());
+ assert.match(html, /Selecção guardada fora das localizações actuais/);
+ assert.match(html, /value="qa-removed-site" selected/);
+});
+
+await test('an incomplete earlier location does not change the index or name of a later selectable site', () => {
+ const h = harness({
+ ...payload,
+ locations_json: JSON.stringify([
+ locations.emptyBusinessLocation(),
+ paths[1],
+ ]),
+ });
+ const option = nodes(h.render()).find(
+ (node) =>
+ node.type === 'option' &&
+ node.props.value === locations.businessPointTerritoryKey(paths[1]),
+ );
+ const html = renderToStaticMarkup(option);
+ assert.match(html, /Localização 2/);
+ assert.match(html, /QA two/);
+ assert.doesNotMatch(html, /QA one/);
+ assert.equal(
+ locations.businessPointTerritoryLabel(
+ {
+ ...payload,
+ location_point_territory: locations.businessPointTerritoryKey(
+ paths[1],
+ ),
+ },
+ [['QA one'], ['QA two']],
+ ),
+ 'QA two',
+ );
+});
+
+await test('summary distinguishes registered, prepared and published data, escapes the reused source and reports an unavailable supplement', () => {
+ const registered = {
+ id: 'qa-existing',
+ is_public: false,
+ precision_level: 'exact',
+ has_geometry: true,
+ latitude: -27,
+ longitude: 33,
+ };
+ let html = renderToStaticMarkup(
+ Summary({ payload, registered, available: false }),
+ );
+ assert.match(html, /Latitude -27; longitude/);
+ assert.match(html, /Ponto em preparação/);
+ assert.match(html, /<QA source>/);
+ assert.match(html, /ainda não está instalado/);
+ assert.match(html, /substitui o primário cadastrado/);
+ html = renderToStaticMarkup(
+ Summary({ payload, registered, published: true }),
+ );
+ assert.match(html, /Ponto declarado na publicação/);
+ assert.match(html, /não reescreve o histórico/);
+ assert.equal(
+ Summary({ payload: { ...payload, location_unknown: 'yes' } }),
+ null,
+ );
+ html = renderToStaticMarkup(
+ Summary({
+ payload: { ...payload, location_point_enabled: 'no' },
+ registered,
+ }),
+ );
+ assert.match(
+ html,
+ /cadastro existente é conservado|cadastro\s+existente é conservado/,
+ );
+ assert.doesNotMatch(html, /-26.0001|<QA source>/);
+});
+
+await test('public source dates remain calendar dates in a western timezone and unknown dates are not replaced by the registration time', () => {
+ const previous = process.env.TZ;
+ try {
+ process.env.TZ = 'Pacific/Honolulu';
+ const html = renderToStaticMarkup(
+ sourceModule.BusinessLocationSource({
+ record: {
+ location_source_reference: '',
+ location_source_date: '2026-10-02',
+ location_recorded_at: '2026-11-02T10:00:00Z',
+ },
+ showRecorded: true,
+ }),
+ );
+ assert.match(html, /<Public source>/);
+ assert.ok(
+ html.includes(
+ new Date('2026-10-02T00:00:00Z').toLocaleDateString('pt-MZ', {
+ timeZone: 'UTC',
+ }),
+ ),
+ );
+ const unknown = renderToStaticMarkup(
+ sourceModule.BusinessLocationSource({
+ record: { location_recorded_at: '2026-11-02T10:00:00Z' },
+ }),
+ );
+ assert.match(unknown, /Data da fonte: desconhecida/);
+ assert.doesNotMatch(unknown, /2026/);
+ } finally {
+ if (previous === undefined) delete process.env.TZ;
+ else process.env.TZ = previous;
+ }
+});
diff --git a/tests/frontend/business-proximity-catalogue.test.mjs b/tests/frontend/business-proximity-catalogue.test.mjs
new file mode 100644
index 00000000..71915888
--- /dev/null
+++ b/tests/frontend/business-proximity-catalogue.test.mjs
@@ -0,0 +1,177 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks) {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const proximity = load('../../resources/js/components/similar-businesses.tsx', {
+ '@inertiajs/react': { Link: 'a' },
+ '@/lib/portal-api': {},
+});
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const coverage = {
+ origin_id: 'qa-public-reference',
+ origin_title: '',
+ radius_km: 25,
+ origin_recorded_at: null,
+ with_public_point: 1,
+ without_public_point: 3,
+ source: 'Published register',
+ method: 'Geodesic, not road',
+};
+
+await test('catalogue preserves applied radius in detail links while edits affect only the next search, and clearing removes both proximity fields', () => {
+ let cursor = 0,
+ sent;
+ const state = [];
+ const Page = load(
+ '../../resources/js/pages/investment/business-marketplace.tsx',
+ {
+ react: {
+ useState(initial) {
+ const index = cursor++;
+ if (!(index in state))
+ state[index] =
+ typeof initial === 'function' ? initial() : initial;
+ return [
+ state[index],
+ (value) => {
+ state[index] =
+ typeof value === 'function'
+ ? value(state[index])
+ : value;
+ },
+ ];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {
+ get: (...args) => {
+ sent = args;
+ },
+ },
+ },
+ './shared': {
+ Frame: 'div',
+ button: 'button',
+ card: 'card',
+ input: 'input',
+ },
+ './business-types': {
+ businessModalities: { company_sale: 'Company sale' },
+ },
+ '@/components/investment-territory': {
+ TerritoryFields: () => null,
+ },
+ '@/components/opportunity-classification': {
+ ClassificationSummary: () => null,
+ },
+ '@/components/similar-businesses': proximity,
+ },
+ ).default;
+ const props = {
+ filters: {
+ near_business: 'qa-public-reference',
+ radius_km: '25',
+ sector: '4',
+ },
+ geographicCoverage: coverage,
+ results: {
+ data: [
+ {
+ id: 'qa-near',
+ slug: 'qa-near',
+ title: 'Nearby',
+ modality: 'company_sale',
+ distance_km: 1.2,
+ location_recorded_at: '2026-10-02T10:00:00Z',
+ },
+ ],
+ },
+ };
+ const render = () => {
+ cursor = 0;
+ return Page(props);
+ };
+ let tree = render();
+ let html = renderToStaticMarkup(tree);
+ assert.match(html, /1 com ponto utilizável; 3 sem ponto público/);
+ assert.match(html, /<Public reference>/);
+ assert.match(html, /data não indicada/);
+ assert.match(html, /Distância aproximada em linha recta/);
+ nodes(tree)
+ .find((node) => node.type === 'input' && node.props.type === 'number')
+ .props.onChange({ target: { value: '10.5' } });
+ nodes(tree)
+ .find(
+ (node) =>
+ node.type === 'input' && node.props.id === 'business-search',
+ )
+ .props.onChange({ target: { value: 'next search' } });
+ tree = render();
+ html = renderToStaticMarkup(tree);
+ assert.match(
+ html,
+ /\/negocios\/qa-near\?near_business=qa-public-reference&radius_km=25§or=4/,
+ );
+ assert.doesNotMatch(html, /qa-near\?[^"]*radius_km=10/);
+ nodes(tree)
+ .find((node) => node.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ assert.equal(sent[1].radius_km, '10.5');
+ assert.equal(sent[1].near_business, 'qa-public-reference');
+ assert.equal(sent[1].sector, '4');
+ assert.equal(sent[1].q, 'next search');
+ nodes(tree)
+ .find((node) => node.type === 'input' && node.props.type === 'number')
+ .props.onChange({ target: { value: '' } });
+ tree = render();
+ nodes(tree)
+ .find((node) => node.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ assert.equal('radius_km' in sent[1], false);
+ assert.equal('near_business' in sent[1], false);
+ assert.equal(sent[1].sector, '4');
+});
+
+await test('distance rendering rejects unknown or malformed values and keeps unknown source dates explicit', () => {
+ for (const distance of [null, undefined, -1, Infinity, NaN, '2'])
+ assert.equal(
+ proximity.BusinessDistance({ record: { distance_km: distance } }),
+ null,
+ );
+ const html = renderToStaticMarkup(
+ proximity.BusinessDistance({
+ record: { distance_km: 0, location_recorded_at: 'not-a-date' },
+ }),
+ );
+ assert.match(html, /0 km/);
+ assert.match(html, /data não indicada/);
+});
diff --git a/tests/frontend/bvm-admission-guide.test.mjs b/tests/frontend/bvm-admission-guide.test.mjs
new file mode 100644
index 00000000..6f975c67
--- /dev/null
+++ b/tests/frontend/bvm-admission-guide.test.mjs
@@ -0,0 +1,296 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { execFileSync } from 'node:child_process';
+import { compileFunction } from 'node:vm';
+import { createRequire } from 'node:module';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (key) => mocks[key] ?? require(key),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+// Pure config export: no application bootstrap, connection or active database access.
+const guide = JSON.parse(
+ execFileSync(
+ 'php',
+ [
+ '-r',
+ "echo json_encode(require 'config/bvm-admission-guide.php', JSON_THROW_ON_ERROR);",
+ ],
+ { cwd: new URL('../..', import.meta.url), encoding: 'utf8' },
+ ),
+);
+guide.sha256 = 'b'.repeat(64);
+const lib = load('../../resources/js/lib/investment-guides.ts');
+const props = {
+ guide,
+ instruments: [],
+ note: '',
+ case: null,
+ saved: null,
+ canWrite: false,
+ historical: false,
+ olderEdition: false,
+ currentAvailable: true,
+ workingCopy: false,
+ contextChanged: false,
+ unavailableInstruments: [],
+ history: [],
+ historyNext: null,
+};
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+function harness() {
+ let cursor = 0;
+ const values = [],
+ requests = [];
+ class ValidationError extends Error {}
+ const component = load('../../resources/js/pages/investment/guide.tsx', {
+ react: {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in values)) values[i] = structuredClone(initial);
+ return [
+ values[i],
+ (value) => {
+ values[i] =
+ typeof value === 'function'
+ ? value(values[i])
+ : value;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ if (!(i in values)) values[i] = { current: initial };
+ return values[i];
+ },
+ },
+ '@inertiajs/react': { Link: 'a', router: { visit() {} } },
+ './shared': { Frame: 'main', card: '', input: '', button: '' },
+ '@/lib/investment-guides': lib,
+ '@/lib/operation-key': {
+ createOperationKey: () => 'SYNTHETIC-operation',
+ },
+ '@/lib/profile-json': {
+ ProfileValidationError: ValidationError,
+ profileJson: async (...args) => {
+ requests.push(args);
+ return { saved: true };
+ },
+ },
+ });
+ return {
+ render(extra = {}) {
+ cursor = 0;
+ const outer = component.default({ ...props, ...extra });
+ return outer.type(outer.props);
+ },
+ requests,
+ };
+}
+function headingCount(tree, label) {
+ return nodes(tree).filter(
+ (n) =>
+ ['h2', 'h3', 'h4'].includes(n.type) && n.props.children === label,
+ ).length;
+}
+
+await test('actual source guide renders five paths, scoped gaps and article/page links with explicit historical minimums', () => {
+ const tree = harness().render(),
+ html = renderToStaticMarkup(tree);
+ assert.equal(
+ nodes(tree).filter(
+ (n) => n.type === 'input' && n.props.name === 'instruments[]',
+ ).length,
+ 5,
+ );
+ assert.match(html, /Que segmento e tipo de valor pretende preparar/);
+ assert.match(html, /Requisitos por segmento e tipo de valor/);
+ assert.match(html, /Período indicado até 2025-03-31/);
+ assert.match(html, /fonte histórica, sem aplicação como mínimo actual/);
+ assert.match(html, /Por esclarecer/);
+ assert.match(html, /Regra com dispensa ou condição específica/);
+ assert.match(html, /Regulamento 04\/2021/);
+ assert.ok(
+ nodes(tree).some(
+ (n) =>
+ n.type === 'a' &&
+ n.props.href ===
+ 'https://www.bvm.co.mz/documentos/regulamentos/RegulamentoTerceiroMercado.pdf#page=2',
+ ),
+ );
+ assert.match(html, /Art. 2\(1\)\(c\) e art. 8/);
+ assert.equal(headingCount(tree, 'Preparar para discussão'), 0);
+ assert.doesNotMatch(html, /name="(note|nuit|email|amount|capital)"/);
+});
+
+await test('third-market selection hides the entry audit document while keeping OCAM, declaration and conditional waiver explanations', () => {
+ const h = harness();
+ nodes(h.render())
+ .find((n) => n.props?.value === 'third_shares')
+ .props.onChange({ target: { checked: true } });
+ const tree = h.render(),
+ html = renderToStaticMarkup(tree);
+ assert.equal(headingCount(tree, 'Auditoria ou certificação aplicável'), 0);
+ assert.equal(
+ headingCount(
+ tree,
+ 'Demonstrações financeiras assinadas por contabilista certificado',
+ ),
+ 1,
+ );
+ assert.equal(
+ headingCount(tree, 'Declaração de actualidade das informações'),
+ 1,
+ );
+ assert.equal(
+ headingCount(tree, 'Detentores do capital e participações'),
+ 1,
+ );
+ assert.match(html, /sem extensão automática/);
+ assert.match(html, /demonstrações e relatório de evolução semestrais/);
+ assert.doesNotMatch(html, /Existência jurídica de um ano, não derrogável/);
+ assert.doesNotMatch(
+ html,
+ /Relatórios de gestão e contas anuais dos dois exercícios anteriores/,
+ );
+});
+
+await test('multiple paths share common documents once while retaining their different accounts and prospectus conditions', () => {
+ const h = harness();
+ for (const code of ['official_shares', 'second_shares'])
+ nodes(h.render())
+ .find((n) => n.props?.value === code)
+ .props.onChange({ target: { checked: true } });
+ const tree = h.render(),
+ html = renderToStaticMarkup(tree);
+ for (const title of [
+ 'Deliberações, estatutos e certidão',
+ 'Relatórios, contas, fiscalização e publicações',
+ 'Auditoria ou certificação aplicável',
+ 'Projecto de prospecto conforme o segmento',
+ ])
+ assert.equal(headingCount(tree, title), 1);
+ assert.equal(
+ headingCount(
+ tree,
+ 'Demonstrações financeiras assinadas por contabilista certificado',
+ ),
+ 0,
+ );
+ assert.match(html, /dois exercícios anteriores/);
+ assert.match(html, /pelo menos nove meses/);
+ assert.match(html, /Anexo A do Regulamento do Segundo Mercado/);
+ assert.doesNotMatch(
+ html,
+ /Documentos específicos do empréstimo obrigacionista/,
+ );
+});
+
+await test('bonds use their own document path and external handoffs never receive private note or dossier parameters', () => {
+ const dossier = {
+ id: 'SYNTHETIC-private-dossier',
+ title: 'SYNTHETIC private context',
+ version: 1,
+ };
+ const tree = harness().render({
+ case: dossier,
+ canWrite: true,
+ instruments: ['second_bonds'],
+ note: 'SYNTHETIC PRIVATE NOTE',
+ });
+ assert.equal(
+ headingCount(
+ tree,
+ 'Documentos específicos do empréstimo obrigacionista',
+ ),
+ 1,
+ );
+ assert.equal(
+ headingCount(tree, 'Detentores do capital e participações'),
+ 0,
+ );
+ assert.ok(
+ nodes(tree).some(
+ (n) =>
+ n.props?.href ===
+ '/balcao-virtual/dossiers/SYNTHETIC-private-dossier',
+ ),
+ );
+ const external = nodes(tree).filter(
+ (n) => n.type === 'a' && n.props.href?.startsWith('https://'),
+ );
+ assert.ok(external.length > 10);
+ for (const link of external) {
+ assert.doesNotMatch(
+ link.props.href,
+ /SYNTHETIC|note=|context=|dossier=/,
+ );
+ assert.equal(new URL(link.props.href).search, '');
+ assert.equal(link.props.rel, 'noopener noreferrer');
+ }
+ assert.ok(
+ external.some(
+ (n) => n.props.href === 'https://www.bvm.co.mz/empresas/0/0',
+ ),
+ );
+});
+
+await test('historical BVM references render frozen sources and conditions without reopening a write or mixing guide history', async () => {
+ const h = harness();
+ const oldGuide = { ...guide, version: 'SYNTHETIC-old-BVM-edition' };
+ const tree = h.render({
+ guide: oldGuide,
+ instruments: ['third_shares'],
+ case: { id: 'SYNTHETIC-case', title: 'SYNTHETIC', version: 3 },
+ saved: { revision: 1, at: 'SYNTHETIC-date', context: { revision: 0 } },
+ canWrite: true,
+ historical: true,
+ history: [
+ {
+ id: 'SYNTHETIC-event',
+ revision: 1,
+ edition: 'SYNTHETIC-old-BVM-edition',
+ at: 'SYNTHETIC-date',
+ },
+ ],
+ });
+ assert.equal(
+ nodes(tree).find((n) => n.type === 'fieldset').props.disabled,
+ true,
+ );
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await new Promise((resolve) => setImmediate(resolve));
+ assert.equal(h.requests.length, 0);
+ assert.match(renderToStaticMarkup(tree), /SYNTHETIC-old-BVM-edition/);
+ assert.ok(
+ nodes(tree).some(
+ (n) =>
+ n.props?.href ===
+ '/investimentos/SYNTHETIC-case/guias/bolsa?revision=SYNTHETIC-event',
+ ),
+ );
+});
diff --git a/tests/frontend/company-comparison.test.mjs b/tests/frontend/company-comparison.test.mjs
new file mode 100644
index 00000000..f7ac22f6
--- /dev/null
+++ b/tests/frontend/company-comparison.test.mjs
@@ -0,0 +1,335 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { compileFunction } from 'node:vm';
+import { createRequire } from 'node:module';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (key) => mocks[key] ?? require(key),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const urls = load('../../resources/js/lib/company-comparison.ts');
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const questions = {
+ purpose: {
+ label: 'Finalidade',
+ options: {
+ new: 'Nova',
+ representation: 'Representação',
+ unknown: 'Por definir',
+ },
+ },
+ participants: {
+ label: 'Participantes',
+ options: { one: 'Um', several: 'Vários', unknown: 'Por definir' },
+ },
+ regulated: {
+ label: 'Regras específicas',
+ options: { unknown: 'Por conferir' },
+ },
+ preferred: {
+ label: 'Preferência',
+ options: { quotas: 'Quotas', unknown: 'Por definir' },
+ },
+};
+const props = {
+ definition: { version: 'v1', questions },
+ answers: {
+ purpose: 'new',
+ participants: 'one',
+ regulated: 'unknown',
+ preferred: 'quotas',
+ },
+ result: {
+ engine_version: 'v1',
+ questions,
+ active: Object.keys(questions),
+ pending: ['regulated'],
+ route: 'Compare alternativas.',
+ preparation: ['Preparar contrato.'],
+ scope: 'Edição indicada.',
+ source: {
+ title: 'Código Comercial',
+ edition: 'Edição consultada',
+ issued_on: '2022-05-25',
+ consulted_on: '2026-11-02',
+ url: 'https://tsrm.gov.mz/source.pdf',
+ },
+ forms: [
+ {
+ code: 'quotas',
+ title: 'Sociedade ',
+ description: 'Capital em quotas',
+ articles: 'Artigo 281',
+ source_href: 'https://tsrm.gov.mz/source.pdf#page=42',
+ selected: true,
+ constraints: ['SYNTHETIC incompatibility'],
+ notes: ['Conferir modalidade.'],
+ },
+ ],
+ },
+ case: null,
+ saved: null,
+ history: [],
+ historyNext: null,
+ historical: false,
+ workingCopy: false,
+ canWrite: false,
+};
+function harness() {
+ let cursor = 0;
+ const values = [],
+ refs = [],
+ visits = [],
+ requests = [];
+ let rejectSave = false;
+ const hooks = {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in values))
+ values[i] = typeof initial === 'function' ? initial() : initial;
+ return [
+ values[i],
+ (v) => {
+ values[i] = v;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ if (!(i in values)) {
+ values[i] = { current: initial };
+ refs.push(values[i]);
+ }
+ return values[i];
+ },
+ };
+ const module = load(
+ '../../resources/js/pages/investment/company-comparison.tsx',
+ {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { visit: (...args) => visits.push(args) },
+ },
+ './shared': { Frame: 'main', card: '', input: '', button: '' },
+ '@/lib/company-comparison': urls,
+ '@/lib/operation-key': {
+ createOperationKey: () => 'SYNTHETIC-operation',
+ },
+ '@/lib/profile-json': {
+ profileJson: async (...args) => {
+ requests.push(args);
+ if (rejectSave)
+ throw new Error('SYNTHETIC conflict; keep edits');
+ return { saved: true };
+ },
+ },
+ },
+ );
+ return {
+ render(extra = {}) {
+ cursor = 0;
+ const outer = module.default({ ...props, ...extra });
+ return outer.type(outer.props);
+ },
+ refs,
+ visits,
+ requests,
+ fail() {
+ rejectSave = true;
+ },
+ };
+}
+const find = (tree, name) =>
+ nodes(tree).find((node) => node.props?.name === `answers[${name}]`);
+const button = (tree, text) =>
+ nodes(tree).find(
+ (node) => node.type === 'button' && node.props.children === text,
+ );
+await test('public comparison is a real GET form, safely renders sources and constraints, and asks no identity data', () => {
+ const h = harness(),
+ tree = h.render(),
+ html = renderToStaticMarkup(tree);
+ const form = nodes(tree).find((node) => node.type === 'form');
+ assert.equal(form.props.method, 'get');
+ assert.equal(form.props.action, '/formas-juridicas');
+ assert.match(html, /Sociedade <SYNTHETIC>/);
+ assert.match(html, /Incompatibilidade a resolver/);
+ assert.match(html, /Preferência para aprofundar/);
+ assert.match(html, /2022-05-25/);
+ assert.doesNotMatch(html, /name="(email|nuit|name|registration)"/);
+});
+await test('changing to representation hides inapplicable questions while keeping their answers for later recovery', () => {
+ const h = harness();
+ find(h.render(), 'purpose').props.onChange({
+ target: { value: 'representation' },
+ });
+ const tree = h.render();
+ assert.equal(find(tree, 'participants').type, 'input');
+ assert.equal(find(tree, 'participants').props.type, 'hidden');
+ assert.equal(find(tree, 'participants').props.value, 'one');
+ assert.equal(find(tree, 'preferred').props.value, 'quotas');
+ find(tree, 'purpose').props.onChange({ target: { value: 'new' } });
+ assert.equal(find(h.render(), 'participants').props.value, 'one');
+});
+await test('dossier choice uses current browser values and transports only answer codes through normal authentication', () => {
+ const h = harness(),
+ tree = h.render();
+ h.refs[0].current = {};
+ const old = globalThis.FormData;
+ globalThis.FormData = class {
+ get(key) {
+ return key === 'answers[participants]' ? 'several' : null;
+ }
+ };
+ try {
+ button(tree, 'Escolher dossier para guardar').props.onClick();
+ } finally {
+ globalThis.FormData = old;
+ }
+ const target = new URL(h.visits[0][0], 'https://portal.test');
+ assert.equal(target.pathname, '/investimentos');
+ assert.equal(
+ target.searchParams.get('company_comparison[participants]'),
+ 'several',
+ );
+ assert.equal(
+ target.searchParams.get('company_comparison[preferred]'),
+ 'quotas',
+ );
+});
+await test('a failed save keeps actual field values and context, and never navigates as though the comparison was saved', async () => {
+ const h = harness();
+ h.fail();
+ const extra = {
+ case: { id: 'dossier-a', title: 'SYNTHETIC dossier', version: 7 },
+ canWrite: true,
+ };
+ let tree = h.render(extra);
+ h.refs[0].current = {};
+ find(tree, 'participants').props.onChange({ target: { value: 'several' } });
+ tree = h.render(extra);
+ const old = globalThis.FormData;
+ globalThis.FormData = class {
+ get(key) {
+ return key === 'answers[participants]' ? 'several' : null;
+ }
+ };
+ try {
+ await button(tree, 'Guardar no dossier').props.onClick();
+ } finally {
+ globalThis.FormData = old;
+ }
+ assert.equal(h.requests[0][0], '/investimentos/dossier-a/forma-juridica');
+ assert.equal(h.requests[0][1].version, 7);
+ assert.equal(h.requests[0][1].answers.participants, 'several');
+ assert.equal(h.visits.length, 0);
+ const after = h.render(extra);
+ assert.equal(find(after, 'participants').props.value, 'several');
+ assert.match(renderToStaticMarkup(after), /SYNTHETIC conflict; keep edits/);
+ assert.equal(
+ button(after, 'Reabrir com estas respostas').props.type,
+ 'submit',
+ );
+ assert.equal(
+ nodes(after).find((node) => node.type === 'form').props.method,
+ 'get',
+ );
+});
+await test('historical and superseded results retain their own question labels and source and require explicit current preparation', () => {
+ const h = harness();
+ const historicalResult = {
+ ...props.result,
+ engine_version: 'older',
+ questions: {
+ ...questions,
+ participants: {
+ ...questions.participants,
+ label: 'SYNTHETIC historical wording',
+ },
+ },
+ };
+ const tree = h.render({
+ case: { id: 'dossier-a', title: 'Dossier', version: 3 },
+ canWrite: true,
+ historical: true,
+ saved: { revision: 1, at: '2026-11-01', result: historicalResult },
+ result: historicalResult,
+ });
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /SYNTHETIC historical wording/);
+ assert.equal(nodes(tree).filter((node) => node.type === 'form').length, 0);
+ const link = nodes(tree).find(
+ (node) =>
+ node.props?.children ===
+ 'Preparar nova comparação com estas respostas',
+ );
+ assert.equal(
+ new URL(link.props.href, 'https://portal.test').searchParams.get(
+ 'answers[participants]',
+ ),
+ 'one',
+ );
+ assert.equal(
+ new URL(link.props.href, 'https://portal.test').searchParams.has(
+ 'revision',
+ ),
+ false,
+ );
+});
+await test('successful save recovers the saved dossier edition and history links retain the exact dossier scope', async () => {
+ const h = harness(),
+ extra = {
+ case: { id: 'dossier-a', title: 'Dossier', version: 5 },
+ canWrite: true,
+ history: [
+ {
+ id: 'event-a',
+ revision: 2,
+ at: '2026-11-02',
+ engine_version: 'v1',
+ },
+ ],
+ historyNext: 100,
+ };
+ const tree = h.render(extra);
+ h.refs[0].current = {};
+ const old = globalThis.FormData;
+ globalThis.FormData = class {
+ get() {
+ return null;
+ }
+ };
+ try {
+ await button(tree, 'Guardar no dossier').props.onClick();
+ } finally {
+ globalThis.FormData = old;
+ }
+ assert.equal(h.visits[0][0], '/investimentos/dossier-a/forma-juridica');
+ assert.equal(h.visits[0][1].preserveState, false);
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /dossier-a\/forma-juridica\?revision=event-a/);
+ assert.match(html, /dossier-a\/forma-juridica\?history_before=100/);
+});
diff --git a/tests/frontend/company-preparation.test.mjs b/tests/frontend/company-preparation.test.mjs
new file mode 100644
index 00000000..05fc3b7a
--- /dev/null
+++ b/tests/frontend/company-preparation.test.mjs
@@ -0,0 +1,389 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { compileFunction } from 'node:vm';
+import { createRequire } from 'node:module';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (key) => mocks[key] ?? require(key),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const lib = load('../../resources/js/lib/company-preparation.ts');
+const party = {
+ id: 'SYNTHETIC-party',
+ name: '',
+ kind: 'person',
+ source: null,
+ roles: ['subscriber'],
+ represented_id: null,
+ cash: '10',
+ in_kind: '0',
+ paid: '2',
+ share_count: '5',
+ work: null,
+ commitment: null,
+};
+const facts = {
+ form: 'quotas',
+ proposed_name: null,
+ seat: null,
+ activities: null,
+ regulated: 'unknown',
+ currency: 'MZN',
+ capital: '10',
+ nominal_value: '2',
+ management: null,
+ binding: null,
+ notes: null,
+ parties: [party],
+};
+const props = {
+ case: { id: 'SYNTHETIC-case', title: 'SYNTHETIC dossier', version: 1 },
+ canWrite: true,
+ historical: false,
+ definition: {
+ version: 'v1',
+ forms: {
+ individual: { title: 'Individual' },
+ quotas: { title: 'Quotas' },
+ anonymous: { title: 'Anónima' },
+ },
+ roles: {
+ subscriber: 'Sócio',
+ administrator: 'Administração',
+ representative: 'Representante',
+ beneficial_owner: 'Beneficiário',
+ },
+ template_notice: 'Exemplares pendentes; ficha de preparação.',
+ source: {
+ title: 'SYNTHETIC source',
+ edition: '2022',
+ url: 'https://source.test/code.pdf',
+ },
+ },
+ facts,
+ review: {
+ issues: ['SYNTHETIC pending'],
+ totals: { subscribed: '10', unpaid: '8' },
+ note: 'SYNTHETIC declared',
+ },
+ saved: null,
+ sources: {
+ case_proponent: {
+ name: 'SYNTHETIC reused',
+ kind: 'person',
+ origin: 'Proponente do dossier',
+ },
+ },
+ history: [],
+ historyNext: null,
+};
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const named = (tree, name) => nodes(tree).find((n) => n.props?.name === name);
+const button = (tree, label) =>
+ nodes(tree).find((n) => n.type === 'button' && n.props.children === label);
+const tick = () => new Promise((resolve) => setImmediate(resolve));
+function harness() {
+ let cursor = 0,
+ reject = false;
+ const values = [],
+ refs = [],
+ visits = [],
+ requests = [];
+ class ValidationError extends Error {
+ constructor(message) {
+ super(message);
+ this.fields = { 'facts.capital': 'SYNTHETIC amount error' };
+ }
+ }
+ const component = load(
+ '../../resources/js/pages/investment/company-preparation.tsx',
+ {
+ react: {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in values)) values[i] = structuredClone(initial);
+ return [
+ values[i],
+ (next) => {
+ values[i] =
+ typeof next === 'function'
+ ? next(values[i])
+ : next;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ if (!(i in values)) {
+ values[i] = { current: initial };
+ refs.push(values[i]);
+ }
+ return values[i];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { visit: (...args) => visits.push(args) },
+ },
+ './shared': { Frame: 'main', card: '', input: '', button: '' },
+ '@/lib/company-preparation': lib,
+ '@/lib/operation-key': {
+ createOperationKey: () => 'SYNTHETIC-operation',
+ },
+ '@/lib/profile-json': {
+ ProfileValidationError: ValidationError,
+ profileJson: async (...args) => {
+ requests.push(args);
+ if (args[2] === 'GET')
+ return {
+ ...props,
+ case: { ...props.case, version: 4 },
+ facts: {
+ ...facts,
+ notes: 'SYNTHETIC concurrent edit',
+ },
+ };
+ if (reject) throw new ValidationError('SYNTHETIC conflict');
+ return { saved: true };
+ },
+ },
+ },
+ );
+ return {
+ render(extra = {}) {
+ cursor = 0;
+ const outer = component.default({ ...props, ...extra });
+ return outer.type(outer.props);
+ },
+ refs,
+ visits,
+ requests,
+ fail() {
+ reject = true;
+ },
+ };
+}
+async function withData(data, fn) {
+ const original = globalThis.FormData;
+ globalThis.FormData = class {
+ get(key) {
+ return Object.hasOwn(data, key) ? data[key] : null;
+ }
+ };
+ try {
+ return await fn();
+ } finally {
+ globalThis.FormData = original;
+ }
+}
+
+await test('preparation renders seven sections, escaped private names, source and explicit incomplete state', () => {
+ const tree = harness().render(),
+ html = renderToStaticMarkup(tree);
+ assert.equal(
+ nodes(tree).filter(
+ (n) => n.type === 'h2' && /^[1-7]\./.test(n.props.children),
+ ).length,
+ 7,
+ );
+ assert.match(html, /<SYNTHETIC>/);
+ assert.match(html, /Exemplares pendentes/);
+ assert.match(html, /SYNTHETIC pending/);
+ assert.match(html, /https:\/\/source.test\/code.pdf/);
+ assert.doesNotMatch(html, /name="(email|nuit|password)"/);
+});
+
+await test('changing form hides only inapplicable capital and preserves amounts for later recovery', () => {
+ const h = harness();
+ named(h.render(), 'form').props.onChange({
+ target: { value: 'individual' },
+ });
+ assert.equal(named(h.render(), 'capital'), undefined);
+ named(h.render(), 'form').props.onChange({
+ target: { value: 'anonymous' },
+ });
+ assert.equal(named(h.render(), 'capital').props.value, '10');
+ assert.equal(named(h.render(), 'nominal_value').props.value, '2');
+ assert.equal(named(h.render(), `${party.id}.share_count`).props.value, '5');
+});
+
+await test('explicit reuse fills source identity while roles remain independently selectable', () => {
+ const h = harness();
+ const source = nodes(h.render()).find(
+ (n) =>
+ n.type === 'select' &&
+ n.props.children?.[0]?.props?.children ===
+ 'Informação nova desta preparação',
+ );
+ source.props.onChange({ target: { value: 'case_proponent' } });
+ assert.equal(
+ named(h.render(), `${party.id}.name`).props.value,
+ 'SYNTHETIC reused',
+ );
+ assert.equal(named(h.render(), `${party.id}.name`).props.readOnly, true);
+ const checkboxes = nodes(h.render()).filter(
+ (n) => n.type === 'input' && n.props.type === 'checkbox',
+ );
+ assert.deepEqual(
+ checkboxes.map((n) => n.props.checked),
+ [true, false, false, false],
+ );
+ checkboxes[1].props.onChange({ target: { checked: true } });
+ assert.deepEqual(
+ nodes(h.render())
+ .filter((n) => n.type === 'input' && n.props.type === 'checkbox')
+ .map((n) => n.props.checked),
+ [true, true, false, false],
+ );
+});
+
+await test('actual browser values are sent privately and hidden values survive without forged source snapshots', async () => {
+ await withData(
+ {
+ proposed_name: 'SYNTHETIC autofill',
+ [`${party.id}.cash`]: '7,25',
+ capital: '',
+ },
+ () => {
+ const values = lib.preparationValues(
+ {},
+ {
+ ...facts,
+ form: 'individual',
+ parties: [
+ {
+ ...party,
+ source_snapshot: { reference: 'DO NOT POST' },
+ },
+ ],
+ },
+ );
+ assert.equal(values.proposed_name, 'SYNTHETIC autofill');
+ assert.equal(values.capital, null);
+ assert.equal(values.parties[0].cash, '7,25');
+ assert.equal(values.parties[0].share_count, '5');
+ assert.equal('source_snapshot' in values.parties[0], false);
+ },
+ );
+ const h = harness();
+ h.render();
+ h.refs[0].current = {};
+ await withData({ notes: 'SYNTHETIC autofill' }, async () => {
+ nodes(h.render())
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ });
+ assert.equal(
+ h.requests[0][0],
+ '/investimentos/SYNTHETIC-case/preparar-empresa',
+ );
+ assert.equal(h.requests[0][1].facts.notes, 'SYNTHETIC autofill');
+ assert.deepEqual(h.visits, [
+ [
+ '/investimentos/SYNTHETIC-case/preparar-empresa',
+ { preserveState: false },
+ ],
+ ]);
+});
+
+await test('failed save retains private edits, consults current version without URL data and requires explicit reconciliation', async () => {
+ const h = harness();
+ h.render();
+ h.refs[0].current = {};
+ h.fail();
+ await withData({ notes: 'SYNTHETIC unsaved' }, async () => {
+ nodes(h.render())
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ });
+ assert.equal(h.visits.length, 0);
+ assert.equal(named(h.render(), 'notes').props.value, 'SYNTHETIC unsaved');
+ assert.match(renderToStaticMarkup(h.render()), /SYNTHETIC amount error/);
+ await button(
+ h.render(),
+ 'Conferir edição actual sem perder estes dados',
+ ).props.onClick();
+ assert.equal(h.requests[1][2], 'GET');
+ assert.equal(named(h.render(), 'notes').props.value, 'SYNTHETIC unsaved');
+ const recoveryHtml = renderToStaticMarkup(h.render());
+ assert.match(recoveryHtml, /SYNTHETIC concurrent edit/);
+ assert.match(recoveryHtml, /Denominação proposta/);
+ const recoverySection = nodes(h.render()).find(
+ (n) =>
+ n.type === 'section' &&
+ nodes(n).some(
+ (child) =>
+ child.type === 'h2' &&
+ child.props.children ===
+ 'Edição actualmente guardada no dossier',
+ ),
+ );
+ assert.doesNotMatch(
+ renderToStaticMarkup(recoverySection),
+ /source_snapshot|proposed_name|SYNTHETIC-party/,
+ );
+ button(
+ h.render(),
+ 'Conferi: manter os meus dados para uma nova revisão',
+ ).props.onClick();
+ assert.equal(named(h.render(), 'notes').props.value, 'SYNTHETIC unsaved');
+ await withData({}, async () => {
+ nodes(h.render())
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ });
+ assert.equal(h.requests[2][1].version, 4);
+});
+
+await test('history and consultation keep all fields read-only and cannot submit a write', async () => {
+ const h = harness();
+ const tree = h.render({
+ historical: true,
+ saved: { revision: 1, at: 'SYNTHETIC-date' },
+ history: [{ id: 'old', revision: 1, at: 'SYNTHETIC-date' }],
+ historyNext: 7,
+ });
+ assert.equal(
+ nodes(tree).find((n) => n.type === 'fieldset').props.disabled,
+ true,
+ );
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ assert.equal(h.requests.length, 0);
+ assert.match(renderToStaticMarkup(tree), /preparar-empresa\?revision=old/);
+ assert.match(renderToStaticMarkup(tree), /history_before=7/);
+ const viewer = harness();
+ assert.equal(
+ nodes(viewer.render({ canWrite: false })).find(
+ (n) => n.type === 'fieldset',
+ ).props.disabled,
+ true,
+ );
+});
diff --git a/tests/frontend/crm-next-action.test.mjs b/tests/frontend/crm-next-action.test.mjs
new file mode 100644
index 00000000..cde6ac6c
--- /dev/null
+++ b/tests/frontend/crm-next-action.test.mjs
@@ -0,0 +1,171 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+const require = createRequire(import.meta.url);
+const Link = ({ children, href }) =>
+ React.createElement('a', { href }, children);
+const Empty = () => null;
+const mocks = {
+ '@inertiajs/react': {
+ Link,
+ useForm: (data) => ({ data, processing: false, errors: {} }),
+ },
+ '@/lib/crm-record-edit': {
+ useCrmRecordEdit: ({ values }) => ({
+ form: { processing: false },
+ values,
+ blocked: false,
+ error: () => undefined,
+ }),
+ },
+ '@/components/crm-edit-comparison': { default: Empty },
+ '../management/shared': {
+ Management: ({ children }) =>
+ React.createElement('main', null, children),
+ Field: ({ label, children }) =>
+ React.createElement('label', null, label, children),
+ button: '',
+ control: '',
+ },
+ './types': {
+ leadStates: {
+ new: 'Novo',
+ qualified: 'Qualificado',
+ disqualified: 'Desqualificado',
+ converted: 'Convertido',
+ },
+ taskStates: { open: 'Aberta', done: 'Concluída' },
+ },
+};
+function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL('../../' + path, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+mocks['@/pages/management/shared'] = mocks['../management/shared'];
+mocks['./operation-key'] = {
+ createOperationKey: () => '00000000-0000-4000-8000-000000000001',
+};
+mocks['./profile-json'] = load('resources/js/lib/profile-json.ts');
+mocks['./crm-task-preparation'] = load(
+ 'resources/js/lib/crm-task-preparation.ts',
+);
+mocks['@/lib/crm-task-creation'] = load(
+ 'resources/js/lib/crm-task-creation.ts',
+);
+mocks['@/components/crm-task-creation'] = load(
+ 'resources/js/components/crm-task-creation.tsx',
+);
+const Detail = load('resources/js/pages/crm/lead.tsx').default;
+function render(patch = {}) {
+ return renderToStaticMarkup(
+ React.createElement(Detail, {
+ lead: {
+ id: 'one',
+ version_no: 1,
+ title: 'SYNTHETIC lead',
+ status: 'new',
+ owner_user_id: 1,
+ tasks: [],
+ },
+ taskCreation: { lead_id: 'one', actor_id: 1, commands: [] },
+ contacts: [],
+ owners: [{ id: 1, name: 'SYNTHETIC manager' }],
+ nextAction: { future_tasks: 0 },
+ ...patch,
+ }),
+ );
+}
+
+test('an active lead without an available future task explains the existing requirement and links to its creation form', () => {
+ const html = render();
+ assert.match(html, /0 tarefas disponíveis com prazo futuro/);
+ assert.match(html, /role="status"/);
+ assert.match(html, /dossier encerrado ficam no histórico/);
+ assert.match(html, /href="#new-crm-task"/);
+ assert.match(html, /id="new-crm-task"/);
+ assert.doesNotMatch(html, /disabled=""/); // Disqualification and creation remain available; the server checks the chosen operation.
+});
+
+test('a future action count does not claim that qualification or completion has already occurred', () => {
+ const singular = render({ nextAction: { future_tasks: 1 } });
+ assert.match(singular, /1 tarefa disponível com prazo futuro/);
+ assert.doesNotMatch(singular, /1 tarefas/);
+ const html = render({ nextAction: { future_tasks: 2 } });
+ assert.match(html, /2 tarefas disponíveis com prazo futuro/);
+ assert.doesNotMatch(
+ html,
+ /role="status"|acompanhamento qualificado|licença aprovada/,
+ );
+});
+
+test('a suspended task retains its title, deadline and history without a response button', () => {
+ const html = render({
+ lead: {
+ id: 'one',
+ version_no: 1,
+ title: 'SYNTHETIC lead',
+ status: 'qualified',
+ owner_user_id: 1,
+ tasks: [
+ {
+ id: 'paused',
+ version_no: 1,
+ title: 'SYNTHETIC preserved task',
+ status: 'open',
+ due_at: '2026-11-05T10:00:00Z',
+ assignee_user_id: 1,
+ can_update: false,
+ },
+ ],
+ },
+ });
+ assert.match(html, /SYNTHETIC preserved task/);
+ assert.match(html, /Dossier associado encerrado/);
+ assert.match(html, /Maputo/);
+ assert.match(html, /id="crm-task-paused"/);
+ assert.doesNotMatch(html, /Actualizar tarefa<\/button>/);
+});
+
+test('an older response without availability metadata does not invent a zero', () => {
+ const html = render({ nextAction: undefined });
+ assert.doesNotMatch(
+ html,
+ /tarefas disponíveis com prazo futuro|role="status"/,
+ );
+ assert.match(html, /Registar próxima acção/);
+});
+
+test('disqualified leads retain their form without the active-lead requirement notice', () => {
+ const html = render({
+ lead: {
+ id: 'one',
+ version_no: 1,
+ title: 'SYNTHETIC disqualified lead',
+ status: 'disqualified',
+ owner_user_id: 1,
+ tasks: [],
+ },
+ });
+ assert.match(html, /0 tarefas disponíveis com prazo futuro/);
+ assert.doesNotMatch(html, /role="status"|disabled=""/);
+});
diff --git a/tests/frontend/crm-record-versions.test.mjs b/tests/frontend/crm-record-versions.test.mjs
new file mode 100644
index 00000000..b5fa9198
--- /dev/null
+++ b/tests/frontend/crm-record-versions.test.mjs
@@ -0,0 +1,463 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, suffix = '') {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+function harness(initial = {}, component = null) {
+ const cells = [],
+ sent = [],
+ reloads = [];
+ let cursor,
+ result,
+ props = {
+ id: 'one',
+ kind: 'investor',
+ version: 1,
+ values: { name: 'original', status: 'prospect' },
+ ...initial,
+ };
+ const form = {
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ },
+ setDefaults(value) {
+ this.defaults = value;
+ },
+ clearErrors(key) {
+ if (key) delete this.errors[key];
+ else this.errors = {};
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ patch(url, options) {
+ sent.push({
+ url,
+ options,
+ data: structuredClone(this.transformer(this.data)),
+ });
+ },
+ };
+ const mocks = {
+ react: {
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) => {
+ cells[i] =
+ typeof value === 'function'
+ ? value(cells[i])
+ : value;
+ },
+ ];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ },
+ useForm(initial) {
+ form.data ??= structuredClone(initial);
+ return form;
+ },
+ },
+ '../management/shared': {
+ Management: 'main',
+ Field: 'label',
+ control: '',
+ button: '',
+ },
+ './types': {
+ leadStates: { new: 'Novo', qualified: 'Qualificado' },
+ taskStates: { open: 'Aberta', in_progress: 'Em curso' },
+ },
+ };
+ const hook = load('../../resources/js/lib/crm-record-edit.ts', mocks);
+ mocks['@/lib/crm-record-edit'] = hook;
+ mocks['@/components/crm-edit-comparison'] = { default: () => null };
+ mocks['@/components/crm-task-creation'] = { default: () => null };
+ const renderComponent = component
+ ? load(component.file, mocks, component.suffix ?? '')[
+ component.name ?? 'default'
+ ]
+ : hook.useCrmRecordEdit;
+ function render(patch = {}) {
+ props = { ...props, ...patch };
+ cursor = 0;
+ result = renderComponent(props);
+ return result;
+ }
+ render();
+ return {
+ form,
+ sent,
+ reloads,
+ render,
+ get edit() {
+ return result;
+ },
+ };
+}
+function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+const text = (tree) =>
+ typeof tree === 'string'
+ ? tree
+ : Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : '';
+
+test('different fields merge only after explicit adoption, retaining batched deliberate edits', () => {
+ const h = harness();
+ h.edit.change('name', 'my name');
+ h.edit.change('extra', 'ignored');
+ h.render({ version: 2, values: { name: 'original', status: 'active' } });
+ assert.deepEqual(h.edit.changed, ['status']);
+ assert.deepEqual(h.edit.unresolved, []);
+ h.edit.submit('/synthetic');
+ assert.equal(h.sent.length, 0);
+ h.edit.adopt();
+ h.render();
+ assert.deepEqual(h.edit.values, { name: 'my name', status: 'active' });
+ h.edit.submit('/synthetic');
+ assert.deepEqual(h.sent[0].data, {
+ name: 'my name',
+ status: 'active',
+ version: 2,
+ });
+});
+
+test('same-field conflicts require a choice and deliberate return to the initial value is retained', () => {
+ const h = harness();
+ h.edit.change('name', 'temporary');
+ h.edit.change('name', 'original');
+ h.render({
+ version: 2,
+ values: { name: 'other operator', status: 'prospect' },
+ });
+ assert.deepEqual(h.edit.unresolved, ['name']);
+ h.edit.adopt();
+ h.render();
+ assert.equal(h.edit.baseVersion, 1);
+ h.edit.choose('name', 'mine');
+ h.render();
+ h.edit.adopt();
+ h.render();
+ assert.equal(h.edit.values.name, 'original');
+ assert.equal(h.edit.baseVersion, 2);
+});
+
+test('choosing the current value changes only that field and another update requires a fresh choice', () => {
+ const h = harness();
+ h.edit.change('name', 'mine');
+ h.edit.change('status', 'inactive');
+ h.render({ version: 2, values: { name: 'remote', status: 'prospect' } });
+ h.edit.choose('name', 'current');
+ h.render();
+ h.edit.adopt();
+ h.render();
+ assert.deepEqual(h.edit.values, { name: 'remote', status: 'inactive' });
+ h.render({
+ version: 3,
+ values: { name: 'new remote', status: 'prospect' },
+ });
+ assert.deepEqual(h.edit.unresolved, ['name']);
+});
+
+test('refresh keeps the draft and version error until the current revision is compared', () => {
+ const h = harness();
+ h.edit.change('name', 'draft');
+ h.form.errors.version = 'Stale';
+ h.render();
+ h.edit.submit('/synthetic');
+ assert.equal(h.sent.length, 0);
+ h.edit.refresh();
+ h.render();
+ assert.deepEqual(h.reloads[0].only, ['investor', 'contacts']);
+ assert.equal(h.edit.values.name, 'draft');
+ assert.equal(h.edit.blocked, true);
+ h.reloads[0].onFinish();
+ h.render({ version: 2, values: { name: 'original', status: 'active' } });
+ h.edit.adopt();
+ h.render();
+ assert.equal(h.form.errors.version, undefined);
+ assert.equal(h.edit.values.name, 'draft');
+});
+
+test('success uses the actual returned record and keeps edits made while saving', () => {
+ const h = harness({
+ kind: 'contact',
+ values: { email: 'UPPER@EXAMPLE.INVALID', phone: '111' },
+ });
+ h.edit.submit('/synthetic');
+ h.edit.change('email', 'temporary');
+ h.edit.change('email', 'UPPER@EXAMPLE.INVALID');
+ h.edit.change('phone', '222');
+ assert.equal(h.sent[0].data.phone, '111');
+ h.sent[0].options.onSuccess({
+ props: {
+ contacts: [
+ { id: 'different', version_no: 900 },
+ {
+ id: 'one',
+ version_no: 2,
+ email: 'upper@example.invalid',
+ phone: '111',
+ },
+ ],
+ },
+ });
+ h.render({
+ version: 2,
+ values: { email: 'upper@example.invalid', phone: '111' },
+ });
+ assert.deepEqual(h.edit.values, {
+ email: 'UPPER@EXAMPLE.INVALID',
+ phone: '222',
+ });
+ assert.deepEqual(h.form.defaults, {
+ version: 2,
+ values: { email: 'upper@example.invalid', phone: '111' },
+ });
+ h.edit.submit('/synthetic');
+ assert.equal(h.sent[1].data.version, 2);
+});
+
+test('lead success clears the previous event reason while keeping a newly typed reason', () => {
+ for (const duringSave of [false, true]) {
+ const h = harness({
+ kind: 'lead',
+ values: { status: 'new', qualification_reason: '' },
+ blankAfterSave: ['qualification_reason'],
+ });
+ h.edit.change('qualification_reason', 'first event');
+ h.render();
+ h.edit.submit('/synthetic');
+ if (duringSave) h.edit.change('qualification_reason', 'new event');
+ h.sent[0].options.onSuccess({
+ props: {
+ taskCreation: { lead_id: 'one', actor_id: 1, commands: [] },
+ lead: {
+ id: 'one',
+ version_no: 2,
+ status: 'qualified',
+ qualification_reason: 'first event',
+ },
+ },
+ });
+ h.render({
+ version: 2,
+ values: { status: 'qualified', qualification_reason: '' },
+ });
+ assert.equal(
+ h.edit.values.qualification_reason,
+ duringSave ? 'new event' : '',
+ );
+ }
+});
+
+test('task success resolves the exact task; invalid responses and another record cannot reset a draft', () => {
+ const h = harness({ kind: 'task', values: { status: 'open' } });
+ h.edit.change('status', 'in_progress');
+ h.render();
+ h.edit.submit('/synthetic');
+ for (const props of [
+ { lead: { tasks: [{ id: 'other', version_no: 2, status: 'done' }] } },
+ { lead: { tasks: [{ id: 'one', version_no: '2', status: 'done' }] } },
+ ]) {
+ h.sent[0].options.onSuccess({ props });
+ assert.equal(h.form.data.values.status, 'in_progress');
+ }
+ h.sent[0].options.onSuccess({
+ props: {
+ lead: {
+ tasks: [{ id: 'one', version_no: 2, status: 'in_progress' }],
+ },
+ },
+ });
+ h.render({ version: 2 });
+ assert.equal(h.edit.baseVersion, 2);
+ h.edit.submit('/synthetic');
+ h.render({ id: 'two' });
+ h.sent[1].options.onSuccess({
+ props: {
+ lead: { tasks: [{ id: 'one', version_no: 3, status: 'done' }] },
+ },
+ });
+ assert.equal(h.form.data.values.status, 'in_progress');
+ assert.equal(h.edit.blocked, true);
+});
+
+test('invalid version blocks a command and transformed field errors remain accessible', () => {
+ const h = harness({ version: 0 });
+ h.edit.submit('/synthetic');
+ assert.equal(h.sent.length, 0);
+ h.form.errors.email = 'Invalid email';
+ assert.equal(h.edit.error('email'), 'Invalid email');
+});
+
+test('comparison offers explicit non-submit choices and blocks adoption while conflicts remain', () => {
+ const h = harness();
+ h.edit.change('name', 'mine');
+ h.render({ version: 2, values: { name: 'remote', status: 'prospect' } });
+ const Panel = load(
+ '../../resources/js/components/crm-edit-comparison.tsx',
+ ).default;
+ const tree = Panel({ editor: h.edit, labels: { name: 'Nome' } });
+ const buttons = nodes(tree).filter((node) => node.type === 'button');
+ assert.ok(buttons.every((button) => button.props.type === 'button'));
+ assert.match(text(tree), /Actualmente guardado/);
+ assert.match(text(tree), /mine/);
+ assert.match(text(tree), /remote/);
+ assert.equal(buttons.at(-1).props.disabled, true);
+ buttons
+ .find((button) => text(button).includes('Manter minha'))
+ .props.onClick();
+ h.render();
+ assert.equal(h.edit.unresolved.length, 0);
+});
+
+test('all four CRM forms send their real revisions without asking the user to enter one', () => {
+ const cases = [
+ {
+ file: '../../resources/js/pages/crm/investor.tsx',
+ props: {
+ investor: {
+ id: 'one',
+ version_no: 6,
+ legal_name: 'Synthetic investor',
+ investor_type: 'domestic',
+ status: 'prospect',
+ },
+ contacts: [],
+ leads: [],
+ },
+ expected: {
+ legal_name: 'Synthetic investor',
+ investor_type: 'domestic',
+ status: 'prospect',
+ version: 6,
+ },
+ },
+ {
+ file: '../../resources/js/pages/crm/investor.tsx',
+ suffix: '\nexport { ContactForm };',
+ name: 'ContactForm',
+ props: {
+ investorId: 'i',
+ contact: {
+ id: 'one',
+ version_no: 7,
+ full_name: 'Synthetic',
+ email: 'a@example.invalid',
+ phone: '',
+ },
+ },
+ expected: {
+ full_name: 'Synthetic',
+ email: 'a@example.invalid',
+ phone: '',
+ version: 7,
+ },
+ },
+ {
+ file: '../../resources/js/pages/crm/lead.tsx',
+ props: {
+ taskCreation: { lead_id: 'one', actor_id: 1, commands: [] },
+ lead: {
+ id: 'one',
+ version_no: 9,
+ title: 'Synthetic lead',
+ status: 'new',
+ owner_user_id: 1,
+ tasks: [],
+ },
+ contacts: [],
+ owners: [{ id: 1, name: 'Synthetic owner' }],
+ },
+ expected: {
+ status: 'new',
+ owner_user_id: '1',
+ qualification_reason: '',
+ version: 9,
+ },
+ },
+ {
+ file: '../../resources/js/pages/crm/lead.tsx',
+ suffix: '\nexport { TaskRow };',
+ name: 'TaskRow',
+ props: {
+ leadId: 'l',
+ task: {
+ id: 'one',
+ version_no: 8,
+ title: 'Synthetic',
+ status: 'open',
+ due_at: null,
+ assignee_user_id: 1,
+ can_update: true,
+ },
+ },
+ expected: { status: 'open', version: 8 },
+ },
+ ];
+ for (const item of cases) {
+ const h = harness(item.props, item);
+ nodes(h.edit)
+ .find((node) => node.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ assert.deepEqual(h.sent[0].data, item.expected);
+ assert.equal(
+ nodes(h.edit).filter(
+ (node) =>
+ node.type === 'input' && node.props.name === 'version',
+ ).length,
+ 0,
+ );
+ }
+});
diff --git a/tests/frontend/crm-task-creation.test.mjs b/tests/frontend/crm-task-creation.test.mjs
new file mode 100644
index 00000000..dda8ffc8
--- /dev/null
+++ b/tests/frontend/crm-task-creation.test.mjs
@@ -0,0 +1,207 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { harness, props, text, leadId } from './helpers/crm-task-creation.mjs';
+const form = 'new-crm-task';
+function fill(h, title = 'SYNTHETIC first') {
+ h.change(form, 'Tarefa', title);
+ h.change(form, 'Prazo (hora local)', '2027-11-04T10:30');
+}
+function saved(h, request, patch = {}) {
+ return {
+ ...h.props,
+ lead: {
+ ...h.props.lead,
+ tasks: [
+ {
+ id: '20000000-0000-4000-8000-000000000001',
+ title: request.data.title,
+ due_at: request.data.due_at,
+ assignee_user_id: Number(request.data.assignee_user_id),
+ version_no: 1,
+ status: 'open',
+ },
+ ],
+ },
+ taskCreation: {
+ lead_id: leadId,
+ actor_id: 1,
+ commands: [
+ {
+ key: request.data.client_key,
+ task_id: '20000000-0000-4000-8000-000000000001',
+ version: 1,
+ },
+ ],
+ },
+ ...patch,
+ };
+}
+test('confirmation preserves title and deadline edited after the request was sent', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.change(form, 'Tarefa', 'SYNTHETIC later');
+ h.change(form, 'Prazo (hora local)', '2027-11-05T11:00');
+ h.success(saved(h, request), request);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
+ assert.equal(
+ h.field(form, 'Prazo (hora local)').props.value,
+ '2027-11-05T11:00',
+ );
+});
+test('a lost response retries exactly the frozen request, preserving later edits', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.change(form, 'Tarefa', 'SYNTHETIC next task');
+ h.change(form, 'Responsável pela tarefa', '2');
+ h.fail(request);
+ const retry = h.submit(form);
+ assert.deepEqual(retry.data, request.data);
+ h.success(saved(h, retry), retry);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC next task');
+ assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '2');
+ const next = h.submit(form);
+ assert.notEqual(next.data.client_key, request.data.client_key);
+ assert.equal(next.data.title, 'SYNTHETIC next task');
+});
+test('a fresh read acknowledges the committed creation without posting again', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.fail(request, 500);
+ h.click('Actualizar tarefas');
+ assert.deepEqual(h.reloads.at(-1).only, [
+ 'lead',
+ 'owners',
+ 'taskCreation',
+ 'nextAction',
+ ]);
+ h.refreshed(saved(h, request));
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.field(form, 'Tarefa').props.value, '');
+ assert.match(text(h.tree), /Tarefa registada/);
+});
+test('unconfirmed reads keep the original command and later edits', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.fail(request);
+ h.change(form, 'Tarefa', 'SYNTHETIC later');
+ h.click('Actualizar tarefas');
+ h.refreshed(h.props);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
+ assert.deepEqual(h.submit(form).data, request.data);
+});
+test('another account or lead cannot acknowledge or clear a pending command', () => {
+ for (const context of [
+ { lead_id: leadId, actor_id: 2 },
+ { lead_id: 'other', actor_id: 1 },
+ ]) {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ const next = saved(h, request);
+ next.taskCreation = { ...next.taskCreation, ...context };
+ request.options.onSuccess({ props: next });
+ request.form.processing = false;
+ h.render();
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
+ assert.doesNotMatch(text(h.tree), /Tarefa registada/);
+ }
+});
+test('a same-version task mismatch does not count as confirmation', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ const next = saved(h, request);
+ next.lead.tasks[0].title = 'SYNTHETIC different';
+ h.success(next, request);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
+ assert.match(text(h.tree), /não permitiu confirmar/);
+});
+test('later task changes and a removed task are acknowledged without restoration', () => {
+ for (const removed of [false, true]) {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ const next = saved(h, request);
+ if (removed) next.lead.tasks = [];
+ else
+ Object.assign(next.lead.tasks[0], {
+ version_no: 2,
+ status: 'done',
+ title: 'SYNTHETIC updated',
+ });
+ request.options.onSuccess({ props: next });
+ request.form.processing = false;
+ h.render();
+ assert.equal(h.field(form, 'Tarefa').props.value, '');
+ assert.equal(h.sent.length, 1);
+ if (removed) assert.match(text(h.tree), /já não está disponível/);
+ }
+});
+test('validation retains the draft and allows a corrected fresh command', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.validation({ due_at: 'SYNTHETIC validation' }, request);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC first');
+ h.change(form, 'Prazo (hora local)', '2027-11-06T12:00');
+ const next = h.submit(form);
+ assert.notEqual(next.data.client_key, request.data.client_key);
+ assert.equal(next.data.due_at, new Date('2027-11-06T12:00').toISOString());
+});
+test('an untouched assignee follows a refreshed owner while an explicit choice is retained', () => {
+ const h = harness();
+ h.render({ ...h.props, lead: { ...h.props.lead, owner_user_id: 2 } });
+ assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '2');
+ h.change(form, 'Responsável pela tarefa', '1');
+ h.render({
+ ...h.props,
+ lead: { ...h.props.lead, owner_user_id: null },
+ owners: [],
+ });
+ assert.equal(h.field(form, 'Responsável pela tarefa').props.value, '1');
+ assert.match(text(h.form(form)), /Responsável anterior indisponível/);
+});
+test('draft and unknown results have one navigation guard; confirmed unchanged values clear it', () => {
+ const h = harness();
+ assert.equal(h.leave(), false);
+ fill(h);
+ assert.equal(h.leave(), true);
+ assert.equal(h.confirmCalls, 1);
+ assert.equal(h.unload(), true);
+ const request = h.submit(form);
+ h.fail(request);
+ assert.equal(h.leave(true), false);
+ h.success(saved(h, request), request);
+ assert.equal(h.leave(), false);
+ assert.equal(h.unload(), false);
+});
+test('an obsolete callback cannot erase the draft of a different lead or actor', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ const other = props({
+ lead: { ...h.props.lead, id: 'other' },
+ taskCreation: { lead_id: 'other', actor_id: 2, commands: [] },
+ });
+ h.render(other);
+ h.change(form, 'Tarefa', 'SYNTHETIC other draft');
+ request.options.onSuccess({ props: saved(h, request) });
+ request.form.processing = false;
+ h.render();
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC other draft');
+});
+test('access and conflict responses keep the command blocked until a scoped refresh', () => {
+ const h = harness();
+ fill(h);
+ const request = h.submit(form);
+ h.fail(request, 403);
+ assert.equal(h.button('Recuperar a mesma criação').props.disabled, true);
+ h.click('Actualizar tarefas');
+ h.refreshed(h.props);
+ assert.equal(h.button('Recuperar a mesma criação').props.disabled, false);
+ assert.deepEqual(h.submit(form).data, request.data);
+});
diff --git a/tests/frontend/crm-task-preparation.test.mjs b/tests/frontend/crm-task-preparation.test.mjs
new file mode 100644
index 00000000..262162e4
--- /dev/null
+++ b/tests/frontend/crm-task-preparation.test.mjs
@@ -0,0 +1,326 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { harness, props, text } from './helpers/crm-task-preparation.mjs';
+const form = 'new-crm-task';
+const taskId = '20000000-0000-4000-8000-000000000001';
+function fill(h, title = 'SYNTHETIC prepared task') {
+ h.change(form, 'Tarefa', title);
+ h.change(form, 'Prazo (hora local)', '2027-11-04T10:30');
+}
+function savedContext(h, call = h.draftRequests.at(-1)) {
+ return {
+ ...h.props.taskCreation,
+ preparation: {
+ installed: true,
+ version: call.data.version + 1,
+ operation_key: call.data.operation_key,
+ snapshot: call.data.snapshot,
+ unavailable: false,
+ updated_at: '2026-11-03T12:00:00Z',
+ },
+ };
+}
+function pageWith(context, patch = {}) {
+ return props({ taskCreation: context, ...patch });
+}
+test('automatic preparation survives a new page instance and adoption is explicit', async () => {
+ const first = harness();
+ fill(first);
+ await first.tick();
+ assert.equal(first.sent.length, 0);
+ assert.equal(first.draftRequests.length, 1);
+ const context = savedContext(first);
+ await first.respond(context);
+ const next = harness(pageWith(context));
+ assert.equal(next.field(form, 'Tarefa').props.value, '');
+ assert.ok(next.button('Comparar preparação guardada'));
+ next.click('Comparar preparação guardada');
+ next.click('Aplicar escolhas e retomar');
+ assert.equal(
+ next.field(form, 'Tarefa').props.value,
+ 'SYNTHETIC prepared task',
+ );
+ assert.equal(
+ new Date(
+ next.field(form, 'Prazo (hora local)').props.value,
+ ).toISOString(),
+ context.preparation.snapshot.values.due_at,
+ );
+ assert.equal(next.sent.length, 0);
+});
+test('creation waits until its frozen command has been checkpointed', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ assert.equal(h.sent.length, 0);
+ assert.equal(h.draftRequests.length, 1);
+ const context = savedContext(h);
+ await h.respond(context);
+ assert.equal(h.sent.length, 1);
+ assert.deepEqual(
+ h.sent[0].data,
+ context.preparation.snapshot.pending.values,
+ );
+});
+test('an uncertain preparation write retries exactly its key and preserves later edits', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ const first = h.draftRequests[0];
+ h.change(form, 'Tarefa', 'SYNTHETIC later');
+ await h.rejectDraft(first);
+ h.click('Voltar a guardar preparação');
+ const retry = h.draftRequests.at(-1);
+ assert.deepEqual(retry.data, first.data);
+ await h.respond(savedContext(h, retry), retry);
+ assert.equal(h.sent.length, 0);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
+ h.submit(form);
+ await h.flush();
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.sent[0].data.title, 'SYNTHETIC prepared task');
+});
+test('a new page recovers an uncertain business command with its original key', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ const context = savedContext(h);
+ await h.respond(context);
+ const request = h.sent[0];
+ h.fail(request, 500);
+ const next = harness(pageWith(context));
+ next.click('Comparar preparação guardada');
+ next.click('Aplicar escolhas e retomar');
+ assert.equal(next.sent.length, 0);
+ next.submit(form);
+ assert.deepEqual(next.sent[0].data, request.data);
+});
+test('a committed creation is acknowledged after reopening without another business request', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ const context = savedContext(h);
+ await h.respond(context);
+ const request = h.sent[0];
+ const stored = structuredClone(context);
+ stored.preparation.snapshot.values.title = 'SYNTHETIC later';
+ stored.preparation.snapshot.generation.title++;
+ stored.commands = [
+ { key: request.data.client_key, task_id: taskId, version: 1 },
+ ];
+ const next = harness(
+ pageWith(stored, {
+ lead: {
+ ...h.props.lead,
+ tasks: [
+ {
+ id: taskId,
+ title: request.data.title,
+ due_at: request.data.due_at,
+ assignee_user_id: 1,
+ version_no: 1,
+ status: 'open',
+ },
+ ],
+ },
+ }),
+ );
+ next.click('Comparar preparação guardada');
+ next.click('Aplicar escolhas e retomar');
+ assert.equal(next.sent.length, 0);
+ assert.equal(next.field(form, 'Tarefa').props.value, 'SYNTHETIC later');
+ assert.equal(next.field(form, 'Prazo (hora local)').props.value, '');
+ assert.match(text(next.tree), /Tarefa registada/);
+});
+test('changes made during the business request are checkpointed with its immutable command', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ await h.respond(savedContext(h));
+ const request = h.sent[0];
+ h.change(form, 'Tarefa', 'SYNTHETIC later');
+ await h.tick();
+ const latest = h.draftRequests.at(-1).data;
+ assert.equal(latest.snapshot.values.title, 'SYNTHETIC later');
+ assert.deepEqual(latest.snapshot.pending.values, request.data);
+});
+test('comparison preserves local edits and requires a new choice after further changes', async () => {
+ const h = harness();
+ fill(h);
+ await h.tick();
+ const context = savedContext(h);
+ const next = harness(pageWith(context));
+ next.change(form, 'Tarefa', 'SYNTHETIC local');
+ next.click('Comparar preparação guardada');
+ next.change(form, 'Valor a retomar: Tarefa', 'saved');
+ next.change(form, 'Tarefa', 'SYNTHETIC after choice');
+ assert.equal(
+ next.button('Aplicar escolhas e retomar').props.disabled,
+ true,
+ );
+ next.change(form, 'Valor a retomar: Tarefa', 'page');
+ next.click('Aplicar escolhas e retomar');
+ assert.equal(
+ next.field(form, 'Tarefa').props.value,
+ 'SYNTHETIC after choice',
+ );
+});
+test('a response for a different account cannot authorise a business send or clear the draft', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ await h.respond({ ...savedContext(h), actor_id: 2 });
+ assert.equal(h.sent.length, 0);
+ assert.equal(
+ h.field(form, 'Tarefa').props.value,
+ 'SYNTHETIC prepared task',
+ );
+ assert.match(text(h.tree), /Não foi possível confirmar a preparação/);
+});
+test('a callback from the previous account cannot send a task after navigation', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ const call = h.draftRequests[0],
+ context = savedContext(h, call);
+ h.render(props({ taskCreation: { ...props().taskCreation, actor_id: 2 } }));
+ h.change(form, 'Tarefa', 'SYNTHETIC next account');
+ await h.respond(context, call);
+ assert.equal(h.sent.length, 0);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC next account');
+});
+test('an unavailable installation retains the existing manual creation path', () => {
+ const initial = props();
+ initial.taskCreation.preparation.installed = false;
+ const h = harness(initial);
+ fill(h);
+ const request = h.submit(form);
+ assert.equal(h.draftRequests.length, 0);
+ assert.equal(request.data.title, 'SYNTHETIC prepared task');
+ assert.match(text(h.tree), /criação manual continua disponível/);
+});
+test('another saved preparation cannot replace a locally sent unknown command', async () => {
+ const h = harness();
+ fill(h);
+ h.submit(form);
+ await h.respond(savedContext(h));
+ const request = h.sent[0];
+ h.fail(request);
+ const newer = savedContext(h);
+ newer.preparation.version = 3;
+ newer.preparation.operation_key = '00000000-0000-4000-8000-999999999999';
+ newer.preparation.snapshot = structuredClone(newer.preparation.snapshot);
+ newer.preparation.snapshot.pending.values.client_key =
+ '00000000-0000-4000-8000-888888888888';
+ h.render({ ...h.props, taskCreation: newer });
+ h.click('Comparar preparação guardada');
+ h.click('Aplicar escolhas e retomar');
+ assert.match(text(h.tree), /outro envio sem confirmação/);
+ const retry = h.submit(form);
+ assert.deepEqual(retry.data, request.data);
+});
+
+test('a confirmed durable preparation does not repeat the leave warning but new edits do', async () => {
+ const h = harness();
+ fill(h);
+ assert.equal(h.leave(), true);
+ await h.tick();
+ await h.respond(savedContext(h));
+ assert.equal(h.leave(), false);
+ assert.equal(h.unload(), false);
+ h.change(form, 'Tarefa', 'SYNTHETIC unsaved change');
+ assert.equal(h.leave(), true);
+ assert.equal(h.unload(), true);
+});
+test('validation allows a corrected preparation with a fresh save key without discarding its fields', async () => {
+ const h = harness();
+ fill(h, 'S'.repeat(201));
+ await h.tick();
+ const first = h.draftRequests[0];
+ await h.validationDraft(
+ { 'snapshot.values.title': 'SYNTHETIC validation' },
+ first,
+ );
+ h.change(form, 'Tarefa', 'SYNTHETIC corrected');
+ h.click('Voltar a guardar preparação');
+ const corrected = h.draftRequests.at(-1);
+ assert.notEqual(corrected.data.operation_key, first.data.operation_key);
+ assert.equal(corrected.data.snapshot.values.title, 'SYNTHETIC corrected');
+ await h.respond(savedContext(h, corrected), corrected);
+ assert.equal(h.field(form, 'Tarefa').props.value, 'SYNTHETIC corrected');
+});
+test('unreadable saved data is explained and the explicit manual path preserves the server preparation', () => {
+ const initial = props();
+ initial.taskCreation.preparation = {
+ ...initial.taskCreation.preparation,
+ version: 1,
+ unavailable: true,
+ };
+ const h = harness(initial);
+ assert.match(text(h.tree), /não pôde ser lida/);
+ h.click('Continuar só nesta página');
+ fill(h);
+ h.submit(form);
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.draftRequests.length, 0);
+ assert.match(text(h.tree), /guardada no servidor foi preservada/);
+});
+
+test('cross-time-zone recovery keeps the saved instant including repeated local time and seconds', async () => {
+ const previous = process.env.TZ;
+ process.env.TZ = 'America/New_York';
+ try {
+ const initial = props(),
+ instant = '2027-11-07T06:30:12.345Z';
+ initial.taskCreation.preparation = {
+ installed: true,
+ version: 1,
+ operation_key: '00000000-0000-4000-8000-111111111111',
+ unavailable: false,
+ updated_at: '2026-11-03T12:00:00Z',
+ snapshot: {
+ values: {
+ title: 'SYNTHETIC saved instant',
+ due_at: instant,
+ assignee_user_id: '1',
+ },
+ generation: { title: 1, due_at: 1, assignee_user_id: 0 },
+ pending: null,
+ },
+ };
+ const h = harness(initial);
+ h.click('Comparar preparação guardada');
+ h.click('Aplicar escolhas e retomar');
+ h.submit(form);
+ assert.equal(
+ h.draftRequests[0].data.snapshot.pending.values.due_at,
+ instant,
+ );
+ await h.respond(savedContext(h));
+ assert.equal(h.sent[0].data.due_at, instant);
+ } finally {
+ if (previous === undefined) delete process.env.TZ;
+ else process.env.TZ = previous;
+ }
+});
+
+test('an empty completed preparation matching the page does not ask the user to compare it again', () => {
+ const initial = props();
+ initial.taskCreation.preparation = {
+ installed: true,
+ version: 2,
+ operation_key: '00000000-0000-4000-8000-111111111111',
+ unavailable: false,
+ updated_at: '2026-11-03T12:00:00Z',
+ snapshot: {
+ values: { title: '', due_at: '', assignee_user_id: '1' },
+ generation: { title: 2, due_at: 1, assignee_user_id: 0 },
+ pending: null,
+ },
+ };
+ const h = harness(initial);
+ assert.equal(h.button('Comparar preparação guardada'), undefined);
+ assert.equal(h.button('Criar tarefa').props.disabled, false);
+ assert.equal(h.leave(), false);
+ assert.equal(h.draftRequests.length, 0);
+});
diff --git a/tests/frontend/dashboard-work-queue.test.mjs b/tests/frontend/dashboard-work-queue.test.mjs
new file mode 100644
index 00000000..2b641563
--- /dev/null
+++ b/tests/frontend/dashboard-work-queue.test.mjs
@@ -0,0 +1,274 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, suffix = '') {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const Link = ({ children, href, className }) =>
+ React.createElement('a', { href, className }, children);
+const Empty = () => null;
+const mocks = {
+ '@inertiajs/react': { Link, Head: Empty },
+ '@/pages/management/shared': { states: { received: 'Recebido existente' } },
+ '@/pages/crm/types': { taskStates: { open: 'Aberta existente' } },
+};
+const Queue = load(
+ '../../resources/js/components/dashboard-work-queue.tsx',
+ mocks,
+).default;
+const Dashboard = load('../../resources/js/pages/dashboard.tsx', {
+ ...mocks,
+ '@/components/dashboard-work-queue': { default: Queue },
+ '@/components/profile-navigation': { default: Empty },
+ '@/components/content-management-entry': { default: Empty },
+ '@/routes': { dashboard: () => '/dashboard' },
+}).default;
+const item = (patch = {}) => ({
+ id: 'synthetic-one',
+ title: 'SYNTHETIC next action',
+ reference: 'SYNTHETIC-REF',
+ status: 'received',
+ due_at: '2026-11-03T10:00:00.000000Z',
+ overdue: true,
+ href: '/management/interests/1',
+ ...patch,
+});
+const group = (patch = {}) => ({
+ total: 1,
+ overdue: 1,
+ items: [item()],
+ page: 1,
+ last_page: 1,
+ previous: null,
+ next: null,
+ ...patch,
+});
+const queue = (groups) => ({
+ as_of: '2026-11-03T11:00:00.000000Z',
+ desk_states: { accepted: 'Aceite internamente — edição configurada' },
+ groups,
+});
+const render = (Component, props) =>
+ renderToStaticMarkup(React.createElement(Component, props));
+function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+
+test('investor dashboard retains its investment context without an irrelevant operational panel', () => {
+ const html = render(Dashboard, {
+ summary: null,
+ workQueue: null,
+ investorPath: {
+ contexts: [{ id: 'own-case', title: 'SYNTHETIC own investment' }],
+ current: {
+ id: 'own-case',
+ next: { code: 'S01', title: 'SYNTHETIC next investment step' },
+ pending: 2,
+ documents: 3,
+ results: 1,
+ tasks: 4,
+ },
+ },
+ });
+ assert.match(html, /SYNTHETIC own investment/);
+ assert.match(html, /href="\/investimentos\/own-case#S01"/);
+ assert.doesNotMatch(
+ html,
+ /O meu acompanhamento|Manifestações atribuídas a mim|Gestão de Oportunidades/,
+ );
+});
+
+test('the three collections keep separate totals and labels from their existing domains', () => {
+ const html = render(Queue, {
+ queue: queue({
+ interests: group({ total: 7, overdue: 2 }),
+ desk: group({
+ total: 8,
+ overdue: 3,
+ items: [
+ item({
+ status: 'accepted',
+ href: '/balcao-virtual/pedidos/one',
+ }),
+ ],
+ }),
+ crm_tasks: group({
+ total: 9,
+ overdue: 4,
+ items: [
+ item({
+ status: 'open',
+ href: '/management/crm/leads/one#crm-task-one',
+ }),
+ ],
+ }),
+ }),
+ });
+ for (const label of [
+ 'Manifestações atribuídas a mim',
+ 'Pedidos do Balcão atribuídos a mim',
+ 'Tarefas do CRM atribuídas a mim',
+ 'Recebido existente',
+ 'Aceite internamente — edição configurada',
+ 'Aberta existente',
+ ])
+ assert.ok(html.includes(label));
+ for (const n of [7, 8, 9]) assert.ok(html.includes(`${n} por acompanhar`));
+ assert.doesNotMatch(html, /24 por acompanhar|Aprovado|Licença concedida/);
+ assert.ok(html.includes('href="/management/crm/leads/one#crm-task-one"'));
+});
+
+test('missing groups stay absent and an accessible empty collection shows its real zero', () => {
+ const html = render(Queue, {
+ queue: queue({ desk: group({ total: 0, overdue: 0, items: [] }) }),
+ });
+ assert.match(html, /0 por acompanhar/);
+ assert.match(html, /Não tem registos activos atribuídos/);
+ assert.doesNotMatch(
+ html,
+ /Manifestações atribuídas|Tarefas do CRM atribuídas|Página/,
+ );
+ assert.equal(render(Queue, { queue: undefined }), '');
+});
+
+test('deadlines use Maputo time with explicit overdue and unknown-deadline information', () => {
+ const html = render(Queue, {
+ queue: queue({
+ interests: group({
+ items: [
+ item(),
+ item({ id: 'no-date', due_at: null, overdue: false }),
+ ],
+ }),
+ }),
+ });
+ assert.ok(html.includes('dateTime="2026-11-03T10:00:00.000000Z"'));
+ assert.match(html, /12:00.*?Maputo/);
+ assert.match(html, /Prazo ultrapassado/);
+ assert.match(html, /Sem prazo definido/);
+});
+
+test('each collection paginates through supplied destinations without losing scroll position', () => {
+ const tree = Queue({
+ queue: queue({
+ interests: group({
+ total: 13,
+ page: 2,
+ last_page: 3,
+ previous: '/dashboard?interests_page=1&desk_page=2',
+ next: '/dashboard?interests_page=3&desk_page=2',
+ }),
+ }),
+ });
+ const pagination = nodes(tree).find((node) => node.type === 'nav');
+ assert.equal(
+ pagination.props['aria-label'],
+ 'Páginas: Manifestações atribuídas a mim',
+ );
+ const links = nodes(pagination).filter((node) => node.type === Link);
+ assert.deepEqual(
+ links.map((link) => link.props.href),
+ [
+ '/dashboard?interests_page=1&desk_page=2',
+ '/dashboard?interests_page=3&desk_page=2',
+ ],
+ );
+ assert.ok(links.every((link) => link.props.preserveScroll === true));
+ assert.match(
+ render(Queue, {
+ queue: queue({
+ interests: group({ total: 13, page: 2, last_page: 3 }),
+ }),
+ }),
+ /Página 2 de 3/,
+ );
+});
+
+test('work queue and existing management indicators coexist, escaping record text', () => {
+ const html = render(Dashboard, {
+ summary: {
+ requestsByStatus: { received: 4 },
+ publishedOpportunities: 3,
+ draftOpportunities: 2,
+ activeSectors: 1,
+ recentRequests: [],
+ canCreateOpportunity: false,
+ },
+ workQueue: queue({
+ interests: group({
+ items: [item({ title: ' ' })],
+ }),
+ }),
+ });
+ assert.match(html, /O meu acompanhamento/);
+ assert.match(html, /Indicadores de utilização e cobertura/);
+ assert.match(html, /Oportunidades publicadas/);
+ assert.ok(html.includes('<img src=x onerror=alert(1)>'));
+ assert.doesNotMatch(html, / {
+ const TaskRow = load(
+ '../../resources/js/pages/crm/lead.tsx',
+ {
+ '@inertiajs/react': { Link, useForm() {} },
+ '@/lib/crm-record-edit': {
+ useCrmRecordEdit: () => ({
+ form: { processing: false },
+ values: { status: 'open' },
+ error: () => undefined,
+ blocked: false,
+ }),
+ },
+ '@/components/crm-edit-comparison': { default: Empty },
+ '@/components/crm-task-creation': { default: Empty },
+ '../management/shared': {
+ Management: Empty,
+ Field: Empty,
+ button: '',
+ control: '',
+ },
+ './types': { leadStates: {}, taskStates: { open: 'Aberta' } },
+ },
+ '\nexport { TaskRow };',
+ ).TaskRow;
+ const form = TaskRow({
+ task: {
+ id: 'one',
+ title: 'SYNTHETIC task',
+ status: 'open',
+ due_at: null,
+ assignee_user_id: 1,
+ version_no: 1,
+ },
+ leadId: 'lead-one',
+ });
+ const href = '/management/crm/leads/lead-one#crm-task-one';
+ assert.equal(form.props.id, href.split('#')[1]);
+});
diff --git a/tests/frontend/desk-attachments.test.mjs b/tests/frontend/desk-attachments.test.mjs
new file mode 100644
index 00000000..489386bb
--- /dev/null
+++ b/tests/frontend/desk-attachments.test.mjs
@@ -0,0 +1,569 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { File } from 'node:buffer';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, globals = {}, suffix = '') {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, [
+ 'require',
+ 'module',
+ 'exports',
+ ...Object.keys(globals),
+ ])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ ...Object.values(globals),
+ );
+ return module.exports;
+}
+const values = load('../../resources/js/lib/desk-field-values.ts');
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const field = {
+ type: 'attachment',
+ label: 'SYNTHETIC support',
+ required: true,
+ mime_types: ['text/plain'],
+ max_size_kb: 2,
+ max_files: 1,
+};
+const document = {
+ id: 'link-one',
+ document_id: 'document-one',
+ file_name: 'SYNTHETIC proof.txt',
+ category: 'SYNTHETIC',
+ source_reference: 'SYNTHETIC source',
+ status: 'quarantined',
+ malware_scan_status: 'pending',
+ media_type: 'text/plain',
+ size_bytes: 100,
+ version_no: 1,
+};
+function fieldHarness(
+ handler = async () => ({
+ documents: [document],
+ case_version: 2,
+ link_id: document.id,
+ }),
+) {
+ const cells = [],
+ calls = [],
+ inventory = [],
+ busy = [],
+ changes = [];
+ let cursor = 0,
+ props,
+ tree;
+ const react = {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) =>
+ (cells[i] =
+ typeof value === 'function' ? value(cells[i]) : value),
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ };
+ class ValidationError extends Error {}
+ const Component = load(
+ '../../resources/js/components/desk-attachment-field.tsx',
+ {
+ react,
+ '@/lib/profile-json': {
+ ProfileValidationError: ValidationError,
+ async profileJson(url, body = {}, method = 'POST') {
+ calls.push({ url, body, method });
+ return handler(url, body, method);
+ },
+ },
+ '@/lib/desk-field-values': values,
+ './desk-document-picker': { default: () => null },
+ },
+ ).default;
+ props = {
+ caseId: 'synthetic-case',
+ requestId: 'synthetic-request',
+ caseVersion: 1,
+ fieldKey: 'support',
+ field,
+ value: [],
+ documents: [document],
+ disabled: false,
+ uploading: false,
+ onChange: (ids) => changes.push(ids),
+ onBusy: (value) => busy.push(value),
+ onInventory: (data, select) => inventory.push({ data, select }),
+ };
+ const render = (patch = {}) => {
+ props = { ...props, ...patch };
+ cursor = 0;
+ tree = Component(props);
+ return tree;
+ };
+ render();
+ return {
+ render,
+ calls,
+ inventory,
+ busy,
+ changes,
+ async settle() {
+ for (let i = 0; i < 8; i++) await Promise.resolve();
+ render();
+ },
+ get tree() {
+ return tree;
+ },
+ button(label) {
+ return nodes(tree).find(
+ (node) =>
+ node.type === 'button' && node.props.children === label,
+ );
+ },
+ prepare(
+ file = new File(['SYNTHETIC bytes'], 'synthetic-proof.txt', {
+ type: 'text/plain',
+ }),
+ ) {
+ nodes(tree)
+ .find(
+ (node) =>
+ node.type === 'input' && node.props.type === 'file',
+ )
+ .props.onChange({ target: { files: [file] } });
+ render();
+ nodes(tree)
+ .find(
+ (node) =>
+ node.type === 'input' && node.props.maxLength === 3000,
+ )
+ .props.onChange({
+ target: { value: 'SYNTHETIC submitted source' },
+ });
+ render();
+ nodes(tree)
+ .filter(
+ (node) =>
+ node.type === 'input' && node.props.type === 'checkbox',
+ )
+ .at(-1)
+ .props.onChange({ target: { checked: true } });
+ render();
+ },
+ };
+}
+
+await test('cross-dossier picker uses the selected origin identity and does not re-enter existing provenance', async () => {
+ const h = fieldHarness();
+ const picker = nodes(h.tree).find(
+ (node) => typeof node.type === 'function' && 'onSelect' in node.props,
+ );
+ picker.props.onSelect({
+ ...document,
+ id: 'other-dossier-link',
+ document_id: 'other-original',
+ origin_label: 'SYNTHETIC previous dossier',
+ });
+ h.render();
+ assert.ok(
+ !nodes(h.tree).some(
+ (node) => node.type === 'input' && node.props.type === 'file',
+ ),
+ );
+ assert.ok(
+ !nodes(h.tree).some(
+ (node) => node.type === 'input' && node.props.maxLength === 3000,
+ ),
+ );
+ nodes(h.tree)
+ .filter(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ )
+ .at(-1)
+ .props.onChange({ target: { checked: true } });
+ h.render();
+ h.button('Reutilizar documento nesta pergunta').props.onClick();
+ await h.settle();
+ assert.equal(h.calls[0].body.get('document_id'), 'other-original');
+ assert.equal(h.calls[0].body.get('reuse_link_id'), 'other-dossier-link');
+ assert.equal(h.calls[0].body.has('source_reference'), false);
+ assert.equal(h.calls[0].body.has('file'), false);
+ assert.equal(h.inventory[0].select, true);
+});
+
+await test('attachment question reuses labelled documents, preserves pending drafts and enforces configured choice/format limits', () => {
+ const h = fieldHarness();
+ let tree = h.tree;
+ assert.equal(
+ nodes(tree).filter(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ )[0].props.disabled,
+ false,
+ );
+ nodes(tree)
+ .filter(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ )[0]
+ .props.onChange({ target: { checked: true } });
+ assert.deepEqual(h.changes[0], ['link-one']);
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /SYNTHETIC proof.txt/);
+ assert.match(html, /Análise ou disponibilidade pendente/);
+ assert.match(html, /2 KB por ficheiro/);
+ assert.ok(
+ !nodes(tree).some(
+ (node) =>
+ node.type === 'input' && node.props.name === 'document_id',
+ ),
+ );
+ tree = h.render({
+ value: ['link-one'],
+ documents: [
+ document,
+ {
+ ...document,
+ id: 'link-two',
+ document_id: 'document-two',
+ file_name: 'SYNTHETIC other.txt',
+ },
+ ],
+ });
+ assert.equal(
+ nodes(tree).filter(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ )[1].props.disabled,
+ true,
+ );
+ tree = h.render({
+ value: [],
+ documents: [{ ...document, media_type: 'application/pdf' }],
+ });
+ assert.equal(
+ nodes(tree).find(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ ).props.disabled,
+ true,
+ );
+ tree = h.render({
+ value: [],
+ documents: [{ ...document, media_type: null, size_bytes: null }],
+ });
+ assert.equal(
+ nodes(tree).find(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ ).props.disabled,
+ false,
+ );
+ assert.match(renderToStaticMarkup(tree), /Formato ou tamanho por conferir/);
+ assert.equal(h.render({ disabled: true }).props.disabled, true);
+});
+
+await test('document aliases render once and removing a choice removes duplicate aliases without changing another question', () => {
+ const h = fieldHarness();
+ const tree = h.render({
+ value: ['link-one', 'link-alias'],
+ documents: [document, { ...document, id: 'link-alias' }],
+ });
+ const checkboxes = nodes(tree).filter(
+ (node) => node.type === 'input' && node.props.type === 'checkbox',
+ );
+ assert.equal(checkboxes.length, 2); // One document and upload consent.
+ checkboxes[0].props.onChange({ target: { checked: false } });
+ assert.deepEqual(h.changes[0], []);
+ const inherited = values.mergeDeskPrefill(
+ { support: [] },
+ { support: ['link-one'] },
+ { support: field },
+ true,
+ );
+ assert.deepEqual(inherited.support, []);
+});
+
+await test('new support uses multipart with request, question and case version and never submits the request', async () => {
+ const h = fieldHarness();
+ h.prepare();
+ const fileInput = nodes(h.tree).find(
+ (node) => node.type === 'input' && node.props.type === 'file',
+ );
+ fileInput.props.ref.current = { value: 'selected' };
+ await h.button('Associar ficheiro a esta pergunta').props.onClick();
+ await h.settle();
+ assert.equal(h.calls.length, 1);
+ const data = h.calls[0].body;
+ assert.ok(data instanceof FormData);
+ assert.equal(data.get('field_key'), 'support');
+ assert.equal(data.get('request_id'), 'synthetic-request');
+ assert.equal(data.get('version'), '1');
+ assert.equal(data.get('source_reference'), 'SYNTHETIC submitted source');
+ assert.equal(data.get('submit'), null);
+ assert.equal(data.get('context_reviewed'), null);
+ assert.equal(h.inventory[0].select, true);
+ assert.deepEqual(h.busy, [true, false]);
+ assert.equal(fileInput.props.ref.current.value, '');
+ assert.equal(
+ h.button('Associar ficheiro a esta pergunta').props.disabled,
+ true,
+ );
+});
+
+await test('oversized file stays selected without a write and a failed upload can be retried with the original data', async () => {
+ const oversized = fieldHarness();
+ oversized.prepare(
+ new File(['X'.repeat(2049)], 'oversized.txt', { type: 'text/plain' }),
+ );
+ await oversized.button('Associar ficheiro a esta pergunta').props.onClick();
+ oversized.render();
+ assert.equal(oversized.calls.length, 0);
+ assert.match(
+ renderToStaticMarkup(oversized.tree),
+ /excede o tamanho máximo/,
+ );
+ let failed = true;
+ const h = fieldHarness(async () => {
+ if (failed) throw Error('SYNTHETIC network failure');
+ return {
+ documents: [document],
+ case_version: 2,
+ link_id: document.id,
+ reused_link: true,
+ };
+ });
+ h.prepare();
+ await h.button('Associar ficheiro a esta pergunta').props.onClick();
+ await h.settle();
+ assert.equal(
+ h.button('Associar ficheiro a esta pergunta').props.disabled,
+ false,
+ );
+ failed = false;
+ await h.button('Associar ficheiro a esta pergunta').props.onClick();
+ await h.settle();
+ assert.equal(h.calls.length, 2);
+ assert.equal(
+ h.calls[0].body.get('file').size,
+ h.calls[1].body.get('file').size,
+ );
+ assert.match(
+ renderToStaticMarkup(h.tree),
+ /Conservou-se a referência registada/,
+ );
+});
+
+await test('document refresh keeps answers on the page and a stale upload response is not treated as a confirmed selection', async () => {
+ const h = fieldHarness(async (url, body, method) =>
+ method === 'GET'
+ ? { documents: [document], caseVersion: 8 }
+ : { ok: true },
+ );
+ await h.button('Actualizar documentos disponíveis').props.onClick();
+ await h.settle();
+ assert.equal(h.inventory[0].select, false);
+ assert.equal(h.inventory[0].data.case_version, 8);
+ assert.equal(h.changes.length, 0);
+ h.prepare();
+ await h.button('Associar ficheiro a esta pergunta').props.onClick();
+ await h.settle();
+ assert.equal(h.inventory.length, 1);
+ assert.match(renderToStaticMarkup(h.tree), /não confirmou o documento/);
+ assert.equal(
+ h.button('Associar ficheiro a esta pergunta').props.disabled,
+ false,
+ );
+});
+
+await test('the common transport keeps multipart boundaries with the browser and preserves existing JSON and CSRF behaviour', async () => {
+ const sent = [];
+ const api = load(
+ '../../resources/js/lib/profile-json.ts',
+ {},
+ {
+ document: { cookie: 'XSRF-TOKEN=synthetic%3Dtoken' },
+ fetch: async (url, options) => {
+ sent.push(options);
+ return new Response(JSON.stringify({ ok: true }), {
+ status: 200,
+ });
+ },
+ },
+ );
+ const data = new FormData();
+ data.set(
+ 'file',
+ new File(['SYNTHETIC'], 'proof.txt', { type: 'text/plain' }),
+ );
+ await api.profileJson('/synthetic-upload', data);
+ assert.equal(sent[0].body, data);
+ assert.equal(sent[0].headers['Content-Type'], undefined);
+ assert.equal(sent[0].headers['X-XSRF-TOKEN'], 'synthetic=token');
+ assert.equal(sent[0].credentials, 'same-origin');
+ await api.profileJson('/synthetic-json', { answer: 0 });
+ assert.equal(sent[1].body, '{"answer":0}');
+ assert.equal(sent[1].headers['Content-Type'], 'application/json');
+});
+
+await test('owner reuse chooses the precise registered source without asking for its reference again or sending another file', async () => {
+ const sourceB = {
+ ...document,
+ id: 'source-b',
+ document_id: 'shared-original',
+ source_reference: 'SYNTHETIC ref B',
+ stage: 'E1',
+ valid_until: '2027-01-02',
+ };
+ const sourceC = {
+ ...sourceB,
+ id: 'source-c',
+ source_reference: 'SYNTHETIC ref C',
+ stage: 'E2',
+ };
+ const target = { ...sourceB, id: 'new-use' };
+ const h = fieldHarness(async () => ({
+ documents: [target],
+ case_version: 4,
+ link_id: target.id,
+ reusable_documents: [sourceB, sourceC, target],
+ }));
+ h.render({ documents: [], reusableDocuments: [sourceB, sourceC] });
+ let select = nodes(h.tree).find((node) => node.type === 'select');
+ assert.equal(
+ nodes(select).filter((node) => node.type === 'option').length,
+ 3,
+ );
+ select.props.onChange({ target: { value: 'source-b' } });
+ h.render();
+ assert.ok(
+ !nodes(h.tree).some(
+ (node) => node.type === 'input' && node.props.type === 'file',
+ ),
+ );
+ assert.ok(
+ !nodes(h.tree).some(
+ (node) => node.type === 'input' && node.props.maxLength === 3000,
+ ),
+ );
+ assert.match(
+ renderToStaticMarkup(h.tree),
+ /Referência já registada: SYNTHETIC ref B/,
+ );
+ nodes(h.tree)
+ .find((node) => node.type === 'input' && node.props.type === 'checkbox')
+ .props.onChange({ target: { checked: true } });
+ h.render();
+ await h.button('Reutilizar documento nesta pergunta').props.onClick();
+ await h.settle();
+ const data = h.calls[0].body;
+ assert.equal(data.get('document_id'), 'shared-original');
+ assert.equal(data.get('reuse_link_id'), 'source-b');
+ assert.equal(data.get('source_reference'), null);
+ assert.equal(data.get('file'), null);
+ assert.equal(h.inventory[0].select, true);
+});
+
+await test('editor publishes explicit attachment limits in the proposed version and clears unrelated metadata when type changes', () => {
+ let form;
+ const Editor = load(
+ '../../resources/js/pages/desk/service-editor.tsx',
+ {
+ react: { useState: (value) => [value, () => {}] },
+ '@inertiajs/react': {
+ Link: 'a',
+ useForm(key, initial) {
+ form ??= {
+ data: initial,
+ errors: {},
+ processing: false,
+ setData(value) {
+ this.data = value(this.data);
+ },
+ };
+ return form;
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/desk-service-history': { default: () => null },
+ },
+ {},
+ '\nexport { Editor };',
+ ).Editor;
+ const service = {
+ code: 'synthetic',
+ version: 1,
+ definition: {
+ title: 'SYNTHETIC',
+ theme: 'Synthetic',
+ profile: 'Investor',
+ entity: 'Internal',
+ result: 'Internal preparation',
+ stage: 'E10',
+ fields: {
+ question: {
+ label: 'SYNTHETIC support',
+ type: 'text',
+ required: false,
+ },
+ },
+ },
+ };
+ const render = () => Editor({ service });
+ let tree = render();
+ const type = () =>
+ nodes(tree).find(
+ (node) =>
+ node.type === 'select' &&
+ nodes(node).some(
+ (child) =>
+ child.type === 'option' &&
+ child.props.value === 'attachment',
+ ),
+ );
+ type().props.onChange({ target: { value: 'attachment' } });
+ tree = render();
+ assert.equal(form.data.definition.fields.question.max_files, 1);
+ assert.equal(form.data.definition.fields.question.max_size_kb, 10240);
+ assert.equal(form.data.definition.fields.question.mime_types.length, 4);
+ assert.equal(form.data.definition.fields.question.required, false);
+ const size = nodes(tree).find(
+ (node) => node.type === 'input' && node.props.max === 10240,
+ );
+ size.props.onChange({ target: { value: '256' } });
+ tree = render();
+ assert.equal(form.data.definition.fields.question.max_size_kb, 256);
+ assert.equal(form.data.confirm, false);
+ assert.match(renderToStaticMarkup(tree), /Tamanho por ficheiro: 256 KiB/);
+ type().props.onChange({ target: { value: 'text' } });
+ assert.equal(form.data.definition.fields.question.mime_types, undefined);
+ assert.equal(form.data.definition.fields.question.max_files, undefined);
+ assert.equal(service.definition.fields.question.type, 'text');
+});
diff --git a/tests/frontend/desk-case-state.test.mjs b/tests/frontend/desk-case-state.test.mjs
new file mode 100644
index 00000000..69ea4319
--- /dev/null
+++ b/tests/frontend/desk-case-state.test.mjs
@@ -0,0 +1,278 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports.default;
+}
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const text = (tree) =>
+ typeof tree === 'string'
+ ? tree
+ : Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'number'
+ ? String(tree)
+ : '';
+function harness(file, initial, extra = {}) {
+ const forms = [],
+ cells = [],
+ calls = [];
+ let formCursor = 0,
+ cursor = 0,
+ serial = 0,
+ tree,
+ props = initial;
+ const Empty = () => null;
+ const Component = load(file, {
+ react: {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) => {
+ cells[i] = value;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { reload() {} },
+ usePage: () => ({
+ url: '/synthetic',
+ props: { auth: { user: { id: 1 } } },
+ }),
+ useForm(initial) {
+ const i = formCursor++;
+ forms[i] ??= {
+ data: { ...initial },
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data[key] = value;
+ },
+ reset(...keys) {
+ for (const key of keys) this.data[key] = initial[key];
+ },
+ put(url, options) {
+ calls.push({ url, options, data: { ...this.data } });
+ },
+ };
+ return forms[i];
+ },
+ },
+ '@/lib/operation-key': {
+ createOperationKey: () => `SYNTHETIC-${++serial}`,
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/investor-guidance': { InvestorGuidance: Empty },
+ '@/components/desk-internal-operations': { DocumentReview: Empty },
+ '@/components/desk-document-picker': { default: Empty },
+ ...extra,
+ });
+ function render(patch = {}) {
+ props = { ...props, ...patch };
+ cursor = 0;
+ formCursor = 0;
+ tree = Component(props);
+ }
+ render();
+ return {
+ forms,
+ calls,
+ render,
+ all: () => nodes(tree),
+ text: () => text(tree),
+ find: (type, label) =>
+ nodes(tree).find(
+ (n) => n.type === type && (!label || text(n).includes(label)),
+ ),
+ submit() {
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ },
+ };
+}
+const dossier = { id: 'case-one', version: 1, closed_at: null };
+const activity = { open_requests: 2, open_tasks: 1, pending_payments: 3 };
+const state = (extra) =>
+ harness('../../resources/js/components/desk-case-state-form.tsx', {
+ dossier,
+ activity,
+ ...extra,
+ });
+
+test('owner can explicitly close with recorded pending items and sends only state decision data', () => {
+ const h = state();
+ h.find('textarea').props.onChange({
+ target: { value: 'SYNTHETIC owner reason' },
+ });
+ h.render();
+ h.submit();
+ assert.match(h.calls[0].url, /dossiers\/case-one\/estado$/);
+ assert.deepEqual(
+ Object.keys(h.calls[0].data).sort(),
+ ['version', 'state', 'reason', 'client_key'].sort(),
+ );
+ assert.equal(h.calls[0].data.state, 'closed');
+ assert.equal(h.calls[0].data.version, 1);
+ assert.match(
+ h.text(),
+ /Pedidos em curso: 2.*tarefas em curso: 1.*comprovativos por conferir: 3/,
+ );
+});
+
+test('success adopts actual server state and version for reopening and calls parent cleanup only for the same dossier', () => {
+ let changed = 0;
+ const h = state({
+ onChanged() {
+ changed++;
+ },
+ });
+ h.find('textarea').props.onChange({
+ target: { value: 'SYNTHETIC close reason' },
+ });
+ h.render();
+ h.submit();
+ const key = h.forms[0].data.client_key;
+ h.calls[0].options.onSuccess({
+ props: { case: { ...dossier, version: 2, closed_at: '2026-11-03' } },
+ });
+ h.render({ dossier: { ...dossier, version: 2, closed_at: '2026-11-03' } });
+ assert.equal(h.forms[0].data.state, 'open');
+ assert.equal(h.forms[0].data.version, 2);
+ assert.equal(h.forms[0].data.reason, '');
+ assert.notEqual(h.forms[0].data.client_key, key);
+ assert.equal(changed, 1);
+ h.calls[0].options.onSuccess({
+ props: { case: { id: 'other-case', version: 9 } },
+ });
+ assert.equal(changed, 1);
+ assert.ok(h.find('button', 'Confirmar reabertura'));
+});
+
+test('failed retry keeps operation identity and reason while editing or explicitly adopting new state starts a new intent', () => {
+ const h = state();
+ h.find('textarea').props.onChange({
+ target: { value: 'SYNTHETIC deliberate reason' },
+ });
+ h.render();
+ h.submit();
+ h.submit();
+ assert.deepEqual(h.calls[0].data, h.calls[1].data);
+ const key = h.forms[0].data.client_key;
+ h.render({ dossier: { ...dossier, version: 3, closed_at: '2026-11-03' } });
+ assert.equal(h.find('button', 'Confirmar reabertura').props.disabled, true);
+ h.submit();
+ assert.equal(h.calls.length, 2);
+ h.find('button', 'Usar estado actual').props.onClick();
+ h.render();
+ assert.equal(h.forms[0].data.version, 3);
+ assert.equal(h.forms[0].data.state, 'open');
+ assert.equal(h.forms[0].data.reason, 'SYNTHETIC deliberate reason');
+ assert.notEqual(h.forms[0].data.client_key, key);
+});
+
+test('unknown optional counts remain unknown and in-flight business work disables the decision', () => {
+ const h = state({
+ activity: {
+ open_requests: 0,
+ open_tasks: null,
+ pending_payments: null,
+ },
+ disabled: true,
+ });
+ assert.match(
+ h.text(),
+ /Pedidos em curso: 0.*tarefas em curso: por confirmar.*comprovativos por conferir: por confirmar/,
+ );
+ assert.equal(
+ h.find('button', 'Confirmar encerramento').props.disabled,
+ true,
+ );
+ h.submit();
+ assert.equal(h.calls.length, 0);
+});
+
+test('case exposes owner control separately from ordinary writing and clears unassociated file consent after success', () => {
+ const State = () => null;
+ const base = {
+ case: {
+ ...dossier,
+ closed_at: '2026-11-03',
+ title: 'SYNTHETIC owner dossier',
+ workflow: {},
+ },
+ canWrite: false,
+ canChangeState: true,
+ activity,
+ manager: false,
+ requests: [],
+ services: [],
+ documents: [],
+ workflow: {},
+ stepStates: {},
+ states: {},
+ guidance: null,
+ events: [],
+ links: [],
+ legacyRequest: null,
+ };
+ const h = harness('../../resources/js/pages/desk/case.tsx', base, {
+ '@/components/desk-case-state-form': { default: State },
+ });
+ let widget = h.all().find((n) => n.type === State);
+ assert.ok(widget);
+ h.forms[2].setData('file', { name: 'SYNTHETIC unsent file' });
+ h.forms[2].setData('consent', true);
+ widget.props.onChanged();
+ assert.equal(h.forms[2].data.file, null);
+ assert.equal(h.forms[2].data.consent, false);
+ h.forms[2].processing = true;
+ h.render();
+ widget = h.all().find((n) => n.type === State);
+ assert.equal(widget.props.disabled, true);
+ h.render({ canChangeState: false, canWrite: true, manager: true });
+ assert.equal(
+ h.all().some((n) => n.type === State),
+ false,
+ );
+});
diff --git a/tests/frontend/desk-checkpoints.test.mjs b/tests/frontend/desk-checkpoints.test.mjs
new file mode 100644
index 00000000..86cb6ef8
--- /dev/null
+++ b/tests/frontend/desk-checkpoints.test.mjs
@@ -0,0 +1,778 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, globals = {}) {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, [
+ 'require',
+ 'module',
+ 'exports',
+ ...Object.keys(globals),
+ ])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ ...Object.values(globals),
+ );
+ return module.exports;
+}
+const lib = load('../../resources/js/lib/desk-checkpoints.ts');
+class ValidationError extends Error {
+ constructor(message, fields = {}) {
+ super(message);
+ this.fields = fields;
+ }
+}
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const request = {
+ id: 'synthetic-request',
+ version: 1,
+ status: 'draft',
+ payload: { title: 'Original', choices: ['0'], declaration: null },
+ editable_fields: [],
+ can_edit: true,
+ protocol: null,
+ analyst_id: null,
+ due_at: null,
+};
+const initialView = () => ({
+ installed: true,
+ request: structuredClone(request),
+ checkpoint: null,
+});
+function serverCheckpoint(body) {
+ return {
+ version: body.version + 1,
+ request_version: body.request_version,
+ updated_at: '2026-11-03T03:00:00Z',
+ payload: structuredClone(body.payload),
+ reason: body.reason,
+ base_payload: structuredClone(request.payload),
+ edited_keys: [...body.edited_keys],
+ };
+}
+function harness(handler) {
+ const cells = [],
+ timers = new Map(),
+ listeners = new Map(),
+ before = [];
+ let cursor = 0,
+ dirty = true,
+ tree,
+ props,
+ sequence = 0,
+ clock = 0;
+ const effects = [],
+ calls = [],
+ recovered = [],
+ blocked = [],
+ busy = [];
+ const react = {
+ useState(initial) {
+ const i = cursor++;
+ if (!cells[i])
+ cells[i] = {
+ value: typeof initial === 'function' ? initial() : initial,
+ };
+ return [
+ cells[i].value,
+ (value) => {
+ const next =
+ typeof value === 'function'
+ ? value(cells[i].value)
+ : value;
+ if (!Object.is(next, cells[i].value)) {
+ cells[i].value = next;
+ dirty = true;
+ }
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ useEffect(effect, deps) {
+ const i = cursor++,
+ old = cells[i];
+ if (!old || deps.some((v, j) => !Object.is(v, old.deps[j]))) {
+ cells[i] = { deps, cleanup: old?.cleanup };
+ effects.push(() => {
+ cells[i].cleanup?.();
+ cells[i].cleanup = effect();
+ });
+ }
+ },
+ };
+ const Component = load(
+ '../../resources/js/components/desk-draft-recovery.tsx',
+ {
+ react,
+ '@inertiajs/react': {
+ router: {
+ on(name, callback) {
+ before.push(callback);
+ return () => {
+ before.splice(before.indexOf(callback), 1);
+ };
+ },
+ },
+ },
+ '@/lib/profile-json': {
+ ProfileValidationError: ValidationError,
+ async profileJson(url, body = {}, method = 'POST') {
+ calls.push({ url, body: structuredClone(body), method });
+ return handler(url, body, method);
+ },
+ },
+ '@/lib/operation-key': {
+ createOperationKey: () => `synthetic-operation-${++sequence}`,
+ },
+ '@/lib/desk-checkpoints': lib,
+ },
+ {
+ window: {
+ addEventListener: (name, fn) => listeners.set(name, fn),
+ removeEventListener: (name) => listeners.delete(name),
+ confirm: () => false,
+ },
+ setTimeout: (fn) => {
+ const id = ++clock;
+ timers.set(id, fn);
+ return id;
+ },
+ clearTimeout: (id) => timers.delete(id),
+ },
+ ).default;
+ props = {
+ id: request.id,
+ version: 1,
+ initial: structuredClone(request.payload),
+ payload: structuredClone(request.payload),
+ reason: '',
+ fields: {
+ title: { label: 'Title' },
+ choices: { label: 'Choices' },
+ declaration: { label: 'Declaration' },
+ },
+ paused: false,
+ onBusy: (value) => busy.push(value),
+ onBlocked: (value) => blocked.push(value),
+ onRecover: (payload, reason, current) => {
+ recovered.push({ payload, reason, current });
+ props = { ...props, payload, reason, version: current.version };
+ dirty = true;
+ },
+ };
+ function render(patch = {}) {
+ props = { ...props, ...patch };
+ dirty = true;
+ flush();
+ return tree;
+ }
+ function flush() {
+ let loops = 0;
+ while (dirty || effects.length) {
+ if (++loops > 25) throw Error('Effect loop');
+ if (dirty) {
+ dirty = false;
+ cursor = 0;
+ tree = Component(props);
+ }
+ while (effects.length) effects.shift()();
+ }
+ return tree;
+ }
+ async function settle() {
+ for (let i = 0; i < 10; i++) {
+ await Promise.resolve();
+ flush();
+ }
+ return tree;
+ }
+ return {
+ render,
+ settle,
+ calls,
+ recovered,
+ blocked,
+ busy,
+ listeners,
+ before,
+ timers,
+ get tree() {
+ return tree;
+ },
+ get props() {
+ return props;
+ },
+ async advance() {
+ for (const [id, fn] of timers) {
+ timers.delete(id);
+ fn();
+ }
+ await settle();
+ },
+ button(label) {
+ const node = nodes(tree).find(
+ (n) => n.type === 'button' && n.props.children === label,
+ );
+ assert.ok(node, `Button missing: ${label}`);
+ return node;
+ },
+ unmount() {
+ for (const cell of cells) cell?.cleanup?.();
+ },
+ };
+}
+
+await test('recovery preserves typed choices, explicit zero and deliberate reverts; concurrent answers require a choice', () => {
+ const base = {
+ title: 'Original',
+ amount: 0,
+ choices: ['0'],
+ declaration: 'declined',
+ };
+ const saved = {
+ base_payload: base,
+ payload: { ...base, title: 'Saved', choices: ['cotton', '0'] },
+ edited_keys: ['title', 'choices', 'declaration'],
+ };
+ const current = { ...base, title: 'External', declaration: 'accepted' };
+ const result = lib.checkpointRecovery(
+ base,
+ base,
+ [],
+ current,
+ saved,
+ Object.keys(base),
+ );
+ assert.deepEqual(result.conflicts, ['title', 'declaration']);
+ const chosen = lib.checkpointRecovery(
+ base,
+ base,
+ [],
+ current,
+ saved,
+ Object.keys(base),
+ { title: 'current', declaration: 'saved' },
+ );
+ assert.deepEqual(chosen.conflicts, []);
+ assert.equal(chosen.payload.title, 'External');
+ assert.equal(chosen.payload.declaration, 'declined');
+ assert.equal(chosen.payload.amount, 0);
+ assert.deepEqual(chosen.payload.choices, ['cotton', '0']);
+ const returned = lib.checkpointRecovery(
+ base,
+ { ...base, title: 'Forbidden' },
+ ['title'],
+ current,
+ saved,
+ ['amount'],
+ );
+ assert.equal(returned.payload.title, 'External');
+ assert.equal(
+ lib.checkpointSignature({ choices: ['0', 'cotton'] }),
+ lib.checkpointSignature({ choices: ['cotton', '0'] }),
+ );
+});
+
+await test('opportunity and its preserved context are recovered as one choice without displaying technical snapshots', () => {
+ const base = {
+ context_opportunity: 'old',
+ context_opportunity_snapshot: JSON.stringify({
+ choice: { opportunity: { title: 'Old opportunity' } },
+ revision: 1,
+ }),
+ context_reuse: 'old metadata',
+ };
+ const page = {
+ context_opportunity: 'local',
+ context_opportunity_snapshot: JSON.stringify({
+ choice: { opportunity: { title: 'Local opportunity' } },
+ revision: 2,
+ }),
+ context_reuse: 'local metadata',
+ };
+ const current = {
+ context_opportunity: 'remote',
+ context_opportunity_snapshot: JSON.stringify({
+ choice: { opportunity: { title: 'Remote opportunity' } },
+ revision: 3,
+ }),
+ context_reuse: 'remote metadata',
+ };
+ const result = lib.checkpointRecovery(
+ base,
+ page,
+ Object.keys(page),
+ current,
+ null,
+ Object.keys(page),
+ { context_opportunity: 'page' },
+ );
+ assert.deepEqual(result.payload, page);
+ assert.equal(result.rows.length, 1);
+ assert.equal(result.rows[0].page, 'Local opportunity · revisão 2');
+ assert.deepEqual(result.intent, Object.keys(page));
+ assert.ok(!JSON.stringify(result.rows).includes('local metadata'));
+});
+
+await test('autosave is debounced, captures edits during a pending write and never sends submission or consent flags', async () => {
+ let view = initialView(),
+ resolveFirst;
+ const h = harness(async (url, body, method) => {
+ if (method === 'GET') return structuredClone(view);
+ if (!resolveFirst)
+ return new Promise((resolve) => {
+ resolveFirst = () => {
+ view.checkpoint = serverCheckpoint(body);
+ resolve(structuredClone(view));
+ };
+ });
+ view.checkpoint = serverCheckpoint(body);
+ return structuredClone(view);
+ });
+ h.render();
+ await h.settle();
+ assert.equal(h.timers.size, 0);
+ h.render({ payload: { ...request.payload, title: 'First' } });
+ assert.equal(h.timers.size, 1);
+ await h.advance();
+ assert.equal(h.calls.filter((c) => c.method === 'POST').length, 1);
+ h.render({ payload: { ...request.payload, title: 'Newer while saving' } });
+ assert.equal(h.timers.size, 0);
+ resolveFirst();
+ await h.settle();
+ assert.equal(h.timers.size, 1);
+ await h.advance();
+ const posts = h.calls.filter((c) => c.method === 'POST');
+ assert.equal(posts.length, 2);
+ assert.equal(posts[1].body.version, 1);
+ assert.equal(posts[1].body.payload.title, 'Newer while saving');
+ assert.equal(Object.hasOwn(posts[0].body, 'submit'), false);
+ assert.equal(Object.hasOwn(posts[0].body, 'consent'), false);
+ assert.equal(Object.hasOwn(posts[0].body, 'context_reviewed'), false);
+ assert.equal(h.timers.size, 0);
+ assert.deepEqual(h.busy, [true, false, true, false]);
+ h.unmount();
+});
+
+await test('ambiguous network failure repeats the exact attempt before saving newer local answers', async () => {
+ let view = initialView(),
+ failed = false;
+ const h = harness(async (url, body, method) => {
+ if (method === 'GET') return structuredClone(view);
+ if (!failed) {
+ failed = true;
+ view.checkpoint = serverCheckpoint(body);
+ throw Error('SYNTHETIC connection lost after commit');
+ }
+ if (body.version === 0) return structuredClone(view);
+ view.checkpoint = serverCheckpoint(body);
+ return structuredClone(view);
+ });
+ h.render();
+ await h.settle();
+ h.render({
+ payload: { ...request.payload, title: 'Committed but unacknowledged' },
+ });
+ await h.advance();
+ h.render({ payload: { ...request.payload, title: 'Newer' } });
+ assert.equal(h.timers.size, 0);
+ h.button('Tentar novamente a mesma gravação').props.onClick();
+ await h.settle();
+ let posts = h.calls.filter((c) => c.method === 'POST');
+ assert.deepEqual(posts[0].body, posts[1].body);
+ assert.equal(h.props.payload.title, 'Newer');
+ await h.advance();
+ posts = h.calls.filter((c) => c.method === 'POST');
+ assert.equal(posts[2].body.version, 1);
+ assert.notEqual(posts[2].body.operation_key, posts[1].body.operation_key);
+ h.unmount();
+});
+
+await test('server normalization does not cause autosave loops and validation failures wait for an actual edit', async () => {
+ let view = initialView(),
+ invalid = true;
+ const h = harness(async (url, body, method) => {
+ if (method === 'GET') return structuredClone(view);
+ if (invalid)
+ throw new ValidationError('SYNTHETIC invalid type', {
+ 'checkpoint.payload.title': 'Invalid',
+ });
+ view.checkpoint = serverCheckpoint(body);
+ view.checkpoint.payload.title = body.payload.title.trim() || null;
+ return structuredClone(view);
+ });
+ h.render();
+ await h.settle();
+ h.render({ payload: { ...request.payload, title: ' text ' } });
+ await h.advance();
+ await h.settle();
+ assert.equal(h.timers.size, 0);
+ invalid = false;
+ h.render({ payload: { ...request.payload, title: ' corrected ' } });
+ await h.settle();
+ assert.equal(h.timers.size, 1);
+ await h.advance();
+ assert.equal(h.timers.size, 0);
+ assert.equal(h.calls.filter((c) => c.method === 'POST').length, 2);
+ h.unmount();
+});
+
+await test('stored drafts are compared before adoption and a failed recovery is retried without changing its chosen answers', async () => {
+ let view = initialView(),
+ failed = false;
+ view.request.version = 2;
+ view.request.payload.title = 'External';
+ view.checkpoint = {
+ ...serverCheckpoint({
+ version: 0,
+ request_version: 1,
+ payload: {
+ ...request.payload,
+ title: 'Saved',
+ declaration: 'declined',
+ },
+ reason: 'Saved reason',
+ edited_keys: ['title', 'declaration'],
+ }),
+ base_payload: structuredClone(request.payload),
+ };
+ const h = harness(async (url, body, method) => {
+ if (method === 'GET') return structuredClone(view);
+ view.checkpoint = serverCheckpoint(body);
+ if (!failed) {
+ failed = true;
+ throw Error('SYNTHETIC recovery response lost');
+ }
+ return structuredClone(view);
+ });
+ h.render();
+ await h.settle();
+ assert.equal(h.recovered.length, 0);
+ assert.equal(
+ h.button('Recuperar as respostas escolhidas').props.disabled,
+ true,
+ );
+ const select = nodes(h.tree).find(
+ (n) => n.type === 'select' && n.props.value === '',
+ );
+ select.props.onChange({ target: { value: 'saved' } });
+ await h.settle();
+ assert.equal(
+ h.button('Recuperar as respostas escolhidas').props.disabled,
+ false,
+ );
+ h.button('Recuperar as respostas escolhidas').props.onClick();
+ await h.settle();
+ assert.equal(h.recovered.length, 0);
+ h.button('Recuperar as respostas escolhidas').props.onClick();
+ await h.settle();
+ assert.equal(h.recovered.length, 1);
+ assert.equal(h.recovered[0].current.version, 2);
+ assert.equal(h.recovered[0].payload.title, 'Saved');
+ assert.equal(h.recovered[0].payload.declaration, 'declined');
+ const posts = h.calls.filter((c) => c.method === 'POST');
+ assert.deepEqual(posts[0].body, posts[1].body);
+ assert.equal(h.blocked.at(-1), false);
+ h.unmount();
+});
+
+await test('manual operations pause autosave, unavailable installation leaves manual access, and unsaved navigation can be cancelled', async () => {
+ let view = initialView();
+ const h = harness(async (url, body, method) => {
+ if (method === 'GET') return structuredClone(view);
+ view.checkpoint = serverCheckpoint(body);
+ return structuredClone(view);
+ });
+ h.render();
+ await h.settle();
+ h.render({
+ payload: { ...request.payload, title: 'Unsaved' },
+ paused: true,
+ });
+ assert.equal(h.timers.size, 0);
+ let prevented = false;
+ h.before[0]({
+ detail: { visit: { method: 'get' } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ assert.equal(prevented, true);
+ h.render({ paused: false });
+ await h.advance();
+ assert.equal(h.timers.size, 0);
+ h.unmount();
+ assert.equal(h.before.length, 0);
+ assert.equal(h.listeners.size, 0);
+ view.installed = false;
+ const fallback = harness(async () => structuredClone(view));
+ fallback.render();
+ await fallback.settle();
+ fallback.render({ payload: { title: 'Manual still available' } });
+ assert.equal(fallback.timers.size, 0);
+ assert.ok(!fallback.blocked.includes(true));
+ fallback.unmount();
+});
+
+await test('request recovery adopts the actual server version and returned scope while clearing submission and context approvals', () => {
+ const cells = [],
+ forms = [],
+ sent = [];
+ let stateCursor = 0,
+ formCursor = 0;
+ const Empty = () => null,
+ Recovery = () => null,
+ Attachment = () => null;
+ const Page = load('../../resources/js/pages/desk/request.tsx', {
+ react: {
+ useState(initial) {
+ const i = stateCursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) =>
+ (cells[i] =
+ typeof value === 'function'
+ ? value(cells[i])
+ : value),
+ ];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ useForm(initial) {
+ const i = formCursor++;
+ forms[i] ??= {
+ data: structuredClone(initial),
+ errors: {},
+ processing: false,
+ setData(value, next) {
+ this.data =
+ typeof value === 'function'
+ ? value(this.data)
+ : { ...this.data, [value]: next };
+ },
+ transform(fn) {
+ this.mapping = fn;
+ },
+ put(url) {
+ sent.push({
+ url,
+ data: this.mapping
+ ? this.mapping(this.data)
+ : this.data,
+ });
+ },
+ };
+ return forms[i];
+ },
+ },
+ '@/components/desk-draft-recovery': {
+ __esModule: true,
+ default: Recovery,
+ },
+ '@/components/dossier-prefill': { DossierPrefill: Empty },
+ '@/components/country-select': { default: Empty },
+ '@/components/investment-territory': { TerritoryFields: Empty },
+ '@/components/desk-internal-operations': {
+ DocumentReview: Empty,
+ RequestOperations: Empty,
+ },
+ '@/components/desk-typed-choice': { default: Empty },
+ '@/components/desk-attachment-field': { default: Attachment },
+ '@/lib/operation-key': { createOperationKey: () => 'synthetic' },
+ '@/lib/desk-field-visibility': load(
+ '../../resources/js/lib/desk-field-visibility.ts',
+ ),
+ '@/lib/desk-field-values': load(
+ '../../resources/js/lib/desk-field-values.ts',
+ ),
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ }).default;
+ const props = {
+ request: { ...request, analyst_id: null, due_at: null },
+ case: { id: 'synthetic-case', title: 'Synthetic' },
+ definition: {
+ title: 'Synthetic',
+ result: 'Internal',
+ fields: {
+ title: { type: 'text', label: 'Title', required: true },
+ support: {
+ type: 'attachment',
+ label: 'Support',
+ required: false,
+ max_files: 2,
+ max_size_kb: 2,
+ mime_types: ['text/plain'],
+ },
+ choices: {
+ type: 'multiselect',
+ label: 'Choices',
+ required: false,
+ options: { 0: 'Zero' },
+ },
+ declaration: {
+ type: 'consent',
+ label: 'Declaration',
+ required: false,
+ statement: 'Synthetic',
+ },
+ },
+ },
+ owner: true,
+ manager: false,
+ analyst: false,
+ fieldsEditable: true,
+ states: { draft: 'Draft', returned: 'Returned' },
+ transitions: [],
+ findings: [],
+ messages: [],
+ analysts: [],
+ territoryPaths: {},
+ events: [],
+ documents: [],
+ payments: [],
+ caseVersion: 1,
+ countries: [],
+ toolPrefill: null,
+ };
+ const render = () => {
+ stateCursor = 0;
+ formCursor = 0;
+ return Page(props);
+ };
+ let tree = render();
+ forms[0].data.payload.title = 'Deliberate edit during upload';
+ nodes(tree)
+ .find((n) => n.type === Attachment)
+ .props.onBusy(true);
+ tree = render();
+ assert.equal(
+ nodes(tree).find((n) => n.type === Recovery).props.pendingWork,
+ true,
+ );
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ assert.equal(sent.length, 0);
+ const uploaded = {
+ id: 'link-first',
+ document_id: 'binary-one',
+ file_name: 'Synthetic original',
+ status: 'quarantined',
+ malware_scan_status: 'pending',
+ };
+ nodes(tree)
+ .find((n) => n.type === Attachment)
+ .props.onInventory(
+ { documents: [uploaded], case_version: 2, link_id: uploaded.id },
+ true,
+ );
+ nodes(tree)
+ .find((n) => n.type === Attachment)
+ .props.onBusy(false);
+ tree = render();
+ assert.equal(forms[0].data.payload.title, 'Deliberate edit during upload');
+ assert.deepEqual(forms[0].data.payload.support, ['link-first']);
+ const alias = { ...uploaded, id: 'link-alias' };
+ nodes(tree)
+ .find((n) => n.type === Attachment)
+ .props.onInventory(
+ {
+ documents: [uploaded, alias],
+ case_version: 2,
+ link_id: alias.id,
+ },
+ true,
+ );
+ tree = render();
+ assert.deepEqual(forms[0].data.payload.support, ['link-first']);
+ props.caseVersion = 2;
+ props.documents = [
+ { ...uploaded, status: 'active', malware_scan_status: 'clean' },
+ ];
+ tree = render();
+ assert.equal(
+ nodes(tree).find((n) => n.type === Attachment).props.documents[0]
+ .malware_scan_status,
+ 'clean',
+ );
+ const refreshed = {
+ ...uploaded,
+ malware_scan_status: 'synthetic-new-status',
+ };
+ nodes(tree)
+ .find((n) => n.type === Attachment)
+ .props.onInventory({ documents: [refreshed], case_version: 2 }, false);
+ tree = render();
+ assert.equal(
+ nodes(tree).find((n) => n.type === Attachment).props.documents[0]
+ .malware_scan_status,
+ 'synthetic-new-status',
+ );
+ forms[0].data.consent = true;
+ forms[0].data.context_reviewed = true;
+ forms[0].data.context_revision = 8;
+ const restore = nodes(tree).find((n) => n.type === Recovery);
+ restore.props.onRecover(
+ {
+ title: 'Current official draft',
+ choices: ['0'],
+ declaration: 'declined',
+ },
+ 'Recovered reason',
+ {
+ ...request,
+ version: 3,
+ status: 'returned',
+ editable_fields: ['choices'],
+ },
+ );
+ tree = render();
+ assert.equal(forms[0].data.version, 3);
+ assert.equal(forms[0].data.consent, false);
+ assert.equal(forms[0].data.context_reviewed, false);
+ assert.equal(forms[0].data.context_revision, 0);
+ assert.equal(forms[0].data.payload.declaration, 'declined');
+ const form = nodes(tree).find((n) => n.type === 'form');
+ form.props.onSubmit({ preventDefault() {} });
+ assert.equal(sent[0].data.version, 3);
+ assert.equal(sent[0].data.submit, false);
+ nodes(tree)
+ .find((n) => n.type === Recovery)
+ .props.onBusy(true);
+ tree = render();
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ assert.equal(sent.length, 1);
+});
diff --git a/tests/frontend/desk-closed-lifecycle.test.mjs b/tests/frontend/desk-closed-lifecycle.test.mjs
new file mode 100644
index 00000000..1002a396
--- /dev/null
+++ b/tests/frontend/desk-closed-lifecycle.test.mjs
@@ -0,0 +1,453 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, suffix = '') {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const text = (tree) =>
+ typeof tree === 'string'
+ ? tree
+ : Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'number'
+ ? String(tree)
+ : '';
+const Empty = () => null;
+function harness(file, initial, extra = {}, suffix = '') {
+ const cells = [],
+ forms = [],
+ sent = [];
+ let cursor = 0,
+ formCursor = 0,
+ props = initial,
+ tree;
+ const mocks = {
+ react: {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) => {
+ cells[i] =
+ typeof value === 'function'
+ ? value(cells[i])
+ : value;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { reload() {}, post() {} },
+ usePage: () => ({
+ url: '/synthetic',
+ props: { auth: { user: { id: 1 } } },
+ }),
+ useForm(initial) {
+ const i = formCursor++;
+ forms[i] ??= {
+ data: structuredClone(initial),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ if (typeof key === 'function')
+ this.data = key(this.data);
+ else if (typeof key === 'object') this.data = key;
+ else this.data[key] = value;
+ },
+ clearErrors() {},
+ setDefaults() {},
+ transform(callback) {
+ this.transformer = callback;
+ },
+ post(url, options) {
+ sent.push({
+ url,
+ options,
+ data: this.transformer
+ ? this.transformer(this.data)
+ : this.data,
+ });
+ },
+ patch(url, options) {
+ sent.push({ url, options, data: this.data });
+ },
+ };
+ return forms[i];
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/lib/operation-key': {
+ createOperationKey: () => 'synthetic-operation',
+ },
+ '@/lib/desk-field-values': load(
+ '../../resources/js/lib/desk-field-values.ts',
+ ),
+ '@/lib/desk-field-visibility': load(
+ '../../resources/js/lib/desk-field-visibility.ts',
+ ),
+ '@/components/dossier-prefill': { DossierPrefill: Empty },
+ '@/components/desk-typed-choice': { default: Empty },
+ '@/components/desk-draft-recovery': { default: Empty },
+ '@/components/desk-attachment-field': { default: Empty },
+ '@/components/country-select': { default: Empty },
+ '@/components/investment-territory': { TerritoryFields: Empty },
+ '@/components/desk-internal-operations': {
+ DocumentReview: Empty,
+ RequestOperations: Empty,
+ },
+ '@/components/investor-guidance': { InvestorGuidance: Empty },
+ '@/components/desk-case-state-form': { default: Empty },
+ '@/components/desk-document-picker': { default: Empty },
+ ...extra,
+ };
+ mocks['@/lib/crm-record-edit'] = load(
+ '../../resources/js/lib/crm-record-edit.ts',
+ mocks,
+ );
+ mocks['@/components/crm-edit-comparison'] = { default: Empty };
+ mocks['@/components/crm-task-creation'] = { default: Empty };
+ const exports = load(file, mocks, suffix);
+ const Component =
+ exports.TaskRow ?? exports.default ?? exports.InvestorGuidance;
+ function render(patch = {}) {
+ props = { ...props, ...patch };
+ cursor = 0;
+ formCursor = 0;
+ tree = Component(props);
+ }
+ render();
+ return {
+ forms,
+ sent,
+ render,
+ all: () => nodes(tree),
+ text: () => text(tree),
+ find: (type, label) =>
+ nodes(tree).find(
+ (n) => n.type === type && (!label || text(n).includes(label)),
+ ),
+ };
+}
+const request = {
+ id: 'request-one',
+ version: 1,
+ status: 'draft',
+ payload: { title: 'SYNTHETIC saved title' },
+ protocol: null,
+ editable_fields: [],
+ analyst_id: null,
+ due_at: null,
+};
+const props = {
+ request,
+ case: { id: 'case-one', title: 'SYNTHETIC dossier' },
+ definition: {
+ title: 'SYNTHETIC service',
+ fields: {
+ title: { label: 'Project title', type: 'text', required: true },
+ },
+ result: 'SYNTHETIC',
+ },
+ owner: true,
+ manager: false,
+ analyst: false,
+ fieldsEditable: true,
+ operationsEditable: true,
+ states: {
+ draft: 'Rascunho',
+ submitted: 'Submetido',
+ reviewing: 'Em análise',
+ },
+ transitions: [],
+ findings: [],
+ messages: [],
+ analysts: [],
+ territoryPaths: {},
+ events: [],
+ documents: [],
+ payments: [],
+ caseVersion: 1,
+ countries: [],
+ toolPrefill: null,
+};
+const page = (patch) =>
+ harness('../../resources/js/pages/desk/request.tsx', {
+ ...props,
+ ...patch,
+ });
+
+test('owner cancellation uses the existing transition and restores saved server payload only after success', () => {
+ const h = page();
+ h.forms[0].setData('payload', { title: 'SYNTHETIC unsaved edit' });
+ h.forms[1].setData('reason', 'SYNTHETIC deliberate cancellation');
+ h.find('form', 'Cancelar este pedido').props.onSubmit({
+ preventDefault() {},
+ });
+ assert.equal(h.sent[0].data.status, 'cancelled');
+ assert.equal(h.sent[0].data.version, 1);
+ assert.equal(h.sent[0].data.reason, 'SYNTHETIC deliberate cancellation');
+ assert.equal(h.forms[0].data.payload.title, 'SYNTHETIC unsaved edit');
+ h.sent[0].options.onSuccess({
+ props: { request: { ...request, status: 'cancelled', version: 2 } },
+ });
+ h.render({
+ request: { ...request, status: 'cancelled', version: 2 },
+ fieldsEditable: false,
+ operationsEditable: false,
+ });
+ assert.equal(h.forms[0].data.payload.title, 'SYNTHETIC saved title');
+ assert.equal(h.forms[0].data.consent, false);
+ assert.equal(h.find('form', 'Cancelar este pedido'), undefined);
+});
+
+test('cancellation waits for recovery work and is unavailable to submitted requests, reviewers and closed dossiers', () => {
+ const Recovery = () => null;
+ const h = harness('../../resources/js/pages/desk/request.tsx', props, {
+ '@/components/desk-draft-recovery': { default: Recovery },
+ });
+ h.all()
+ .find((n) => n.type === Recovery)
+ .props.onBusy(true);
+ h.render();
+ assert.equal(
+ h.find('button', 'Confirmar cancelamento').props.disabled,
+ true,
+ );
+ h.find('form', 'Cancelar este pedido').props.onSubmit({
+ preventDefault() {},
+ });
+ assert.equal(h.sent.length, 0);
+ for (const patch of [
+ { request: { ...request, status: 'submitted' } },
+ { owner: false, manager: true },
+ { operationsEditable: false },
+ ])
+ assert.equal(
+ page(patch).find('form', 'Cancelar este pedido'),
+ undefined,
+ );
+});
+
+test('closed dossier request hides response, assignment and message actions while keeping previous messages visible', () => {
+ const open = {
+ request: { ...request, status: 'submitted' },
+ owner: false,
+ manager: true,
+ fieldsEditable: false,
+ transitions: ['reviewing'],
+ analysts: [{ id: 2, name: 'SYNTHETIC analyst' }],
+ messages: [
+ {
+ id: 'message-one',
+ body: 'SYNTHETIC historical message',
+ name: 'SYNTHETIC author',
+ kind: 'responsible_response',
+ created_at: '2026-11-03',
+ },
+ ],
+ };
+ const h = page({ ...open, operationsEditable: false });
+ assert.match(h.text(), /SYNTHETIC historical message/);
+ assert.equal(h.find('button', 'Atribuir acompanhamento'), undefined);
+ assert.equal(
+ h.find('form', 'Resposta / análise do responsável'),
+ undefined,
+ );
+ assert.equal(h.find('form', 'Mensagem privada'), undefined);
+ assert.ok(page(open).find('form', 'Resposta / análise do responsável'));
+ assert.ok(page(open).find('form', 'Mensagem privada'));
+});
+
+test('correction explanation applies to returned requests and does not ask draft authors an inapplicable question', () => {
+ assert.doesNotMatch(page().text(), /Justificação de correcção/);
+ assert.match(
+ page({
+ request: {
+ ...request,
+ status: 'returned',
+ editable_fields: ['title'],
+ },
+ }).text(),
+ /Justificação de correcção/,
+ );
+});
+
+test('closed case keeps workflow and documentary context without stage or review operations', () => {
+ const Review = () => null;
+ const base = {
+ case: {
+ id: 'case-one',
+ title: 'SYNTHETIC dossier',
+ version: 1,
+ closed_at: '2026-11-03',
+ workflow: {},
+ },
+ canWrite: false,
+ manager: true,
+ requests: [],
+ services: [],
+ documents: [],
+ workflow: {},
+ stepStates: {},
+ states: {},
+ guidance: null,
+ events: [],
+ links: [],
+ legacyRequest: null,
+ };
+ const h = harness('../../resources/js/pages/desk/case.tsx', base, {
+ '@/components/desk-internal-operations': { DocumentReview: Review },
+ });
+ assert.match(h.text(), /Dossier encerrado/);
+ assert.equal(h.find('button', 'Registar etapa'), undefined);
+ assert.equal(
+ h.all().some((n) => n.type === Review),
+ false,
+ );
+ h.render({ case: { ...base.case, closed_at: null } });
+ assert.ok(h.find('button', 'Registar etapa'));
+ assert.equal(
+ h.all().some((n) => n.type === Review),
+ true,
+ );
+});
+
+test('CRM linked task preserves its title, status and deadline without an update action when dossier is closed', () => {
+ const task = {
+ id: 'task-one',
+ title: 'SYNTHETIC linked task',
+ status: 'open',
+ due_at: '2026-11-05T12:00:00Z',
+ assignee_user_id: 1,
+ version_no: 1,
+ can_update: false,
+ };
+ const h = harness(
+ '../../resources/js/pages/crm/lead.tsx',
+ { task, leadId: 'lead-one' },
+ {
+ '../management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ './types': {
+ taskStates: { open: 'Aberta', done: 'Concluída' },
+ leadStates: {},
+ },
+ },
+ '\nexport { TaskRow };',
+ );
+ assert.match(h.text(), /SYNTHETIC linked task/);
+ assert.equal(h.find('select').props.disabled, true);
+ assert.equal(h.find('button', 'Actualizar tarefa'), undefined);
+ h.find('form').props.onSubmit({ preventDefault() {} });
+ assert.equal(h.sent.length, 0);
+ h.render({ task: { ...task, can_update: true } });
+ assert.ok(h.find('button', 'Actualizar tarefa'));
+});
+
+test('guidance hides task changes on a closed dossier but keeps task history and consulted sources', () => {
+ const guidance = {
+ version: 1,
+ fingerprint: 'x'.repeat(64),
+ rules_version: 'SYNTHETIC',
+ computed_at: '2026-11-03',
+ can_write: false,
+ can_update_tasks: false,
+ facts: {},
+ financial_draft: null,
+ consulted: [],
+ unavailable: [],
+ catalogue_checks: [],
+ phases: [
+ {
+ id: 'one',
+ objective: 'SYNTHETIC phase',
+ known: [],
+ questions: [],
+ evidence: [],
+ recommendations: [],
+ risks: [],
+ },
+ ],
+ tasks: [
+ {
+ id: 'task-one',
+ title: 'SYNTHETIC saved task',
+ status: 'open',
+ due_at: '2026-11-05',
+ assignee_user_id: 1,
+ assignee_name: 'SYNTHETIC actor',
+ version_no: 1,
+ accepted_at: '2026-11-03',
+ desk_request_id: null,
+ },
+ ],
+ calculator_versions: {},
+ crm: { reason: 'SYNTHETIC internal context' },
+ };
+ const h = harness(
+ '../../resources/js/components/investor-guidance.tsx',
+ {
+ caseId: 'case-one',
+ guidance,
+ manager: true,
+ actorId: 1,
+ requests: [],
+ },
+ {
+ '@/lib/investor-guidance-finance': {
+ guidanceFinance: () => ({
+ reason: 'SYNTHETIC no financial draft',
+ result: null,
+ }),
+ guidanceFinancialTools: () => null,
+ },
+ },
+ );
+ assert.match(h.text(), /SYNTHETIC saved task/);
+ assert.doesNotMatch(h.text(), /Resultado ou motivo/);
+ h.render({ guidance: { ...guidance, can_update_tasks: true } });
+ assert.match(h.text(), /Resultado ou motivo/);
+});
diff --git a/tests/frontend/desk-document-picker.test.mjs b/tests/frontend/desk-document-picker.test.mjs
new file mode 100644
index 00000000..33ea69c2
--- /dev/null
+++ b/tests/frontend/desk-document-picker.test.mjs
@@ -0,0 +1,495 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks) {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports.default;
+}
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const text = (node) =>
+ typeof node === 'string'
+ ? node
+ : Array.isArray(node)
+ ? node.map(text).join('')
+ : node?.props
+ ? text(node.props.children)
+ : typeof node === 'number'
+ ? String(node)
+ : '';
+const document = {
+ id: 'source-one',
+ document_id: 'original-one',
+ file_name: 'SYNTHETIC source.txt',
+ version_no: 3,
+ source_reference: 'SYNTHETIC exact source',
+ category: 'project_evidence',
+ stage: 'E2',
+ valid_until: '2028-01-02',
+ origin_label: 'SYNTHETIC previous dossier',
+ status: 'active',
+ malware_scan_status: 'clean',
+ media_type: 'text/plain',
+ size_bytes: 100,
+};
+function harness(handler) {
+ const cells = [],
+ calls = [],
+ selections = [];
+ let cursor = 0,
+ props,
+ tree;
+ const Component = load(
+ '../../resources/js/components/desk-document-picker.tsx',
+ {
+ react: {
+ useId: () => 'synthetic-picker',
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) => {
+ cells[i] =
+ typeof value === 'function'
+ ? value(cells[i])
+ : value;
+ },
+ ];
+ },
+ },
+ '@/lib/profile-json': {
+ async profileJson(url, body, method) {
+ calls.push({ url, body, method });
+ return handler(url);
+ },
+ },
+ },
+ );
+ props = {
+ caseId: 'synthetic-case',
+ disabled: false,
+ selected: null,
+ onSelect: (doc) => {
+ selections.push(doc);
+ props.selected = doc;
+ },
+ };
+ const render = (updates) => {
+ props = { ...props, ...updates };
+ cursor = 0;
+ tree = Component(props);
+ return tree;
+ };
+ const find = (type, label) =>
+ nodes(tree).find(
+ (n) => n.type === type && (!label || text(n).includes(label)),
+ );
+ render();
+ return {
+ render,
+ find,
+ all: () => nodes(tree),
+ calls,
+ selections,
+ text: () => text(tree),
+ };
+}
+const settle = async () => {
+ await new Promise((resolve) => setImmediate(resolve));
+};
+
+test('search encodes literal input, returns names/provenance and never associates on search or selection', async () => {
+ const h = harness(async () => ({
+ documents: [document],
+ next_offset: null,
+ }));
+ h.find('input').props.onChange({
+ target: { value: '%_ source & dossier' },
+ });
+ h.render();
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ assert.equal(h.calls.length, 1);
+ assert.equal(h.calls[0].method, 'GET');
+ const params = new URL(h.calls[0].url, 'http://localhost').searchParams;
+ assert.equal(params.get('q'), '%_ source & dossier');
+ assert.equal(params.get('offset'), '0');
+ assert.match(
+ h.text(),
+ /SYNTHETIC source\.txt.*versão 3.*SYNTHETIC previous dossier.*exact source.*2028-01-02/,
+ );
+ h.all()
+ .find((n) => n.type === 'input' && n.props.type === 'radio')
+ .props.onChange();
+ h.render();
+ assert.deepEqual(h.selections, [document]);
+ assert.equal(h.calls.length, 1);
+ assert.match(h.text(), /Origem seleccionada/);
+ h.find('button', 'Retirar origem seleccionada').props.onClick();
+ assert.equal(h.selections.at(-1), null);
+});
+
+test('pagination does not erase a selected source and new searches start at zero', async () => {
+ const h = harness(async (url) => ({
+ documents: [document],
+ next_offset: url.includes('offset=0') ? 25 : null,
+ }));
+ h.render({ selected: document });
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ h.find('button', 'Próxima página').props.onClick();
+ await settle();
+ h.render();
+ assert.equal(
+ new URL(h.calls.at(-1).url, 'http://localhost').searchParams.get(
+ 'offset',
+ ),
+ '25',
+ );
+ assert.match(h.text(), /Origem seleccionada/);
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ assert.equal(
+ new URL(h.calls.at(-1).url, 'http://localhost').searchParams.get(
+ 'offset',
+ ),
+ '0',
+ );
+ assert.equal(h.selections.length, 0);
+});
+
+test('failed or malformed responses retain selected source and do not expose partial replacements', async () => {
+ let failed = true;
+ const h = harness(async () => {
+ if (failed) throw Error('SYNTHETIC denied');
+ return { documents: {}, next_offset: null };
+ });
+ h.render({ selected: document });
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ assert.match(h.text(), /SYNTHETIC denied/);
+ assert.match(h.text(), /Origem seleccionada/);
+ failed = false;
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ assert.match(h.text(), /selecção anterior foi conservada/);
+ assert.equal(h.selections.length, 0);
+});
+
+test('editing the search removes the old page cursor while retaining a deliberate document selection', async () => {
+ const h = harness(async () => ({ documents: [document], next_offset: 25 }));
+ h.render({ selected: document });
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ await settle();
+ h.render();
+ assert.ok(h.find('button', 'Próxima página'));
+ h.find('input').props.onChange({ target: { value: 'different source' } });
+ h.render();
+ assert.equal(h.find('button', 'Próxima página'), undefined);
+ assert.match(h.text(), /Pesquisa alterada/);
+ assert.match(h.text(), /Origem seleccionada/);
+ assert.equal(h.selections.length, 0);
+});
+
+test('search pending prevents duplicate requests and stale dossier responses are ignored', async () => {
+ let resolve;
+ const h = harness(
+ () =>
+ new Promise((r) => {
+ resolve = r;
+ }),
+ );
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ h.render();
+ assert.equal(h.find('button', 'Pesquisar documentos').props.disabled, true);
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ assert.equal(h.calls.length, 1);
+ h.render({ caseId: 'different-case' });
+ resolve({ documents: [document], next_offset: null });
+ await settle();
+ h.render();
+ assert.equal(
+ h.all().filter((n) => n.type === 'input' && n.props.type === 'radio')
+ .length,
+ 0,
+ );
+ h.render({ disabled: true });
+ h.find('button', 'Pesquisar documentos').props.onClick();
+ assert.equal(h.calls.length, 1);
+});
+
+test('Enter searches without submitting the surrounding form and an unlinked upload remains selectable', async () => {
+ const h = harness(async () => ({
+ documents: [
+ {
+ ...document,
+ id: null,
+ origin_label: null,
+ source_reference: null,
+ },
+ ],
+ next_offset: null,
+ }));
+ let prevented = false;
+ h.find('input').props.onKeyDown({
+ key: 'Enter',
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ await settle();
+ h.render();
+ assert.equal(prevented, true);
+ assert.match(h.text(), /Ficheiro enviado por si.*Referência por completar/);
+ h.all()
+ .find((n) => n.type === 'input' && n.props.type === 'radio')
+ .props.onChange();
+ assert.equal(h.selections[0].id, null);
+ assert.equal(h.selections[0].document_id, document.document_id);
+ assert.ok(
+ h
+ .all()
+ .filter((n) => n.type === 'button')
+ .every((n) => n.props.type === 'button'),
+ );
+});
+
+test('general and question consumers send chosen source identity without asking for UUIDs or rewriting known source', () => {
+ const general = fs.readFileSync(
+ new URL('../../resources/js/pages/desk/case.tsx', import.meta.url),
+ 'utf8',
+ );
+ const field = fs.readFileSync(
+ new URL(
+ '../../resources/js/components/desk-attachment-field.tsx',
+ import.meta.url,
+ ),
+ 'utf8',
+ );
+ assert.match(general, / null;
+ const Component = load('../../resources/js/pages/desk/case.tsx', {
+ react: {
+ useRef(initial) {
+ const i = cursor++;
+ cells[i] ??= { current: initial };
+ return cells[i];
+ },
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in cells)) cells[i] = initial;
+ return [
+ cells[i],
+ (value) => {
+ cells[i] =
+ typeof value === 'function'
+ ? value(cells[i])
+ : value;
+ },
+ ];
+ },
+ },
+ '@/lib/operation-key': { createOperationKey: () => 'synthetic-key' },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { reload() {} },
+ usePage: () => ({
+ props: { auth: { user: { id: 1 } } },
+ url: '/balcao-virtual/dossiers/synthetic-case',
+ }),
+ useForm(initial) {
+ const i = formCursor++;
+ forms[i] ??= {
+ data: { ...initial },
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data[key] = value;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ post(url, options) {
+ posts.push({
+ url,
+ data: this.transformer
+ ? this.transformer(this.data)
+ : this.data,
+ options,
+ });
+ },
+ reset(...keys) {
+ for (const key of keys) this.data[key] = initial[key];
+ },
+ };
+ return forms[i];
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/investor-guidance': { InvestorGuidance: () => null },
+ '@/components/desk-case-state-form': { default: () => null },
+ '@/components/desk-internal-operations': { DocumentReview: () => null },
+ '@/components/desk-document-picker': { default: Picker },
+ });
+ const props = {
+ case: {
+ id: 'synthetic-case',
+ title: 'SYNTHETIC dossier',
+ version: 7,
+ workflow: {},
+ payload: {},
+ },
+ canWrite: true,
+ manager: false,
+ requests: [],
+ services: [],
+ documents: [],
+ workflow: {},
+ stepStates: {},
+ states: {},
+ guidance: null,
+ events: [],
+ links: [],
+ legacyRequest: null,
+ };
+ function render() {
+ cursor = 0;
+ formCursor = 0;
+ tree = Component(props);
+ }
+ render();
+ return {
+ render,
+ forms,
+ posts,
+ picker: () => nodes(tree).find((n) => n.type === Picker),
+ all: () => nodes(tree),
+ submit() {
+ nodes(tree)
+ .find(
+ (n) =>
+ n.type === 'form' &&
+ nodes(n).some((child) => child.type === Picker),
+ )
+ .props.onSubmit({ preventDefault() {} });
+ },
+ };
+}
+
+test('general association sends the selected link, original version context and consent, preserving selection on failure', () => {
+ const h = generalHarness();
+ h.forms[2].setData('file', { name: 'SYNTHETIC old local choice' });
+ h.forms[2].setData('consent', true);
+ h.picker().props.onSelect(document);
+ h.render();
+ assert.equal(h.forms[2].data.file, null);
+ assert.equal(h.forms[2].data.consent, false);
+ h.forms[2].setData('consent', true);
+ h.submit();
+ const posted = h.posts[0];
+ assert.equal(posted.data.version, 7);
+ assert.equal(posted.data.document_id, document.document_id);
+ assert.equal(posted.data.reuse_link_id, document.id);
+ assert.equal(posted.data.file, null);
+ assert.equal(posted.data.source_reference, undefined);
+ h.render();
+ assert.equal(h.picker().props.selected.id, document.id);
+ posted.options.onSuccess();
+ h.render();
+ assert.equal(h.picker().props.selected, null);
+ assert.equal(h.forms[2].data.consent, false);
+});
+
+test('general association asks only for missing provenance on unlinked uploads and preserves entered text until success', () => {
+ const h = generalHarness();
+ h.picker().props.onSelect({
+ ...document,
+ id: null,
+ source_reference: null,
+ });
+ h.render();
+ const source = h.all().find((n) => n.type === 'input' && n.props.required);
+ assert.ok(source);
+ source.props.onChange({
+ target: { value: 'SYNTHETIC missing provenance supplied' },
+ });
+ h.render();
+ h.forms[2].setData('consent', true);
+ h.submit();
+ assert.equal(h.posts[0].data.document_id, document.document_id);
+ assert.equal(h.posts[0].data.reuse_link_id, '');
+ assert.equal(
+ h.posts[0].data.source_reference,
+ 'SYNTHETIC missing provenance supplied',
+ );
+ h.render();
+ assert.equal(
+ h.forms[2].data.source_reference,
+ 'SYNTHETIC missing provenance supplied',
+ );
+ h.posts[0].options.onSuccess();
+ assert.equal(h.forms[2].data.source_reference, '');
+});
diff --git a/tests/frontend/desk-effective-dates.test.mjs b/tests/frontend/desk-effective-dates.test.mjs
new file mode 100644
index 00000000..b997cdca
--- /dev/null
+++ b/tests/frontend/desk-effective-dates.test.mjs
@@ -0,0 +1,349 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks, suffix = '') {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+function form(initial) {
+ return {
+ data: initial,
+ errors: {},
+ processing: false,
+ setData(value, next) {
+ this.data =
+ typeof value === 'function'
+ ? value(this.data)
+ : { ...this.data, [value]: next };
+ },
+ };
+}
+const service = {
+ code: 'project-change',
+ version: 2,
+ effective_from: '2026-11-12',
+ activeVersion: 1,
+ definition: {
+ title: 'SYNTHETIC scheduled form',
+ theme: 'QA',
+ profile: 'Investor',
+ entity: 'Internal',
+ result: 'Internal preparation',
+ stage: 'E10',
+ fields: {
+ question: {
+ label: 'Synthetic question',
+ type: 'text',
+ required: false,
+ },
+ },
+ },
+};
+function editorHarness() {
+ let saved, sent;
+ const Editor = load(
+ '../../resources/js/pages/desk/service-editor.tsx',
+ {
+ react: { useState: (initial) => [initial, () => {}] },
+ '@inertiajs/react': {
+ Link: 'a',
+ useForm(key, initial) {
+ saved ??= {
+ ...form(initial),
+ put(url) {
+ sent = { url, data: structuredClone(this.data) };
+ },
+ };
+ return saved;
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/desk-service-history': { default: () => null },
+ },
+ '\nexport { Editor };',
+ ).Editor;
+ return {
+ render: (props = {}) =>
+ Editor({
+ service,
+ schedulingAvailable: true,
+ today: '2026-11-02',
+ calendarTimezone: 'UTC',
+ ...props,
+ }),
+ data: () => saved,
+ sent: () => sent,
+ };
+}
+
+await test('editing a scheduled edition keeps its future date until changed deliberately and date-only changes require fresh confirmation', () => {
+ const before = JSON.stringify(service);
+ const h = editorHarness();
+ let tree = h.render();
+ assert.equal(h.data().data.effective_from, '2026-11-12');
+ const date = nodes(tree).find(
+ (node) => node.type === 'input' && node.props.type === 'date',
+ );
+ assert.equal(date.props.min, '2026-11-02');
+ h.data().data.confirm = true;
+ date.props.onChange({ target: { value: '2026-11-02' } });
+ assert.equal(h.data().data.confirm, false);
+ tree = h.render();
+ let html = renderToStaticMarkup(tree);
+ assert.match(html, /Versão actualmente disponível para novos pedidos: 1/);
+ assert.match(html, /Entrada em vigor proposta: 2026-11-02/);
+ assert.match(html, /não cancela uma edição já agendada/);
+ assert.match(html, /Calendário do portal: UTC/);
+ h.data().data.confirm = true;
+ tree = h.render();
+ const publish = nodes(tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Publicar nova versão',
+ );
+ assert.equal(publish.props.disabled, false);
+ tree.props.onSubmit({ preventDefault() {} });
+ assert.equal(h.sent().data.effective_from, '2026-11-02');
+ assert.equal(h.sent().data.base_version, 2);
+ assert.equal(JSON.stringify(service), before);
+ date.props.onChange({ target: { value: '' } });
+ html = renderToStaticMarkup(h.render());
+ assert.match(html, /Entrada em vigor proposta: 2026-11-02/);
+});
+
+await test('destinations without the migration retain immediate publication and cannot silently present a scheduling control', () => {
+ const h = editorHarness();
+ const tree = h.render({ schedulingAvailable: false });
+ assert.equal(h.data().data.effective_from, '');
+ assert.equal(
+ nodes(tree).some(
+ (node) => node.type === 'input' && node.props.type === 'date',
+ ),
+ false,
+ );
+ assert.match(
+ renderToStaticMarkup(tree),
+ /agendamento requer a actualização/,
+ );
+});
+
+await test('advancing the calendar does not silently propose an unchanged edition, and upcoming editions remain visible', () => {
+ const h = editorHarness();
+ const props = {
+ service: {
+ ...service,
+ effective_from: '2026-11-01',
+ activeVersion: 2,
+ upcoming: [{ version: 1, effective_from: '2026-11-12' }],
+ },
+ };
+ let tree = h.render(props);
+ h.data().data.confirm = true;
+ tree = h.render(props);
+ let publish = nodes(tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Publicar nova versão',
+ );
+ assert.equal(publish.props.disabled, true);
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /Edições já agendadas/);
+ assert.match(html, /Versão 1: 2026-11-12/);
+ nodes(tree)
+ .find((node) => node.type === 'input' && node.props.type === 'date')
+ .props.onChange({ target: { value: '2026-11-02' } });
+ h.data().data.confirm = true;
+ tree = h.render(props);
+ publish = nodes(tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Publicar nova versão',
+ );
+ assert.equal(publish.props.disabled, false);
+});
+
+await test('refreshing services retains other case forms and requires an explicit choice when the selected edition is no longer listed', () => {
+ let cursor = 0,
+ stateCursor = 0,
+ refreshed,
+ submitted;
+ const forms = [],
+ states = [];
+ const Case = load('../../resources/js/pages/desk/case.tsx', {
+ react: {
+ useState(initial) {
+ const index = stateCursor++;
+ if (!(index in states)) states[index] = initial;
+ return [
+ states[index],
+ (value) => {
+ states[index] =
+ typeof value === 'function'
+ ? value(states[index])
+ : value;
+ },
+ ];
+ },
+ useRef(initial) {
+ const index = stateCursor++;
+ states[index] ??= { current: initial };
+ return states[index];
+ },
+ },
+ '@/lib/operation-key': { createOperationKey: () => 'qa-operation' },
+ '@inertiajs/react': {
+ Link: 'a',
+ usePage: () => ({
+ props: { auth: { user: { id: 3 } } },
+ url: '/balcao-virtual/dossiers/qa',
+ }),
+ router: {
+ reload(options) {
+ refreshed = options;
+ },
+ },
+ useForm(initial) {
+ const index = cursor++;
+ forms[index] ??= {
+ ...form(initial),
+ post(url) {
+ submitted = { url, data: this.data };
+ },
+ };
+ return forms[index];
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/investor-guidance': { InvestorGuidance: () => null },
+ '@/components/desk-case-state-form': { default: () => null },
+ '@/components/desk-document-picker': { default: () => null },
+ '@/components/desk-internal-operations': { DocumentReview: () => null },
+ }).default;
+ const props = {
+ case: { id: 'qa', title: 'Synthetic case', version: 1, workflow: {} },
+ canWrite: true,
+ manager: false,
+ requests: [],
+ services: [{ id: 'v1', title: 'Current', version: 1 }],
+ documents: [],
+ workflow: {},
+ stepStates: {},
+ states: {},
+ guidance: null,
+ events: [],
+ links: [],
+ legacyRequest: null,
+ };
+ const render = (services) => {
+ cursor = 0;
+ stateCursor = 0;
+ return Case({ ...props, services });
+ };
+ let tree = render(props.services);
+ forms[1].data.reason = 'Unsaved stage evidence';
+ tree = render([
+ {
+ id: 'v2',
+ title: 'New current',
+ version: 2,
+ effective_from: '2026-11-03',
+ },
+ ]);
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /versão seleccionada já não está na lista/);
+ assert.match(html, /desde 2026-11-03/);
+ const create = nodes(tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Preparar rascunho de pedido',
+ );
+ assert.equal(create.props.disabled, true);
+ const requestForm = nodes(tree).find(
+ (node) => node.type === 'form' && nodes(node).includes(create),
+ );
+ requestForm.props.onSubmit({ preventDefault() {} });
+ assert.equal(submitted, undefined);
+ nodes(tree)
+ .find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Actualizar versões disponíveis',
+ )
+ .props.onClick();
+ assert.deepEqual(refreshed.only, ['services']);
+ assert.equal(forms[1].data.reason, 'Unsaved stage evidence');
+ const select = nodes(tree).find(
+ (node) => node.type === 'select' && node.props.value === 'v1',
+ );
+ select.props.onChange({ target: { value: 'v2' } });
+ tree = render([{ id: 'v2', title: 'New current', version: 2 }]);
+ const ready = nodes(tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Preparar rascunho de pedido',
+ );
+ assert.equal(ready.props.disabled, false);
+});
+
+await test('catalogue shows the selected calendar date with the distinction between new and existing requests', () => {
+ const Catalogue = load('../../resources/js/pages/desk/catalogue.tsx', {
+ '@inertiajs/react': { Link: 'a' },
+ '@/pages/investment/shared': { Frame: 'main', card: '' },
+ }).default;
+ const html = renderToStaticMarkup(
+ Catalogue({
+ installed: true,
+ services: [
+ {
+ id: 'v2',
+ version: 2,
+ effective_from: '2026-11-03',
+ definition: {
+ title: '',
+ result: 'Internal preparation',
+ },
+ },
+ ],
+ prepared: {},
+ }),
+ );
+ assert.match(html, /novos pedidos desde 2026-11-03/);
+ assert.match(html, /Pedidos anteriores mantêm/);
+ assert.match(html, /<Synthetic public form>/);
+});
diff --git a/tests/frontend/desk-payment-evidence.test.mjs b/tests/frontend/desk-payment-evidence.test.mjs
new file mode 100644
index 00000000..8f963968
--- /dev/null
+++ b/tests/frontend/desk-payment-evidence.test.mjs
@@ -0,0 +1,310 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const text = (tree) =>
+ typeof tree === 'string'
+ ? tree
+ : Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'number'
+ ? String(tree)
+ : '';
+const document = {
+ id: 'link-one',
+ document_id: 'original-one',
+ file_name: 'SYNTHETIC proof.txt',
+ version_no: 3,
+ source_reference: 'SYNTHETIC document source',
+ status: 'active',
+ malware_scan_status: 'clean',
+};
+const payment = {
+ id: 'payment-one',
+ reference: 'SYNTHETIC reference',
+ amount: '25.50',
+ currency: 'MZN',
+ source_reference: 'SYNTHETIC amount purpose',
+ document_id: null,
+ version: 1,
+ status: 'pending',
+ verified_by: null,
+ reason: null,
+};
+const shared = { card: '', input: '', button: '' };
+function formsHarness(file, defaults, pickerMock = {}) {
+ const forms = [],
+ calls = [];
+ let cursor = 0,
+ serial = 0,
+ tree,
+ props = defaults;
+ const loaded = load(file, {
+ '@inertiajs/react': {
+ useForm(initial) {
+ const i = cursor++;
+ forms[i] ??= {
+ data: { ...initial },
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data[key] = value;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ reset(...keys) {
+ for (const key of keys) this.data[key] = initial[key];
+ },
+ put(url, options) {
+ calls.push({
+ url,
+ method: 'PUT',
+ data: { ...this.data },
+ options,
+ });
+ },
+ post(url, options) {
+ calls.push({
+ url,
+ method: 'POST',
+ data: this.transformer
+ ? this.transformer(this.data)
+ : { ...this.data },
+ options,
+ });
+ },
+ };
+ return forms[i];
+ },
+ },
+ '@/lib/operation-key': {
+ createOperationKey: () => `synthetic-key-${++serial}`,
+ },
+ '@/pages/investment/shared': shared,
+ './desk-payment-document-form': pickerMock,
+ });
+ const Component = loaded.default ?? loaded.RequestOperations;
+ function render(patch = {}) {
+ props = { ...props, ...patch };
+ cursor = 0;
+ tree = Component(props);
+ }
+ render();
+ return {
+ forms,
+ calls,
+ render,
+ all: () => nodes(tree),
+ text: () => text(tree),
+ find: (type, label) =>
+ nodes(tree).find(
+ (n) => n.type === type && (!label || text(n).includes(label)),
+ ),
+ submit() {
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ },
+ };
+}
+const proofHarness = () =>
+ formsHarness(
+ '../../resources/js/components/desk-payment-document-form.tsx',
+ { requestId: 'request-one', payment, documents: [document] },
+ );
+
+test('adding proof to a pending payment sends only new documentary facts and conserves financial declaration', () => {
+ const h = proofHarness();
+ h.find('select').props.onChange({ target: { value: document.id } });
+ h.render();
+ h.find('textarea').props.onChange({
+ target: { value: 'SYNTHETIC reason' },
+ });
+ h.render();
+ h.find('input').props.onChange({ target: { checked: true } });
+ h.render();
+ h.submit();
+ assert.match(h.calls[0].url, /pagamentos\/payment-one\/comprovativo$/);
+ assert.equal(h.calls[0].method, 'PUT');
+ assert.deepEqual(
+ Object.keys(h.calls[0].data).sort(),
+ [
+ 'version',
+ 'document_link_id',
+ 'reason',
+ 'consent',
+ 'client_key',
+ ].sort(),
+ );
+ assert.equal(h.calls[0].data.document_link_id, document.id);
+ assert.equal(h.calls[0].data.version, 1);
+ assert.equal(h.calls[0].data.consent, true);
+ assert.match(
+ h.text(),
+ /referência, o valor e a moeda já registados são conservados/,
+ );
+ assert.equal(h.all().filter((n) => n.type === 'input').length, 1);
+});
+
+test('failed retry keeps payload and operation key while editing deliberately starts a new operation', () => {
+ const h = proofHarness();
+ h.forms[0].setData('document_link_id', document.id);
+ h.forms[0].setData('reason', 'SYNTHETIC original reason');
+ h.forms[0].setData('consent', true);
+ h.submit();
+ h.submit();
+ assert.deepEqual(h.calls[0].data, h.calls[1].data);
+ const original = h.forms[0].data.client_key;
+ h.find('textarea').props.onChange({
+ target: { value: 'SYNTHETIC edited reason' },
+ });
+ h.render();
+ assert.notEqual(h.forms[0].data.client_key, original);
+ assert.equal(h.forms[0].data.consent, false);
+ assert.equal(h.forms[0].data.document_link_id, document.id);
+ h.forms[0].setData('consent', true);
+ h.submit();
+ const key = h.forms[0].data.client_key;
+ h.calls.at(-1).options.onSuccess();
+ h.render({ payment: { ...payment, version: 2 } });
+ assert.equal(h.forms[0].data.version, 2);
+ assert.equal(h.forms[0].data.reason, '');
+ assert.equal(h.forms[0].data.document_link_id, '');
+ assert.notEqual(h.forms[0].data.client_key, key);
+});
+
+test('new server version requires deliberate adoption and does not erase reason or selected proof', () => {
+ const h = proofHarness();
+ h.forms[0].setData('document_link_id', document.id);
+ h.forms[0].setData('reason', 'SYNTHETIC unsaved reason');
+ h.forms[0].setData('consent', true);
+ h.render({ payment: { ...payment, version: 3 } });
+ assert.equal(h.find('button', 'Guardar comprovativo').props.disabled, true);
+ h.submit();
+ assert.equal(h.calls.length, 0);
+ h.find('button', 'Usar versão actual').props.onClick();
+ h.render();
+ assert.equal(h.forms[0].data.version, 3);
+ assert.equal(h.forms[0].data.document_link_id, document.id);
+ assert.equal(h.forms[0].data.reason, 'SYNTHETIC unsaved reason');
+ assert.equal(h.forms[0].data.consent, false);
+});
+
+test('read-only operations preserve payment history without offering manual business forms', () => {
+ const Proof = () => null;
+ const h = formsHarness(
+ '../../resources/js/components/desk-internal-operations.tsx',
+ {
+ requestId: 'request-one',
+ owner: false,
+ reviewer: false,
+ documents: [document],
+ payments: [payment],
+ },
+ { default: Proof },
+ );
+ assert.match(h.text(), /SYNTHETIC reference/);
+ assert.match(h.text(), /Comprovativo ainda não associado/);
+ assert.equal(h.all().filter((n) => n.type === 'form').length, 0);
+ assert.equal(h.all().filter((n) => n.type === Proof).length, 0);
+ h.render({ payments: [{ ...payment, document_id: document.document_id }] });
+ assert.match(h.text(), /metadados da associação não capturados à época/);
+});
+
+test('only pending or disputed payment offers proof correction and creation uses exact link without copying amount provenance', () => {
+ const Proof = () => null;
+ const h = formsHarness(
+ '../../resources/js/components/desk-internal-operations.tsx',
+ {
+ requestId: 'request-one',
+ owner: true,
+ reviewer: false,
+ documents: [document],
+ payments: [
+ payment,
+ { ...payment, id: 'verified', status: 'internal_verified' },
+ { ...payment, id: 'issue', status: 'internal_issue' },
+ ],
+ },
+ { default: Proof },
+ );
+ assert.equal(h.all().filter((n) => n.type === Proof).length, 2);
+ const selector = h
+ .all()
+ .find(
+ (n) =>
+ n.type === 'select' &&
+ n.props.value === h.forms[0].data.document_link_id,
+ );
+ assert.ok(
+ nodes(selector).some(
+ (n) => n.type === 'option' && n.props.value === document.id,
+ ),
+ );
+ selector.props.onChange({ target: { value: document.id } });
+ h.render();
+ assert.equal(h.forms[0].data.document_link_id, document.id);
+ assert.equal(h.forms[0].data.source_reference, '');
+ assert.equal(h.forms[0].data.amount, '');
+});
+
+test('historical evidence shows the frozen file version and separates documentary reference from amount purpose', () => {
+ const h = formsHarness(
+ '../../resources/js/components/desk-internal-operations.tsx',
+ {
+ requestId: 'request-one',
+ owner: false,
+ reviewer: false,
+ documents: [],
+ payments: [
+ {
+ ...payment,
+ document_id: document.document_id,
+ document_evidence: {
+ link_id: document.id,
+ file_name: document.file_name,
+ document_version: 3,
+ source_reference: document.source_reference,
+ valid_until: '2028-01-02',
+ },
+ },
+ ],
+ },
+ { default: () => null },
+ );
+ assert.match(h.text(), /Fonte do valor: SYNTHETIC amount purpose/);
+ assert.match(
+ h.text(),
+ /SYNTHETIC proof.txt.*versão 3.*SYNTHETIC document source.*2028-01-02/,
+ );
+});
diff --git a/tests/frontend/desk-request-conditions.test.mjs b/tests/frontend/desk-request-conditions.test.mjs
index 54250c4c..e3bbffb4 100644
--- a/tests/frontend/desk-request-conditions.test.mjs
+++ b/tests/frontend/desk-request-conditions.test.mjs
@@ -27,7 +27,7 @@ function load(file, overrides = {}) {
);
return module.exports;
}
-function render(payload) {
+function render(payload, extra = {}) {
const empty = () => null;
const page = load('../../resources/js/pages/desk/request.tsx', {
'@inertiajs/react': {
@@ -39,12 +39,39 @@ function render(payload) {
'@/lib/desk-field-visibility': load(
'../../resources/js/lib/desk-field-visibility.ts',
),
+ '@/lib/desk-field-values': load(
+ '../../resources/js/lib/desk-field-values.ts',
+ ),
+ '@/components/desk-typed-choice': load(
+ '../../resources/js/components/desk-typed-choice.tsx',
+ {
+ '@/lib/desk-field-values': load(
+ '../../resources/js/lib/desk-field-values.ts',
+ ),
+ },
+ ),
'@/components/dossier-prefill': { DossierPrefill: empty },
+ '@/components/desk-draft-recovery': {
+ __esModule: true,
+ default: empty,
+ },
'@/components/country-select': { __esModule: true, default: empty },
+ '@/components/desk-attachment-field': {
+ __esModule: true,
+ default: empty,
+ },
'@/components/investment-territory': { TerritoryFields: empty },
'@/components/desk-internal-operations': {
DocumentReview: empty,
- RequestOperations: empty,
+ RequestOperations: ({ owner, reviewer, payments }) =>
+ createElement(
+ 'section',
+ {
+ 'data-test': 'manual-operations',
+ 'data-writable': owner || reviewer ? 'yes' : 'no',
+ },
+ payments.map((payment) => payment.reference).join(', '),
+ ),
},
'@/pages/investment/shared': {
Frame: ({ children }) => createElement('main', null, children),
@@ -54,7 +81,7 @@ function render(payload) {
},
}).default;
return renderToStaticMarkup(
- page({
+ createElement(page, {
request: {
id: 'synthetic-request',
version: 1,
@@ -107,9 +134,28 @@ function render(payload) {
caseVersion: 1,
countries: [],
toolPrefill: null,
+ ...extra,
}),
);
}
+await test('manual payment history remains visible with operations disabled and legacy draft props still render', () => {
+ const readonly = render(
+ {},
+ {
+ operationsEditable: false,
+ payments: [{ reference: 'SYNTHETIC historical payment' }],
+ },
+ );
+ assert.match(readonly, /SYNTHETIC historical payment/);
+ assert.match(readonly, /data-writable="no"/);
+ const legacy = render(
+ {},
+ { payments: [{ reference: 'SYNTHETIC legacy draft' }] },
+ );
+ assert.match(legacy, /SYNTHETIC legacy draft/);
+ assert.match(legacy, /data-writable="yes"/);
+});
+
await test('hidden parent answers never reveal nested questions, while reopening the branch restores their answers', () => {
const payload = { root: '0', branch: '1', detail: 'Preserved detail' };
const hidden = render(payload);
@@ -127,3 +173,36 @@ await test('hidden parent answers never reveal nested questions, while reopening
detail: 'Preserved detail',
});
});
+
+await test('return category is optional and comes from the server, while historical labels retain their snapshot', () => {
+ const props = {
+ owner: false,
+ manager: true,
+ fieldsEditable: false,
+ transitions: ['returned'],
+ returnReasons: {
+ unspecified: 'SYNTHETIC unclassified',
+ missing_documents: 'SYNTHETIC configured category',
+ },
+ events: [
+ {
+ id: 'event',
+ action: 'request_returned',
+ name: 'SYNTHETIC actor',
+ created_at: '2026-11-02T10:00:00Z',
+ payload: { return_reason_label: 'SYNTHETIC historical label' },
+ },
+ ],
+ };
+ const returned = render({}, props);
+ assert.match(
+ returned,
+ /Categoria do motivo \(opcional, para indicadores\)/,
+ );
+ assert.match(returned, /SYNTHETIC configured category/);
+ assert.match(returned, /Categoria:.*SYNTHETIC historical label/);
+ assert.doesNotMatch(returned, /]*required/);
+ const other = render({}, { ...props, transitions: ['reviewing'] });
+ assert.doesNotMatch(other, /SYNTHETIC configured category/);
+ assert.match(other, /SYNTHETIC historical label/);
+});
diff --git a/tests/frontend/desk-typed-fields.test.mjs b/tests/frontend/desk-typed-fields.test.mjs
new file mode 100644
index 00000000..c623f8ec
--- /dev/null
+++ b/tests/frontend/desk-typed-fields.test.mjs
@@ -0,0 +1,400 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}, suffix = '') {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8') + suffix,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const values = load('../../resources/js/lib/desk-field-values.ts');
+const { deskFieldApplies } = load(
+ '../../resources/js/lib/desk-field-visibility.ts',
+);
+const Choice = load('../../resources/js/components/desk-typed-choice.tsx', {
+ '@/lib/desk-field-values': values,
+}).default;
+function nodes(tree) {
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ if (!tree || typeof tree !== 'object') return [];
+ return [tree, ...nodes(tree.props?.children)];
+}
+const fields = {
+ root: {
+ type: 'select',
+ label: 'SYNTHETIC root',
+ required: false,
+ options: { on: 'Open', off: 'Closed' },
+ },
+ activities: {
+ type: 'multiselect',
+ label: 'SYNTHETIC activities',
+ required: true,
+ options: { 0: 'Zero', cotton: 'Cotton' },
+ when: { field: 'root', equals: 'on' },
+ },
+ declaration: {
+ type: 'consent',
+ label: 'SYNTHETIC declaration',
+ statement: 'SYNTHETIC declaration.',
+ required: true,
+ when: { field: 'activities', operator: 'contains', equals: 'cotton' },
+ },
+ explanation: {
+ type: 'textarea',
+ label: 'SYNTHETIC explanation',
+ required: true,
+ when: { field: 'declaration', equals: 'declined' },
+ },
+ amount: { type: 'number' },
+};
+
+await test('typed prefill preserves arrays, zero, refusal and deliberate answers; declarations cannot be inherited even with replacement', () => {
+ const before = {
+ activities: ['0'],
+ declaration: 'declined',
+ amount: 0,
+ detail: 'Edited',
+ };
+ const patch = {
+ activities: ['cotton'],
+ declaration: 'accepted',
+ amount: 300,
+ detail: 'Profile',
+ missing: 'New',
+ };
+ assert.deepEqual(values.mergeDeskPrefill(before, patch, fields), {
+ ...before,
+ missing: 'New',
+ });
+ assert.deepEqual(values.mergeDeskPrefill(before, patch, fields, true), {
+ activities: ['cotton'],
+ declaration: 'declined',
+ amount: 300,
+ detail: 'Profile',
+ missing: 'New',
+ });
+ assert.deepEqual(before.activities, ['0']);
+ assert.equal(
+ values.mergeDeskPrefill({}, patch, fields).declaration,
+ undefined,
+ );
+ assert.deepEqual(
+ values.mergeDeskPrefill(
+ { activities: [] },
+ { activities: ['0'] },
+ fields,
+ ).activities,
+ ['0'],
+ );
+ assert.equal(
+ values.mergeDeskPrefill({}, { activities: ['absent'] }, fields)
+ .activities,
+ undefined,
+ );
+ assert.equal(
+ values.mergeDeskPrefill({}, { activities: 'cotton' }, fields)
+ .activities,
+ undefined,
+ );
+ assert.equal(values.deskScalar(0), '0');
+ assert.equal(values.deskScalar(['cotton']), '');
+});
+
+await test('multiple choice controls retain code zero and toggle individual answers without checking an empty answer', () => {
+ let answer;
+ const initial = ['0'];
+ const tree = Choice({
+ fieldKey: 'activities',
+ field: fields.activities,
+ value: initial,
+ disabled: false,
+ onChange: (v) => (answer = v),
+ });
+ const inputs = nodes(tree).filter((n) => n.type === 'input');
+ assert.deepEqual(
+ inputs.map((n) => n.props.checked),
+ [true, false],
+ );
+ inputs[1].props.onChange({ target: { checked: true } });
+ assert.deepEqual(answer, ['0', 'cotton']);
+ inputs[0].props.onChange({ target: { checked: false } });
+ assert.deepEqual(answer, []);
+ assert.deepEqual(initial, ['0']);
+ assert.ok(inputs.every((n) => !n.props.required)); // Saving a partial draft remains possible.
+ const blank = Choice({
+ fieldKey: 'activities',
+ field: fields.activities,
+ value: [],
+ disabled: false,
+ onChange() {},
+ });
+ assert.ok(
+ nodes(blank)
+ .filter((n) => n.type === 'input')
+ .every((n) => !n.props.checked),
+ );
+});
+
+await test('consent has explicit acceptance and refusal, starts unanswered, can be cleared and renders statement safely', () => {
+ let answer;
+ const render = (value) =>
+ Choice({
+ fieldKey: 'declaration',
+ field: fields.declaration,
+ value,
+ disabled: false,
+ onChange: (v) => (answer = v),
+ });
+ let tree = render('');
+ const inputs = nodes(tree).filter((n) => n.type === 'input');
+ assert.deepEqual(
+ inputs.map((n) => n.props.checked),
+ [false, false],
+ );
+ inputs[1].props.onChange();
+ assert.equal(answer, 'declined');
+ tree = render(answer);
+ assert.deepEqual(
+ nodes(tree)
+ .filter((n) => n.type === 'input')
+ .map((n) => n.props.checked),
+ [false, true],
+ );
+ nodes(tree)
+ .find((n) => n.type === 'button')
+ .props.onClick();
+ assert.equal(answer, '');
+ const html = renderToStaticMarkup(tree);
+ assert.ok(html.includes('<script>fictional</script>'));
+ assert.ok(!html.includes(''));
+ assert.match(html, /não exige aceitar/);
+ assert.equal(
+ Choice({
+ fieldKey: 'declaration',
+ field: fields.declaration,
+ value: 'accepted',
+ disabled: true,
+ onChange() {},
+ }).props.disabled,
+ true,
+ );
+});
+
+await test('contains conditions require string membership and active ancestors; reopening restores prior refusal and detail', () => {
+ const payload = {
+ root: 'off',
+ activities: ['cotton', '0'],
+ declaration: 'declined',
+ explanation: 'Preserved',
+ };
+ assert.equal(deskFieldApplies('declaration', fields, payload), false);
+ assert.equal(deskFieldApplies('explanation', fields, payload), false);
+ assert.equal(
+ deskFieldApplies('explanation', fields, { ...payload, root: 'on' }),
+ true,
+ );
+ assert.equal(
+ deskFieldApplies('declaration', fields, {
+ ...payload,
+ root: 'on',
+ activities: 'cotton',
+ }),
+ false,
+ );
+ assert.equal(
+ deskFieldApplies('declaration', fields, {
+ ...payload,
+ root: 'on',
+ activities: ['0'],
+ }),
+ false,
+ );
+ assert.equal(
+ deskFieldApplies('explanation', fields, {
+ ...payload,
+ root: 'on',
+ declaration: 'accepted',
+ }),
+ false,
+ );
+ assert.equal(
+ deskFieldApplies('explanation', fields, {
+ ...payload,
+ root: 'on',
+ declaration: '',
+ }),
+ false,
+ );
+ assert.deepEqual(payload.activities, ['cotton', '0']);
+});
+
+function editorHarness() {
+ let form;
+ const Editor = load(
+ '../../resources/js/pages/desk/service-editor.tsx',
+ {
+ react: { useState: (value) => [value, () => {}] },
+ '@inertiajs/react': {
+ Link: 'a',
+ useForm(key, initial) {
+ form ??= {
+ data: initial,
+ errors: {},
+ processing: false,
+ setData(value) {
+ this.data = value(this.data);
+ },
+ };
+ return form;
+ },
+ },
+ '@/pages/investment/shared': {
+ Frame: 'main',
+ card: '',
+ input: '',
+ button: '',
+ },
+ '@/components/desk-service-history': { default: () => null },
+ },
+ '\nexport { Editor };',
+ ).Editor;
+ const service = {
+ code: 'project-change',
+ version: 1,
+ definition: {
+ title: 'SYNTHETIC form',
+ theme: 'QA',
+ profile: 'Investor',
+ entity: 'Internal',
+ result: 'Preparation',
+ stage: 'E10',
+ fields: structuredClone(fields),
+ },
+ };
+ return {
+ render: () => Editor({ service }),
+ data: () => form.data,
+ section(key) {
+ return nodes(this.render()).find(
+ (n) =>
+ n.type === 'section' &&
+ nodes(n).some(
+ (v) =>
+ v.type === 'input' &&
+ v.props.value === fields[key].label,
+ ),
+ );
+ },
+ };
+}
+
+await test('editor configures multiple-choice membership and consent refusal conditions without losing the operator', () => {
+ const h = editorHarness();
+ let section = h.section('explanation');
+ const conditionSource = nodes(section).find(
+ (n) =>
+ n.type === 'select' &&
+ nodes(n).some(
+ (o) => o.type === 'option' && o.props.children === 'Sempre',
+ ),
+ );
+ conditionSource.props.onChange({ target: { value: 'activities' } });
+ assert.deepEqual(h.data().definition.fields.explanation.when, {
+ field: 'activities',
+ equals: '',
+ operator: 'contains',
+ });
+ section = h.section('explanation');
+ const operand = nodes(section).find(
+ (n) =>
+ n.type === 'select' &&
+ nodes(n).some(
+ (o) => o.type === 'option' && o.props.value === 'cotton',
+ ),
+ );
+ operand.props.onChange({ target: { value: 'cotton' } });
+ assert.equal(
+ h.data().definition.fields.explanation.when.operator,
+ 'contains',
+ );
+ assert.equal(h.data().definition.fields.explanation.when.equals, 'cotton');
+ section = h.section('explanation');
+ nodes(section)
+ .find(
+ (n) =>
+ n.type === 'select' &&
+ nodes(n).some(
+ (o) => o.type === 'option' && o.props.children === 'Sempre',
+ ),
+ )
+ .props.onChange({ target: { value: 'declaration' } });
+ section = h.section('explanation');
+ const refusal = nodes(section).find(
+ (n) =>
+ n.type === 'select' &&
+ nodes(n).some(
+ (o) => o.type === 'option' && o.props.value === 'declined',
+ ),
+ );
+ refusal.props.onChange({ target: { value: 'declined' } });
+ assert.deepEqual(h.data().definition.fields.explanation.when, {
+ field: 'declaration',
+ equals: 'declined',
+ });
+ assert.equal(h.data().confirm, false);
+});
+
+await test('changing simple and multiple choice types preserves codes and adjusts dependent conditions in the draft only', () => {
+ const h = editorHarness();
+ const typeControl = (section) =>
+ nodes(section).find(
+ (n) =>
+ n.type === 'select' &&
+ nodes(n).some(
+ (o) =>
+ o.type === 'option' && o.props.value === 'multiselect',
+ ),
+ );
+ typeControl(h.section('activities')).props.onChange({
+ target: { value: 'select' },
+ });
+ assert.deepEqual(
+ h.data().definition.fields.activities.options,
+ fields.activities.options,
+ );
+ assert.deepEqual(h.data().definition.fields.declaration.when, {
+ field: 'activities',
+ equals: 'cotton',
+ });
+ typeControl(h.section('activities')).props.onChange({
+ target: { value: 'multiselect' },
+ });
+ assert.deepEqual(h.data().definition.fields.declaration.when, {
+ field: 'activities',
+ equals: 'cotton',
+ operator: 'contains',
+ });
+ assert.equal(h.data().confirm, false);
+ assert.equal(fields.declaration.when.operator, 'contains');
+ assert.match(renderToStaticMarkup(h.render()), /inclui cotton/);
+});
diff --git a/tests/frontend/document-scan-retry.test.mjs b/tests/frontend/document-scan-retry.test.mjs
new file mode 100644
index 00000000..69048467
--- /dev/null
+++ b/tests/frontend/document-scan-retry.test.mjs
@@ -0,0 +1,143 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { createElement } from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(file, mocks) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../resources/js/' + file, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const Empty = () => null;
+function management(flash) {
+ return load('pages/management/shared.tsx', {
+ '@inertiajs/react': {
+ Head: Empty,
+ Link: 'a',
+ usePage: () => ({ props: { flash, basePath: '/management' } }),
+ },
+ '@/components/profile-navigation': { default: Empty },
+ '@/components/content-management-entry': { default: Empty },
+ }).Management;
+}
+test('the actual management shell exposes retry warnings as an alert alongside preserved page content', () => {
+ const html = renderToStaticMarkup(
+ createElement(
+ management({ warning: 'SYNTHETIC dispatch unconfirmed' }),
+ { title: 'Documents' },
+ 'SYNTHETIC unchanged editor',
+ ),
+ );
+ assert.match(html, /role="alert"[^>]*>SYNTHETIC dispatch unconfirmed/);
+ assert.match(html, /SYNTHETIC unchanged editor/);
+ assert.doesNotMatch(html, /role="status"/);
+});
+test('the actual management shell still renders a confirmed retry as a status', () => {
+ const html = renderToStaticMarkup(
+ createElement(management({ success: 'SYNTHETIC accepted' }), {
+ title: 'Documents',
+ }),
+ );
+ assert.match(html, /role="status"[^>]*>SYNTHETIC accepted/);
+ assert.doesNotMatch(html, /role="alert"/);
+});
+function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree?.props
+ ? [tree, ...nodes(tree.props.children)]
+ : [];
+}
+function zone(management) {
+ const sent = [],
+ setters = [];
+ const Page = load('pages/investment/zone-attachments.tsx', {
+ react: { useState: (value) => [value, (next) => setters.push(next)] },
+ '@inertiajs/react': { router: { post: (...args) => sent.push(args) } },
+ './shared': {
+ api: () => {
+ throw new Error('Retry must use the redirect-aware transport');
+ },
+ button: '',
+ card: '',
+ input: '',
+ Field: 'label',
+ },
+ }).default;
+ const tree = Page({
+ zoneId: 'SYNTHETIC-zone',
+ management,
+ zonePublished: false,
+ attachments: [
+ {
+ id: 'SYNTHETIC-link',
+ document_id: 'SYNTHETIC-document',
+ kind: 'photo',
+ caption: 'SYNTHETIC attachment',
+ source_reference: '',
+ source_date: null,
+ media_type: 'image/png',
+ size_bytes: 12,
+ download_url: '/private-document',
+ malware_scan_status: 'failed',
+ },
+ ],
+ });
+ return { tree, sent, setters };
+}
+test('the actual zone retry follows the flash response through Inertia and keeps the page scroll', () => {
+ const h = zone(true),
+ button = nodes(h.tree).find(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Tentar análise novamente',
+ );
+ assert.ok(button);
+ button.props.onClick();
+ assert.equal(h.sent.length, 1);
+ assert.equal(
+ h.sent[0][0],
+ '/management/documents/SYNTHETIC-document/malware/retry',
+ );
+ assert.deepEqual(h.sent[0][1], {});
+ assert.equal(h.sent[0][2].preserveScroll, true);
+ assert.deepEqual(h.setters, [true, '']);
+ h.sent[0][2].onError();
+ assert.match(h.setters.at(-1), /Actualize o estado/);
+ h.sent[0][2].onFinish();
+ assert.equal(h.setters.at(-1), false);
+});
+test('public zone attachments expose no retry command', () => {
+ const h = zone(false);
+ assert.equal(
+ nodes(h.tree).filter(
+ (node) =>
+ node.type === 'button' &&
+ node.props.children === 'Tentar análise novamente',
+ ).length,
+ 0,
+ );
+ assert.equal(h.sent.length, 0);
+});
diff --git a/tests/frontend/education-drafts.test.mjs b/tests/frontend/education-drafts.test.mjs
new file mode 100644
index 00000000..da4390b8
--- /dev/null
+++ b/tests/frontend/education-drafts.test.mjs
@@ -0,0 +1,367 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+
+const require = createRequire(import.meta.url);
+function load(path, mocks) {
+ const output = ts.transpileModule(
+ fs.readFileSync(new URL(path, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const emptyProps = {
+ today: '2026-11-02',
+ territories: [],
+ projects: [],
+ courses: [],
+ occupations: [],
+ skills: [],
+ draftsAvailable: true,
+};
+class ApiError extends Error {
+ constructor(status) {
+ super('Synthetic error');
+ this.status = status;
+ this.errors = {};
+ }
+}
+function setup(request, props = emptyProps, renderPage = false) {
+ const states = [];
+ let cursor = 0,
+ form;
+ const Snapshot = () => null;
+ const saved = [],
+ dirty = [];
+ const module = load('../../resources/js/pages/education/index.tsx', {
+ react: {
+ useState(initial) {
+ const index = cursor++;
+ if (!(index in states))
+ states[index] =
+ typeof initial === 'function' ? initial() : initial;
+ return [
+ states[index],
+ (value) => {
+ states[index] =
+ typeof value === 'function'
+ ? value(states[index])
+ : value;
+ },
+ ];
+ },
+ useEffect(fn) {
+ if (!renderPage) fn();
+ },
+ useCallback(fn) {
+ return fn;
+ },
+ },
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {},
+ useForm(initial) {
+ if (renderPage)
+ return {
+ data: initial,
+ errors: {},
+ processing: false,
+ isDirty: false,
+ };
+ form ??= {
+ data: { ...initial },
+ defaults: { ...initial },
+ errors: {},
+ processing: false,
+ get isDirty() {
+ return (
+ JSON.stringify(this.data) !==
+ JSON.stringify(this.defaults)
+ );
+ },
+ setData(key, value) {
+ this.data = { ...this.data, [key]: value };
+ },
+ setDefaults(value) {
+ this.defaults = { ...value };
+ },
+ clearErrors() {
+ this.errors = {};
+ },
+ setError(errors) {
+ this.errors = errors;
+ },
+ post() {
+ throw new Error('Draft must not use legacy create');
+ },
+ };
+ return form;
+ },
+ },
+ '@/lib/portal-api': {
+ portalRequest: request,
+ PortalApiError: ApiError,
+ newSubmissionKey: () => 'synthetic-stable-key',
+ },
+ '@/components/education-submitted-snapshot': {
+ __esModule: true,
+ default: Snapshot,
+ },
+ '../management/shared': {
+ Management: 'main',
+ Field: 'label',
+ control: '',
+ button: '',
+ Pagination: () => null,
+ },
+ '@/components/investment-territory': {
+ TerritoryFields: 'territory-fields',
+ },
+ });
+ return {
+ page() {
+ cursor = 0;
+ return module.default(props);
+ },
+ render() {
+ cursor = 0;
+ return module.Intake({
+ kind: 'demands',
+ props,
+ onSaved: (item) => saved.push(item),
+ onDirty: (kind, value) => dirty.push([kind, value]),
+ });
+ },
+ get form() {
+ return form;
+ },
+ saved,
+ dirty,
+ Snapshot,
+ };
+}
+const saveButton = (tree) =>
+ nodes(tree).find(
+ (node) => node.type === 'button' && node.props.type === 'button',
+ );
+const flush = () => new Promise((resolve) => setImmediate(resolve));
+
+await test('the full education page renders the private draft list and both intake forms', () => {
+ const component = setup(
+ async () => {},
+ {
+ ...emptyProps,
+ filters: {},
+ providers: [],
+ demands: { data: [] },
+ capacities: { data: [] },
+ indicators: {
+ demand_records: 0,
+ capacity_records: 0,
+ expired_demands: 0,
+ pending_demands: 0,
+ },
+ ownDrafts: {
+ data: [
+ {
+ id: 'qa-draft',
+ kind: 'demands',
+ state: 'draft',
+ version_no: 1,
+ label: 'Synthetic qualification',
+ updated_at: '2026-11-02T12:00:00Z',
+ },
+ ],
+ },
+ },
+ true,
+ );
+ const html = renderToStaticMarkup(component.page());
+ assert.ok(html.includes('Os meus rascunhos e submissões'));
+ assert.ok(html.includes('/management/education?draft=qa-draft'));
+ assert.ok(html.includes('Synthetic qualification'));
+ assert.ok(html.includes('Declarar procura de trabalhadores'));
+ assert.ok(html.includes('Declarar vagas de formação'));
+});
+
+await test('incomplete save bypasses native required fields, keeps edits, and submits the saved identity with current values', async () => {
+ const requests = [];
+ const component = setup(async (url, options) => {
+ const data = JSON.parse(options.body);
+ requests.push({ url, method: options.method, data });
+ return {
+ id: 'qa-draft',
+ kind: 'demands',
+ version_no: data.version_no + 1,
+ state: url.endsWith('/submit') ? 'submitted' : 'draft',
+ payload: data.payload,
+ references: {},
+ record_id: null,
+ updated_at: '2026-11-02T12:00:00Z',
+ };
+ });
+ let tree = component.render();
+ component.form.setData('employer', 'Synthetic incomplete employer');
+ tree = component.render();
+ assert.equal(saveButton(tree).props.type, 'button');
+ saveButton(tree).props.onClick();
+ await flush();
+ assert.equal(requests[0].method, 'POST');
+ assert.equal(requests[0].data.payload.qualification, '');
+ assert.equal(component.form.data.employer, 'Synthetic incomplete employer');
+ assert.equal(component.form.isDirty, false);
+ tree = component.render();
+ component.form.setData('quantity', '12');
+ tree = component.render();
+ saveButton(tree).props.onClick();
+ await flush();
+ assert.equal(requests[1].method, 'PUT');
+ assert.equal(requests[1].data.version_no, 1);
+ assert.equal(requests[1].data.client_key, requests[0].data.client_key);
+ tree = component.render();
+ nodes(tree)
+ .find((node) => node.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await flush();
+ assert.equal(
+ requests[2].url,
+ '/management/education/drafts/demands/qa-draft/submit',
+ );
+ assert.equal(requests[2].data.version_no, 2);
+ assert.equal(requests[2].data.payload.quantity, '12');
+ tree = component.render();
+ assert.equal(tree.type, component.Snapshot);
+ assert.equal(tree.props.draft.state, 'submitted');
+ assert.equal(component.saved.length, 3);
+});
+
+await test('recovery preserves blank dates and reference IDs, and a conflict does not overwrite current edits', async () => {
+ const component = setup(
+ async () => {
+ throw new ApiError(409);
+ },
+ {
+ ...emptyProps,
+ selectedDraft: {
+ id: 'recovered',
+ kind: 'demands',
+ version_no: 4,
+ state: 'draft',
+ payload: {
+ employer: 'Old',
+ reference_date: null,
+ geo_location_id: 'retired-location',
+ },
+ references: null,
+ },
+ },
+ );
+ let tree = component.render();
+ assert.equal(component.form.data.reference_date, '');
+ assert.equal(component.form.data.geo_location_id, 'retired-location');
+ component.form.setData('employer', 'Deliberate current edit');
+ tree = component.render();
+ saveButton(tree).props.onClick();
+ await flush();
+ tree = component.render();
+ assert.equal(component.form.data.employer, 'Deliberate current edit');
+ assert.equal(component.form.isDirty, true);
+ assert.ok(
+ nodes(tree).some(
+ (node) =>
+ node.props?.role === 'alert' &&
+ String(node.props.children).includes('noutra sessão'),
+ ),
+ );
+ assert.equal(component.saved.length, 0);
+});
+
+await test('recovered territorial path remains stable while unrelated fields are edited', () => {
+ const territories = [
+ {
+ id: 'p',
+ name: 'Province',
+ parent_id: null,
+ location_type: 'province',
+ },
+ {
+ id: 'd',
+ name: 'District',
+ parent_id: 'p',
+ location_type: 'district',
+ },
+ ];
+ const component = setup(async () => {}, {
+ ...emptyProps,
+ territories,
+ selectedDraft: {
+ id: 'qa',
+ kind: 'demands',
+ version_no: 1,
+ state: 'draft',
+ payload: { geo_location_id: 'd' },
+ },
+ });
+ let tree = component.render();
+ const initial = nodes(tree).find((node) => node.type === 'territory-fields')
+ .props.initial;
+ assert.deepEqual(
+ initial.map((item) => item.id),
+ ['p', 'd'],
+ );
+ component.form.setData('employer', 'New text');
+ tree = component.render();
+ assert.equal(
+ nodes(tree).find((node) => node.type === 'territory-fields').props
+ .initial,
+ initial,
+ );
+});
+
+await test('submitted view uses preserved reference names and escapes source text without another submission form', () => {
+ const Snapshot = load(
+ '../../resources/js/components/education-submitted-snapshot.tsx',
+ { '@inertiajs/react': { Link: 'a' } },
+ ).default;
+ const html = renderToStaticMarkup(
+ Snapshot({
+ draft: {
+ kind: 'demands',
+ record_id: 'qa-record',
+ payload: { quantity: 20, source: '' },
+ references: {
+ project_id: { name: 'Original project name' },
+ territory_path: [{ name: 'Original district' }],
+ },
+ },
+ }),
+ );
+ assert.ok(html.includes('Original project name'));
+ assert.ok(html.includes('Original district'));
+ assert.ok(html.includes('<script>'));
+ assert.ok(!html.includes(' {
+ const h = harness(
+ props({
+ history: {
+ data: [
+ {
+ id: 'one',
+ version: 3,
+ actor: 'SYNTHETIC reviewer',
+ occurred_at: '2026-11-03',
+ available: true,
+ status: 'rejected',
+ reason: 'SYNTHETIC preserved reason',
+ previous_reason: 'SYNTHETIC older reason',
+ },
+ {
+ id: 'two',
+ version: 2,
+ actor: null,
+ occurred_at: '2026-11-02',
+ available: false,
+ status: null,
+ reason: null,
+ previous_reason: null,
+ },
+ ],
+ total: 12,
+ current_page: 1,
+ last_page: 2,
+ prev_page_url: null,
+ next_page_url:
+ '/management/education/demands/one?scope=mine&history_page=2',
+ },
+ }),
+ );
+ assert.match(text(h.tree), /Registos de revisão disponíveis/);
+ assert.match(text(h.tree), /SYNTHETIC preserved reason/);
+ assert.match(
+ text(h.tree),
+ /Fundamento anterior capturado: SYNTHETIC older reason/,
+ );
+ assert.match(text(h.tree), /Fundamento indisponível para leitura/);
+ assert.ok(h.tree);
+});
+test('the submitter sees the declaration without being asked to review it', () => {
+ const initial = props();
+ initial.declaration.can_review = false;
+ initial.declaration.review_unavailable = 'self';
+ const h = harness(initial);
+ assert.equal(h.button('Guardar decisão'), undefined);
+ assert.match(text(h.tree), /outro gestor/);
+});
+test('a newer declaration cannot silently replace the version on which the review was prepared', () => {
+ const h = harness();
+ h.change(
+ form,
+ 'Justificação e evidência da revisão',
+ 'SYNTHETIC prepared reason with evidence.',
+ );
+ h.render({
+ ...h.props,
+ declaration: { ...h.props.declaration, version_no: 2, quantity: 30 },
+ });
+ h.submit(form);
+ assert.equal(h.sent.length, 0);
+});
+
+const reason = 'Justificação e evidência da revisão';
+function prepared(h) {
+ h.change(form, reason, 'SYNTHETIC independent review with evidence.');
+ return h.submit(form);
+}
+function accepted(h, request = h.sent.at(-1), patch = {}) {
+ return {
+ ...h.props,
+ declaration: {
+ ...h.props.declaration,
+ version_no: request.data.version_no + 1,
+ status: request.data.status,
+ review_reason: request.data.review_reason,
+ review_context: {
+ actor_id: h.props.actorId,
+ commands: [
+ {
+ key: request.data.client_key,
+ version: request.data.version_no + 1,
+ },
+ ],
+ },
+ },
+ ...patch,
+ };
+}
+test('explicit comparison adopts the current version without discarding the prepared decision', () => {
+ const h = harness();
+ h.change(form, reason, 'SYNTHETIC prepared reason with evidence.');
+ h.render({
+ ...h.props,
+ declaration: { ...h.props.declaration, version_no: 2, quantity: 30 },
+ });
+ assert.match(text(h.tree), /Analisada: 5.*Actual: 30/);
+ h.click('Confirmar a leitura desta versão');
+ const request = h.submit(form);
+ assert.equal(request.data.version_no, 2);
+ assert.equal(
+ request.data.review_reason,
+ 'SYNTHETIC prepared reason with evidence.',
+ );
+});
+test('confirmation clears only sent event values and preserves later edits', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.change(form, reason, 'SYNTHETIC later reason with evidence.');
+ h.change(form, 'Decisão interna', 'rejected');
+ h.success(accepted(h, request), request);
+ assert.equal(
+ h.field(form, reason).props.value,
+ 'SYNTHETIC later reason with evidence.',
+ );
+ assert.equal(h.field(form, 'Decisão interna').props.value, 'rejected');
+ const next = h.submit(form);
+ assert.equal(next.data.version_no, 2);
+ assert.notEqual(next.data.client_key, request.data.client_key);
+});
+test('an uncertain result retries exactly the original version, decision and key', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.fail(request);
+ h.change(form, reason, 'SYNTHETIC later reason with evidence.');
+ const retry = h.submit(form);
+ assert.deepEqual(retry.data, request.data);
+ h.success(accepted(h, retry), retry);
+ assert.equal(
+ h.field(form, reason).props.value,
+ 'SYNTHETIC later reason with evidence.',
+ );
+});
+test('a fresh authorised read confirms the receipt without sending another decision', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.fail(request, 500);
+ h.click('Actualizar dados da declaração');
+ assert.deepEqual(h.reloads[0].only, [
+ 'declaration',
+ 'references',
+ 'today',
+ 'actorId',
+ 'kind',
+ 'history',
+ ]);
+ h.refreshed(accepted(h, request));
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.field(form, reason).props.value, '');
+ assert.equal(h.leave(), false);
+ assert.match(text(h.tree), /Revisão registada/);
+});
+test('another actor cannot acknowledge or erase a local pending review', () => {
+ const h = harness(),
+ request = prepared(h);
+ request.options.onSuccess({ props: accepted(h, request, { actorId: 3 }) });
+ request.form.processing = false;
+ h.render();
+ assert.equal(
+ h.field(form, reason).props.value,
+ 'SYNTHETIC independent review with evidence.',
+ );
+ assert.deepEqual(h.submit(form).data, request.data);
+});
+test('an obsolete callback cannot alter the draft of the next account', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.render({
+ ...h.props,
+ actorId: 3,
+ declaration: {
+ ...h.props.declaration,
+ review_context: { actor_id: 3, commands: [] },
+ },
+ });
+ h.change(form, reason, 'SYNTHETIC next account review.');
+ request.options.onSuccess({ props: accepted(h, request, { actorId: 1 }) });
+ request.form.processing = false;
+ h.render();
+ assert.equal(
+ h.field(form, reason).props.value,
+ 'SYNTHETIC next account review.',
+ );
+});
+test('a later decision remains current when an earlier receipt is acknowledged', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.fail(request);
+ const next = accepted(h, request);
+ next.declaration.version_no = 3;
+ next.declaration.status = 'rejected';
+ h.render(next);
+ assert.match(text(h.tree), /A declaração mudou/);
+ assert.equal(h.sent.length, 1);
+ h.submit(form);
+ assert.equal(h.sent.length, 1);
+ h.click('Confirmar a leitura desta versão');
+ const fresh = h.submit(form);
+ assert.equal(fresh.data.version_no, 3);
+ assert.notEqual(fresh.data.client_key, request.data.client_key);
+});
+test('a competing newer version without the receipt requires explicit adoption before a new decision', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.fail(request, 409);
+ h.click('Actualizar declaração');
+ h.refreshed({
+ ...h.props,
+ declaration: { ...h.props.declaration, version_no: 2, quantity: 20 },
+ });
+ h.click('Confirmar a leitura desta versão');
+ const next = h.submit(form);
+ assert.equal(next.data.version_no, 2);
+ assert.notEqual(next.data.client_key, request.data.client_key);
+});
+test('expired declarations retain prepared text without a new decision form', () => {
+ const h = harness(),
+ request = prepared(h);
+ h.fail(request, 422);
+ h.render({
+ ...h.props,
+ declaration: {
+ ...h.props.declaration,
+ can_review: false,
+ review_unavailable: 'expired',
+ },
+ });
+ assert.equal(h.button('Guardar decisão'), undefined);
+ assert.equal(h.button('Recuperar a mesma revisão'), undefined);
+ assert.match(text(h.tree), /Fundamento preparado nesta página/);
+ assert.match(text(h.tree), /SYNTHETIC independent review/);
+});
+test('validation preserves the draft and a decision-only change has one leave guard', () => {
+ const h = harness();
+ h.change(form, 'Decisão interna', 'rejected');
+ assert.equal(h.leave(), true);
+ assert.equal(h.confirmCalls, 1);
+ const request = prepared(h);
+ h.validation({ review_reason: 'SYNTHETIC validation' }, request);
+ assert.equal(
+ h.field(form, reason).props.value,
+ 'SYNTHETIC independent review with evidence.',
+ );
+ const next = h.submit(form);
+ assert.notEqual(next.data.client_key, request.data.client_key);
+});
diff --git a/tests/frontend/education-work-queue.test.mjs b/tests/frontend/education-work-queue.test.mjs
new file mode 100644
index 00000000..52418e28
--- /dev/null
+++ b/tests/frontend/education-work-queue.test.mjs
@@ -0,0 +1,164 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+const require = createRequire(import.meta.url),
+ Empty = () => null;
+const mocks = {
+ react: React,
+ '@inertiajs/react': {
+ Link: ({ href, children }) =>
+ React.createElement('a', { href }, children),
+ router: {},
+ useForm: (data) => ({
+ data,
+ errors: {},
+ processing: false,
+ isDirty: false,
+ }),
+ },
+ '@/lib/portal-api': {
+ newSubmissionKey: () => '00000000-0000-4000-8000-000000000001',
+ },
+ '@/components/education-submitted-snapshot': { default: Empty },
+ '@/components/investment-territory': { TerritoryFields: Empty },
+ '../management/shared': {
+ Management: ({ children }) =>
+ React.createElement('main', null, children),
+ Field: ({ label, children }) =>
+ React.createElement('label', null, label, children),
+ Pagination: Empty,
+ control: '',
+ button: '',
+ },
+};
+const output = ts.transpileModule(
+ fs.readFileSync(
+ new URL(
+ '../../resources/js/pages/education/index.tsx',
+ import.meta.url,
+ ),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+).outputText;
+const module = { exports: {} };
+compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+);
+const Index = module.exports.default;
+const counts = {
+ total: 3,
+ submitted: 1,
+ reviewed: 1,
+ rejected: 0,
+ expired: 1,
+ to_review: 2,
+};
+const group = (data) => ({
+ data,
+ total: data.length,
+ current_page: 1,
+ last_page: 1,
+ links: [],
+});
+const base = {
+ today: '2026-11-03',
+ territories: [],
+ projects: [],
+ providers: [],
+ courses: [],
+ occupations: [],
+ skills: [],
+ draftsAvailable: false,
+ ownDrafts: null,
+ filters: { scope: 'all' },
+ workQueue: {
+ actor_id: 1,
+ drafts: 1,
+ demands: counts,
+ capacities: { ...counts, total: 1, submitted: 0, to_review: 4 },
+ },
+ indicators: {
+ demand_records: 42,
+ capacity_records: 17,
+ pending_demands: 9,
+ expired_demands: 4,
+ },
+ demands: group([
+ {
+ id: 'one',
+ qualification: 'SYNTHETIC qualification',
+ quantity: 1000,
+ status: 'submitted',
+ version_no: 1,
+ valid_until: '2027-12-31',
+ period_start: '2027-01-01',
+ period_end: '2027-06-30',
+ source: 'SYNTHETIC source',
+ can_review: false,
+ review_unavailable: 'self',
+ details_url: '/management/education/demands/one?scope=mine',
+ },
+ ]),
+ capacities: group([]),
+};
+const render = (patch) =>
+ renderToStaticMarkup(React.createElement(Index, { ...base, ...patch }));
+test('personal record counts coexist with the unchanged global indicators and retain separate categories', () => {
+ const html = render();
+ assert.match(html, /O meu acompanhamento/);
+ assert.match(html, /Declarações de procura:.*?42/s);
+ assert.match(html, /Submetidas por mim: 3/);
+ assert.match(html, /Submetidas por mim: 1/);
+ assert.doesNotMatch(html, /Submetidas por mim: 1000/);
+ assert.match(html, /Disponíveis para a minha revisão independente: 2/);
+ assert.match(html, /Disponíveis para a minha revisão independente: 4/);
+});
+test('a declaration links to its detailed context and the list no longer asks for repeated review forms', () => {
+ const html = render();
+ assert.ok(
+ html.includes('href="/management/education/demands/one?scope=mine"'),
+ );
+ assert.match(html, /Consultar declaração/);
+ assert.match(html, /a revisão cabe a outro gestor/);
+ assert.doesNotMatch(
+ html,
+ /Guardar decisão|Justificação e evidência da revisão/,
+ );
+});
+test('the independent review scope hides an inapplicable status question and preserves the normal filters', () => {
+ const html = render({
+ filters: { scope: 'review', q: 'SYNTHETIC', status: '' },
+ });
+ assert.match(html, /value="review" selected/);
+ assert.doesNotMatch(html, /Estado/);
+ assert.match(html, /Qualificação/);
+ assert.match(html, /SYNTHETIC/);
+ assert.match(render({ filters: { scope: 'mine' } }), /Estado/);
+});
+test('an unavailable draft count is not presented as zero and declaration text is escaped', () => {
+ const html = render({
+ workQueue: { ...base.workQueue, drafts: null },
+ demands: group([
+ {
+ ...base.demands.data[0],
+ qualification: ' ',
+ },
+ ]),
+ });
+ assert.doesNotMatch(html, /Rascunhos privados por concluir: 0| {
+ state[index] = value;
+ },
+ ];
+ },
+ },
+ '@/lib/portal-api': { portalRequest: request },
+ '@/pages/investment/shared': { card: '', button: '' },
+ };
+ compileFunction(output, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return {
+ render(record) {
+ cursor = 0;
+ return module.exports.default({ record });
+ },
+ };
+}
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const criterion = (code, applies_to) => ({
+ code,
+ applies_to,
+ question: `Question ${code}`,
+ explanation: 'Synthetic condition',
+ source_reference: 'Synthetic source',
+ expected: 'yes',
+});
+const record = {
+ id: 'qa-fund',
+ version_id: 'qa-version',
+ payload: {
+ criteria: [
+ criterion('general', 'all'),
+ criterion('personal', 'individual'),
+ criterion('company', 'entity'),
+ ],
+ windows: [
+ {
+ code: 'qa-window',
+ title: 'Synthetic window',
+ criteria: [criterion('window-rule', 'all')],
+ },
+ ],
+ },
+};
+const field = (tree, name) =>
+ nodes(tree).find((node) => node.props?.name === name);
+
+await test('only applicable answers are submitted while hidden answers survive candidate and window changes', async () => {
+ let sent;
+ const component = setup(async (url, options) => {
+ sent = { url, body: JSON.parse(options.body) };
+ return { notice: 'Synthetic assessment', criteria: [] };
+ });
+ let tree = component.render(record);
+ assert.ok(field(tree, 'criterion-general'));
+ assert.equal(field(tree, 'criterion-personal'), undefined);
+ assert.equal(field(tree, 'criterion-company'), undefined);
+ assert.ok(
+ renderToStaticMarkup(tree).includes('Escolha o tipo de candidato'),
+ );
+ field(tree, 'applicant-kind').props.onChange({
+ target: { value: 'individual' },
+ });
+ tree = component.render(record);
+ field(tree, 'criterion-personal').props.onChange({
+ target: { value: 'yes' },
+ });
+ field(tree, 'funding-window').props.onChange({
+ target: { value: 'qa-window' },
+ });
+ tree = component.render(record);
+ field(tree, 'criterion-window-rule').props.onChange({
+ target: { value: 'no' },
+ });
+ field(tree, 'funding-window').props.onChange({ target: { value: '' } });
+ tree = component.render(record);
+ field(tree, 'applicant-kind').props.onChange({
+ target: { value: 'entity' },
+ });
+ tree = component.render(record);
+ assert.equal(field(tree, 'criterion-personal'), undefined);
+ assert.equal(field(tree, 'criterion-window-rule'), undefined);
+ field(tree, 'criterion-company').props.onChange({
+ target: { value: 'no' },
+ });
+ tree = component.render(record);
+ nodes(tree)
+ .find((node) => node.type === 'button')
+ .props.onClick();
+ await new Promise((resolve) => setImmediate(resolve));
+ assert.equal(sent.url, '/fundos/qa-fund/criterios');
+ assert.equal(sent.body.version_id, 'qa-version');
+ assert.equal(sent.body.applicant_kind, 'entity');
+ assert.deepEqual(sent.body.answers, { general: 'unknown', company: 'no' });
+ tree = component.render(record);
+ field(tree, 'applicant-kind').props.onChange({
+ target: { value: 'individual' },
+ });
+ tree = component.render(record);
+ assert.equal(field(tree, 'criterion-personal').props.value, 'yes');
+ field(tree, 'funding-window').props.onChange({
+ target: { value: 'qa-window' },
+ });
+ tree = component.render(record);
+ assert.equal(field(tree, 'criterion-window-rule').props.value, 'no');
+ assert.ok(!renderToStaticMarkup(tree).includes('Synthetic assessment'));
+});
+
+await test('failed assessment is cleared on a new selection and a programme without windows does not ask for one', async () => {
+ const component = setup(async () => {
+ throw new Error('Synthetic stale-version error');
+ });
+ const item = { ...record, payload: { ...record.payload, windows: [] } };
+ let tree = component.render(item);
+ assert.equal(field(tree, 'funding-window'), undefined);
+ nodes(tree)
+ .find((node) => node.type === 'button')
+ .props.onClick();
+ await new Promise((resolve) => setImmediate(resolve));
+ tree = component.render(item);
+ assert.ok(
+ renderToStaticMarkup(tree).includes('Synthetic stale-version error'),
+ );
+ field(tree, 'applicant-kind').props.onChange({
+ target: { value: 'individual' },
+ });
+ tree = component.render(item);
+ assert.ok(
+ !renderToStaticMarkup(tree).includes('Synthetic stale-version error'),
+ );
+});
diff --git a/tests/frontend/helpers/crm-task-creation.mjs b/tests/frontend/helpers/crm-task-creation.mjs
new file mode 100644
index 00000000..1f246195
--- /dev/null
+++ b/tests/frontend/helpers/crm-task-creation.mjs
@@ -0,0 +1,437 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const leadId = '10000000-0000-4000-8000-000000000001';
+export function props(patch = {}) {
+ return {
+ lead: {
+ id: leadId,
+ version_no: 1,
+ title: 'SYNTHETIC lead',
+ status: 'new',
+ owner_user_id: 1,
+ tasks: [],
+ },
+ contacts: [],
+ owners: [
+ { id: 1, name: 'SYNTHETIC manager' },
+ { id: 2, name: 'SYNTHETIC colleague' },
+ ],
+ nextAction: { future_tasks: 0 },
+ taskCreation: { lead_id: leadId, actor_id: 1, commands: [] },
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+const clone = (value) =>
+ Array.isArray(value)
+ ? value.map(clone)
+ : value && Object.getPrototypeOf(value) === Object.prototype
+ ? Object.fromEntries(
+ Object.entries(value).map(([k, v]) => [k, clone(v)]),
+ )
+ : value;
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ usePage: () => ({
+ props: { auth: { user: { id: current.actorId ?? 1 } } },
+ }),
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ on(name, callback) {
+ if (name === 'before') before.add(callback);
+ return () => before.delete(callback);
+ },
+ post(url, data) {
+ sent.push({ method: 'post', url, data, options: {} });
+ },
+ },
+ useForm(initialData) {
+ const i = cursor++;
+ if (active.cells[i]) return active.cells[i];
+ const form = {
+ data: clone(initialData),
+ defaults: clone(initialData),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ changed = true;
+ },
+ setDefaults(data) {
+ this.defaults = clone(data);
+ },
+ clearErrors() {
+ this.errors = {};
+ changed = true;
+ },
+ reset(...keys) {
+ for (const key of keys)
+ this.data[key] = this.defaults[key];
+ changed = true;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ };
+ for (const method of ['post', 'put', 'patch'])
+ form[method] = (url, options) => {
+ form.processing = true;
+ changed = true;
+ sent.push({
+ method,
+ url,
+ options,
+ data: clone(
+ form.transformer
+ ? form.transformer(form.data)
+ : form.data,
+ ),
+ form,
+ });
+ };
+ active.cells[i] = form;
+ return form;
+ },
+ },
+ '../management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/pages/management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/components/crm-edit-comparison': { default: () => null },
+ '@/lib/crm-record-edit': {
+ useCrmRecordEdit: ({ values }) => ({
+ form: { processing: false },
+ values,
+ error: () => undefined,
+ blocked: false,
+ }),
+ },
+ './types': {
+ leadStates: { new: 'Novo', qualified: 'Qualificado' },
+ taskStates: { open: 'Aberta', done: 'Conclu?da' },
+ },
+ };
+ const operation = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['./operation-key'] = operation;
+ mocks['@/lib/operation-key'] = operation;
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['./profile-json'] = load('resources/js/lib/profile-json.ts');
+ mocks['./crm-task-preparation'] = load(
+ 'resources/js/lib/crm-task-preparation.ts',
+ );
+ for (const [name, path] of [
+ ['@/lib/crm-task-creation', 'resources/js/lib/crm-task-creation.ts'],
+ [
+ '@/components/crm-task-creation',
+ 'resources/js/components/crm-task-creation.tsx',
+ ],
+ ])
+ if (fs.existsSync(new URL('../../../' + path, import.meta.url)))
+ mocks[name] = load(path);
+ const Page = load('resources/js/pages/crm/lead.tsx').default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ all: () => nodes(tree),
+ form(name) {
+ return nodes(tree).find((node) => node.props?.id === name);
+ },
+ button(label, scope = tree) {
+ return nodes(scope).find(
+ (node) => node.type === 'button' && text(node) === label,
+ );
+ },
+ field(name, label) {
+ const root = this.form(name);
+ const field = nodes(root).find(
+ (node) => node.type === 'label' && node.props.label === label,
+ );
+ return nodes(field).find((node) =>
+ ['input', 'select', 'textarea'].includes(node.type),
+ );
+ },
+ change(name, label, value, rerender = true) {
+ const field = this.field(name, label);
+ if (!field) throw Error('Missing field ' + name + '/' + label);
+ field.props.onChange({
+ target: { value, checked: value, files: value ? [value] : [] },
+ });
+ if (rerender) render();
+ },
+ submit(name) {
+ const form = this.form(name);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, scope = tree) {
+ const button = this.button(label, scope);
+ if (!button) throw Error('Missing button ' + label);
+ button.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ success(next, request = sent.at(-1)) {
+ render(next);
+ request.options.onSuccess?.({ props: next });
+ request.form.processing = false;
+ render(next);
+ },
+ validation(errors, request = sent.at(-1)) {
+ request.form.errors = errors;
+ request.options.onError?.(errors);
+ request.form.processing = false;
+ render();
+ },
+ fail(request = sent.at(-1), status = null) {
+ if (status === null) request.options.onNetworkError();
+ else request.options.onHttpException({ status });
+ request.form.processing = false;
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ return prevented;
+ },
+ unload() {
+ let prevented = false;
+ for (const fn of unload)
+ fn({
+ preventDefault() {
+ prevented = true;
+ },
+ returnValue: null,
+ });
+ return prevented;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/crm-task-preparation.mjs b/tests/frontend/helpers/crm-task-preparation.mjs
new file mode 100644
index 00000000..5dd0cfd6
--- /dev/null
+++ b/tests/frontend/helpers/crm-task-preparation.mjs
@@ -0,0 +1,505 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const leadId = '10000000-0000-4000-8000-000000000001';
+export function props(patch = {}) {
+ return {
+ lead: {
+ id: leadId,
+ version_no: 1,
+ title: 'SYNTHETIC lead',
+ status: 'new',
+ owner_user_id: 1,
+ tasks: [],
+ },
+ contacts: [],
+ owners: [
+ { id: 1, name: 'SYNTHETIC manager' },
+ { id: 2, name: 'SYNTHETIC colleague' },
+ ],
+ nextAction: { future_tasks: 0 },
+ taskCreation: {
+ lead_id: leadId,
+ actor_id: 1,
+ commands: [],
+ preparation: {
+ installed: true,
+ version: 0,
+ snapshot: null,
+ operation_key: null,
+ updated_at: null,
+ unavailable: false,
+ },
+ },
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+const clone = (value) =>
+ Array.isArray(value)
+ ? value.map(clone)
+ : value && Object.getPrototypeOf(value) === Object.prototype
+ ? Object.fromEntries(
+ Object.entries(value).map(([k, v]) => [k, clone(v)]),
+ )
+ : value;
+export function harness(initial = props()) {
+ const draftRequests = [],
+ timers = new Map();
+ let timerSequence = 0;
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ usePage: () => ({
+ props: { auth: { user: { id: current.actorId ?? 1 } } },
+ }),
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ on(name, callback) {
+ if (name === 'before') before.add(callback);
+ return () => before.delete(callback);
+ },
+ post(url, data) {
+ sent.push({ method: 'post', url, data, options: {} });
+ },
+ },
+ useForm(initialData) {
+ const i = cursor++;
+ if (active.cells[i]) return active.cells[i];
+ const form = {
+ data: clone(initialData),
+ defaults: clone(initialData),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ changed = true;
+ },
+ setDefaults(data) {
+ this.defaults = clone(data);
+ },
+ clearErrors() {
+ this.errors = {};
+ changed = true;
+ },
+ reset(...keys) {
+ for (const key of keys)
+ this.data[key] = this.defaults[key];
+ changed = true;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ };
+ for (const method of ['post', 'put', 'patch'])
+ form[method] = (url, options) => {
+ form.processing = true;
+ changed = true;
+ sent.push({
+ method,
+ url,
+ options,
+ data: clone(
+ form.transformer
+ ? form.transformer(form.data)
+ : form.data,
+ ),
+ form,
+ });
+ };
+ active.cells[i] = form;
+ return form;
+ },
+ },
+ '../management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/pages/management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/components/crm-edit-comparison': { default: () => null },
+ '@/lib/crm-record-edit': {
+ useCrmRecordEdit: ({ values }) => ({
+ form: { processing: false },
+ values,
+ error: () => undefined,
+ blocked: false,
+ }),
+ },
+ './types': {
+ leadStates: { new: 'Novo', qualified: 'Qualificado' },
+ taskStates: { open: 'Aberta', done: 'Conclu?da' },
+ },
+ };
+ const operation = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['./operation-key'] = operation;
+ mocks['@/lib/operation-key'] = operation;
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, [
+ 'require',
+ 'module',
+ 'exports',
+ 'setTimeout',
+ 'clearTimeout',
+ ])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ (callback) => {
+ const id = ++timerSequence;
+ timers.set(id, callback);
+ return id;
+ },
+ (id) => timers.delete(id),
+ );
+ return module.exports;
+ }
+ mocks['./profile-json'] = {
+ ...load('resources/js/lib/profile-json.ts'),
+ profileJson: (url, data, method = 'POST') =>
+ new Promise((resolve, reject) =>
+ draftRequests.push({ url, data, method, resolve, reject }),
+ ),
+ };
+ mocks['./crm-task-preparation'] = load(
+ 'resources/js/lib/crm-task-preparation.ts',
+ );
+ for (const [name, path] of [
+ ['@/lib/crm-task-creation', 'resources/js/lib/crm-task-creation.ts'],
+ [
+ '@/components/crm-task-creation',
+ 'resources/js/components/crm-task-creation.tsx',
+ ],
+ ])
+ if (fs.existsSync(new URL('../../../' + path, import.meta.url)))
+ mocks[name] = load(path);
+ const Page = load('resources/js/pages/crm/lead.tsx').default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ draftRequests,
+ async validationDraft(fields, request = draftRequests.at(-1)) {
+ request.reject(
+ new mocks['./profile-json'].ProfileValidationError(
+ 'SYNTHETIC validation',
+ fields,
+ ),
+ );
+ await new Promise((resolve) => setImmediate(resolve));
+ render();
+ },
+ async flush() {
+ await new Promise((resolve) => setImmediate(resolve));
+ render();
+ },
+ async tick() {
+ const queue = [...timers.values()];
+ timers.clear();
+ queue.forEach((fn) => fn());
+ await Promise.resolve();
+ render();
+ },
+ async respond(value, request = draftRequests.at(-1)) {
+ request.resolve(value);
+ await new Promise((resolve) => setImmediate(resolve));
+ render();
+ },
+ async rejectDraft(request = draftRequests.at(-1)) {
+ request.reject(new Error('SYNTHETIC network failure'));
+ await new Promise((resolve) => setImmediate(resolve));
+ render();
+ },
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ all: () => nodes(tree),
+ form(name) {
+ return nodes(tree).find((node) => node.props?.id === name);
+ },
+ button(label, scope = tree) {
+ return nodes(scope).find(
+ (node) => node.type === 'button' && text(node) === label,
+ );
+ },
+ field(name, label) {
+ const root = this.form(name);
+ const field = nodes(root).find(
+ (node) =>
+ node.type === 'label' &&
+ (node.props.label === label ||
+ text(node).startsWith(label)),
+ );
+ return nodes(field).find((node) =>
+ ['input', 'select', 'textarea'].includes(node.type),
+ );
+ },
+ change(name, label, value, rerender = true) {
+ const field = this.field(name, label);
+ if (!field) throw Error('Missing field ' + name + '/' + label);
+ field.props.onChange({
+ target: { value, checked: value, files: value ? [value] : [] },
+ });
+ if (rerender) render();
+ },
+ submit(name) {
+ const form = this.form(name);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, scope = tree) {
+ const button = this.button(label, scope);
+ if (!button) throw Error('Missing button ' + label);
+ button.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ success(next, request = sent.at(-1)) {
+ render(next);
+ request.options.onSuccess?.({ props: next });
+ request.form.processing = false;
+ render(next);
+ },
+ validation(errors, request = sent.at(-1)) {
+ request.form.errors = errors;
+ request.options.onError?.(errors);
+ request.form.processing = false;
+ render();
+ },
+ fail(request = sent.at(-1), status = null) {
+ if (status === null) request.options.onNetworkError();
+ else request.options.onHttpException({ status });
+ request.form.processing = false;
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ return prevented;
+ },
+ unload() {
+ let prevented = false;
+ for (const fn of unload)
+ fn({
+ preventDefault() {
+ prevented = true;
+ },
+ returnValue: null,
+ });
+ return prevented;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/education-review.mjs b/tests/frontend/helpers/education-review.mjs
new file mode 100644
index 00000000..fc9a1548
--- /dev/null
+++ b/tests/frontend/helpers/education-review.mjs
@@ -0,0 +1,475 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+const require = createRequire(import.meta.url);
+export const recordId = '10000000-0000-4000-8000-000000000001';
+export function props(patch = {}) {
+ return {
+ declaration: {
+ id: recordId,
+ qualification: 'SYNTHETIC qualification',
+ quantity: 5,
+ status: 'submitted',
+ version_no: 1,
+ valid_until: '2027-12-31',
+ period_start: '2027-01-01',
+ period_end: '2027-06-30',
+ reference_date: '2026-10-01',
+ source: 'SYNTHETIC source',
+ submitted_by: 2,
+ reviewed_by: null,
+ review_reason: null,
+ can_review: true,
+ review_unavailable: null,
+ review_context: { actor_id: 1, commands: [] },
+ },
+ kind: 'demands',
+ actorId: 1,
+ today: '2026-11-03',
+ backUrl: '/management/education',
+ references: {},
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+const clone = (value) =>
+ Array.isArray(value)
+ ? value.map(clone)
+ : value && Object.getPrototypeOf(value) === Object.prototype
+ ? Object.fromEntries(
+ Object.entries(value).map(([k, v]) => [k, clone(v)]),
+ )
+ : value;
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ usePage: () => ({
+ props: { auth: { user: { id: current.actorId ?? 1 } } },
+ }),
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ on(name, callback) {
+ if (name === 'before') before.add(callback);
+ return () => before.delete(callback);
+ },
+ post(url, data) {
+ sent.push({ method: 'post', url, data, options: {} });
+ },
+ },
+ useForm(initialData) {
+ const i = cursor++;
+ if (active.cells[i]) return active.cells[i];
+ const form = {
+ data: clone(initialData),
+ defaults: clone(initialData),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ changed = true;
+ },
+ setDefaults(data) {
+ this.defaults = clone(data);
+ },
+ clearErrors() {
+ this.errors = {};
+ changed = true;
+ },
+ reset(...keys) {
+ for (const key of keys)
+ this.data[key] = this.defaults[key];
+ changed = true;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ };
+ for (const method of ['post', 'put', 'patch'])
+ form[method] = (url, options) => {
+ form.processing = true;
+ changed = true;
+ sent.push({
+ method,
+ url,
+ options,
+ data: clone(
+ form.transformer
+ ? form.transformer(form.data)
+ : form.data,
+ ),
+ form,
+ });
+ };
+ active.cells[i] = form;
+ return form;
+ },
+ },
+ '../management/shared': {
+ Management: 'main',
+ Pagination: ({ page }) =>
+ React.createElement(
+ 'a',
+ { href: page.next_page_url },
+ 'Mais registos',
+ ),
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/pages/management/shared': {
+ Management: 'main',
+ Field: 'label',
+ button: '',
+ control: '',
+ },
+ '@/components/crm-edit-comparison': { default: () => null },
+ '@/lib/crm-record-edit': {
+ useCrmRecordEdit: ({ values }) => ({
+ form: { processing: false },
+ values,
+ error: () => undefined,
+ blocked: false,
+ }),
+ },
+ './types': {
+ leadStates: { new: 'Novo', qualified: 'Qualificado' },
+ taskStates: { open: 'Aberta', done: 'Conclu?da' },
+ },
+ };
+ const operation = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['./operation-key'] = operation;
+ mocks['@/lib/operation-key'] = operation;
+ function load(path, extra = '') {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ) + extra,
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['@/lib/portal-api'] = {};
+ mocks['@/components/education-submitted-snapshot'] = {
+ default: () => null,
+ };
+ mocks['@/components/investment-territory'] = {
+ TerritoryFields: () => null,
+ };
+ for (const [name, path] of [
+ ['@/lib/education-review', 'resources/js/lib/education-review.ts'],
+ [
+ '@/components/education-review',
+ 'resources/js/components/education-review.tsx',
+ ],
+ ])
+ if (fs.existsSync(new URL('../../../' + path, import.meta.url)))
+ mocks[name] = load(path);
+ let Page;
+ if (
+ fs.existsSync(
+ new URL(
+ '../../../resources/js/pages/education/declaration.tsx',
+ import.meta.url,
+ ),
+ )
+ )
+ Page = load('resources/js/pages/education/declaration.tsx').default;
+ else {
+ const Review = load(
+ 'resources/js/pages/education/index.tsx',
+ '\nexport { Review };',
+ ).Review;
+ Page = ({ declaration: row, kind, today, actorId }) =>
+ Review({ row, kind, today, actorId });
+ }
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ all: () => nodes(tree),
+ form(name) {
+ return (
+ nodes(tree).find((node) => node.props?.id === name) ??
+ nodes(tree).find((node) => node.type === 'form')
+ );
+ },
+ button(label, scope = tree) {
+ return nodes(scope).find(
+ (node) => node.type === 'button' && text(node) === label,
+ );
+ },
+ field(name, label) {
+ const root = this.form(name);
+ const field = nodes(root).find(
+ (node) => node.type === 'label' && node.props.label === label,
+ );
+ return nodes(field).find((node) =>
+ ['input', 'select', 'textarea'].includes(node.type),
+ );
+ },
+ change(name, label, value, rerender = true) {
+ const field = this.field(name, label);
+ if (!field) throw Error('Missing field ' + name + '/' + label);
+ field.props.onChange({
+ target: { value, checked: value, files: value ? [value] : [] },
+ });
+ if (rerender) render();
+ },
+ submit(name) {
+ const form = this.form(name);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, scope = tree) {
+ const button = this.button(label, scope);
+ if (!button) throw Error('Missing button ' + label);
+ button.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ success(next, request = sent.at(-1)) {
+ render(next);
+ request.options.onSuccess?.({ props: next });
+ request.form.processing = false;
+ render(next);
+ },
+ validation(errors, request = sent.at(-1)) {
+ request.form.errors = errors;
+ request.options.onError?.(errors);
+ request.form.processing = false;
+ render();
+ },
+ fail(request = sent.at(-1), status = null) {
+ if (status === null) request.options.onNetworkError();
+ else request.options.onHttpException({ status });
+ request.form.processing = false;
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ return prevented;
+ },
+ unload() {
+ let prevented = false;
+ for (const fn of unload)
+ fn({
+ preventDefault() {
+ prevented = true;
+ },
+ returnValue: null,
+ });
+ return prevented;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/investment-profile-editor.mjs b/tests/frontend/helpers/investment-profile-editor.mjs
new file mode 100644
index 00000000..621df28a
--- /dev/null
+++ b/tests/frontend/helpers/investment-profile-editor.mjs
@@ -0,0 +1,402 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const companyId = '10000000-0000-4000-8000-000000000001';
+export function props(patch = {}) {
+ return {
+ actorId: 1,
+ account: {
+ version: 1,
+ payload: {
+ residence_country_code: 'PT',
+ phone: 'SYNTHETIC phone',
+ country: 'SYNTHETIC historical',
+ },
+ },
+ companies: [
+ {
+ id: companyId,
+ version: 1,
+ payload: {
+ name: 'SYNTHETIC company',
+ incorporation_country_code: 'MZ',
+ role: 'SYNTHETIC role',
+ },
+ },
+ ],
+ countries: [
+ { code: 'PT', name: 'Portugal', name_en: 'Portugal' },
+ { code: 'FR', name: 'France', name_en: 'France' },
+ { code: 'MZ', name: 'Mo\u00e7ambique', name_en: 'Mozambique' },
+ { code: 'ZA', name: '\u00c1frica do Sul', name_en: 'South Africa' },
+ ],
+ organizations: [],
+ organizationCountryAvailable: true,
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useId() {
+ const i = cursor++;
+ active.cells[i] ??= 'SYNTHETIC-id-' + ++sequence;
+ return active.cells[i];
+ },
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ class ApiError extends Error {
+ constructor(status, errors = {}) {
+ super('SYNTHETIC HTTP ' + status);
+ this.status = status;
+ this.errors = errors;
+ }
+ }
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {
+ reload: (options) => reloads.push(options),
+ on(name, fn) {
+ if (name === 'before') before.add(fn);
+ return () => before.delete(fn);
+ },
+ },
+ },
+ './shared': {
+ Frame: 'main',
+ Field: 'label',
+ input: '',
+ button: '',
+ card: '',
+ },
+ '@/pages/investment/shared': {
+ Field: 'label',
+ input: '',
+ button: '',
+ card: '',
+ },
+ '@/components/partnership-source-links': { default: () => null },
+ '@/pages/management/shared': { button: '', control: '' },
+ };
+ mocks['./portal-api'] = {
+ PortalApiError: ApiError,
+ portalRequest: (url, options = {}) =>
+ new Promise((resolve, reject) =>
+ sent.push({
+ url,
+ data: options.body ? JSON.parse(options.body) : undefined,
+ method: options.method ?? 'GET',
+ resolve,
+ reject,
+ }),
+ ),
+ };
+ mocks['./operation-key'] = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['@/lib/portal-api'] = mocks['./portal-api'];
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['@/lib/page-preparation-guard'] = load(
+ 'resources/js/lib/page-preparation-guard.ts',
+ );
+ mocks['@/lib/investment-profile-editor'] = load(
+ 'resources/js/lib/investment-profile-editor.ts',
+ );
+ mocks['./country-select'] = load(
+ 'resources/js/components/country-select.tsx',
+ );
+ mocks['@/components/country-select'] = mocks['./country-select'];
+ mocks['@/lib/organization-country-reuse'] = load(
+ 'resources/js/lib/organization-country-reuse.ts',
+ );
+ mocks['./organization-country-reuse'] = load(
+ 'resources/js/components/organization-country-reuse.tsx',
+ );
+ mocks['@/components/investment-profile-editor'] = load(
+ 'resources/js/components/investment-profile-editor.tsx',
+ );
+ mocks['@/components/organization-country-editor'] = load(
+ 'resources/js/components/organization-country-editor.tsx',
+ );
+ const Page = load('resources/js/pages/investment/profile.tsx').default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window,
+ previousDocument = globalThis.document;
+ globalThis.window = windowMock;
+ globalThis.document = {
+ getElementById: () => ({ querySelector: () => ({ focus() {} }) }),
+ };
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ globalThis.document = previousDocument;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ form(label) {
+ return nodes(tree).find(
+ (n) => n.type === 'form' && n.props['aria-label'] === label,
+ );
+ },
+ field(label, formLabel) {
+ return nodes(formLabel ? this.form(formLabel) : tree).find(
+ (n) =>
+ ['input', 'textarea', 'select'].includes(n.type) &&
+ n.props['aria-label'] === label,
+ );
+ },
+ value(label, formLabel) {
+ return this.field(label, formLabel)?.props.value;
+ },
+ change(label, value, formLabel) {
+ const field = this.field(label, formLabel);
+ if (!field) throw Error('Missing field ' + label);
+ field.props.onChange({ target: { value } });
+ render();
+ },
+ button(label, formLabel) {
+ return nodes(formLabel ? this.form(formLabel) : tree).find(
+ (n) => n.type === 'button' && text(n) === label,
+ );
+ },
+ submit(formLabel) {
+ const form = this.form(formLabel);
+ if (!form) throw Error('Missing form ' + formLabel);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, formLabel) {
+ const node = this.button(label, formLabel);
+ if (!node) throw Error('Missing button ' + label);
+ const priorWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ node.props.onClick();
+ } finally {
+ globalThis.window = priorWindow;
+ }
+ render();
+ return sent.at(-1);
+ },
+ async reply(value, request = sent.at(-1)) {
+ request.resolve(value);
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ async fail(status = null, request = sent.at(-1), errors = {}) {
+ request.reject(
+ status === null
+ ? new Error('SYNTHETIC network loss')
+ : new ApiError(status, errors),
+ );
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const old = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = old;
+ }
+ return prevented;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/partnership-candidacy.mjs b/tests/frontend/helpers/partnership-candidacy.mjs
new file mode 100644
index 00000000..3682c2b3
--- /dev/null
+++ b/tests/frontend/helpers/partnership-candidacy.mjs
@@ -0,0 +1,548 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const criteria = [
+ {
+ code: 'capacity',
+ label: 'Capacidade técnica/produtiva',
+ weight: 20,
+ mandatory: true,
+ state: 'unknown',
+ evidence: null,
+ explanation: 'SYNTHETIC unknown',
+ },
+ {
+ code: 'experience',
+ label: 'Experiência comprovada',
+ weight: 10,
+ mandatory: false,
+ state: 'unknown',
+ evidence: null,
+ explanation: 'SYNTHETIC unknown',
+ },
+];
+export const original = {
+ id: 10,
+ user_id: 2,
+ partnership_id: 1,
+ version: 1,
+ status: 'submitted',
+ organization_id: null,
+ proposal: 'SYNTHETIC original proposal',
+ payload: {
+ capacity: 'SYNTHETIC original capacity',
+ availability: 'SYNTHETIC original availability',
+ contribution: 'SYNTHETIC original contribution',
+ conflicts: 'SYNTHETIC original conflicts',
+ consent: true,
+ },
+ assessment: [],
+ decision_reason: null,
+ can_edit: true,
+ commands: [],
+ match: {
+ weights_hash: 'a'.repeat(64),
+ score_min: 0,
+ score_max: 100,
+ eligibility: 'unknown',
+ criteria,
+ },
+ room_id: null,
+};
+export function props(patch = {}) {
+ return {
+ actorId: 2,
+ record: {
+ id: 1,
+ version: 4,
+ title: 'SYNTHETIC partnership',
+ kind: 'seeking',
+ partnership_type: 'joint_venture',
+ sector_id: null,
+ deadline: null,
+ status: 'published',
+ offer: 'SYNTHETIC offer',
+ seeking: 'SYNTHETIC cooperation',
+ payload: {
+ summary: 'SYNTHETIC summary',
+ requirements: 'SYNTHETIC requirements',
+ consent: true,
+ },
+ },
+ owner: false,
+ moderator: false,
+ canEdit: false,
+ acceptingInterests: true,
+ canStartInterest: false,
+ interests: [structuredClone(original)],
+ organizations: [],
+ types: { joint_venture: 'Consórcio' },
+ sectors: [],
+ territories: [],
+ criteria: {},
+ sources: [],
+ origins: [],
+ locations: [],
+ historySummary: Object.hasOwn(patch, 'historySummary')
+ ? patch.historySummary
+ : patch.owner || patch.moderator
+ ? {
+ limit: 5,
+ entries: [],
+ has_more: false,
+ href: `/parcerias/${patch.record?.id ?? 1}/historico`,
+ }
+ : null,
+ publicationActions: [],
+ publicationCommands: [],
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+const clone = (value) =>
+ Array.isArray(value)
+ ? value.map(clone)
+ : value && Object.getPrototypeOf(value) === Object.prototype
+ ? Object.fromEntries(
+ Object.entries(value).map(([k, v]) => [k, clone(v)]),
+ )
+ : value;
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const setters = new WeakMap();
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ if (!setters.has(frame)) setters.set(frame, new Map());
+ const stable = setters.get(frame);
+ if (!stable.has(i))
+ stable.set(i, (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ });
+ return [frame.cells[i], stable.get(i)];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ usePage: () => ({
+ props: {
+ auth: {
+ user:
+ current.actorId === null
+ ? null
+ : { id: current.actorId ?? 2 },
+ },
+ },
+ }),
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ on(name, callback) {
+ if (name === 'before') before.add(callback);
+ return () => before.delete(callback);
+ },
+ post(url, data) {
+ sent.push({ method: 'post', url, data, options: {} });
+ },
+ },
+ useForm(initialData) {
+ const i = cursor++;
+ if (active.cells[i]) return active.cells[i];
+ const form = {
+ data: clone(initialData),
+ defaults: clone(initialData),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ changed = true;
+ },
+ setDefaults(data) {
+ this.defaults = clone(data);
+ },
+ clearErrors() {
+ this.errors = {};
+ changed = true;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ };
+ for (const method of ['post', 'put'])
+ form[method] = (url, options) => {
+ form.processing = true;
+ changed = true;
+ sent.push({
+ method,
+ url,
+ options,
+ data: clone(
+ form.transformer
+ ? form.transformer(form.data)
+ : form.data,
+ ),
+ form,
+ });
+ };
+ active.cells[i] = form;
+ return form;
+ },
+ },
+ '@/pages/partnerships/shared': {
+ labels: {
+ negotiation: 'Em negociação',
+ agreement_recorded: 'Acordo registado',
+ agreed: 'Confirmado pelas partes',
+ execution: 'Em execução',
+ closed: 'Concluída',
+ cancelled: 'Cancelada',
+ pending: 'Pendente',
+ progress: 'Em curso',
+ completed: 'Concluído',
+ },
+ },
+ './shared': {
+ Frame: 'main',
+ Field: 'label',
+ Errors: 'errors',
+ labels: {
+ pending: 'Submetida — legado',
+ progress: 'Em curso',
+ completed: 'Concluído',
+ },
+ },
+ };
+ const operation = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['./operation-key'] = operation;
+ mocks['@/lib/operation-key'] = operation;
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['./shared'].labels = {
+ draft: 'Rascunho',
+ pending: 'Submetida — legado',
+ submitted: 'Submetida',
+ returned: 'Devolvida',
+ rejected: 'Rejeitada',
+ published: 'Publicada',
+ suspended: 'Suspensa',
+ archived: 'Arquivada',
+ withdrawn: 'Retirada',
+ clarification: 'Em esclarecimento',
+ shortlisted: 'Lista curta',
+ negotiation: 'Em negociação',
+ agreement_recorded: 'Acordo registado',
+ agreed: 'Confirmado pelas partes',
+ execution: 'Em execução',
+ closed: 'Concluída',
+ cancelled: 'Cancelada',
+ progress: 'Em curso',
+ completed: 'Concluído',
+ met: 'Comprovadamente cumprido',
+ unmet: 'Comprovadamente incumprido',
+ unknown: 'Informação insuficiente',
+ };
+ mocks['@/pages/partnerships/shared'] = mocks['./shared'];
+ mocks['@/components/investment-complements'] = {
+ ComplementEntryActions: 'complements',
+ };
+ mocks['@/components/structure-geography'] = {
+ __esModule: true,
+ default: 'geography',
+ };
+ mocks['@/lib/partnership-candidacy-edit'] = load(
+ 'resources/js/lib/partnership-candidacy-edit.ts',
+ );
+ mocks['@/components/partnership-candidacies'] = load(
+ 'resources/js/components/partnership-candidacies.tsx',
+ );
+ mocks['@/lib/partnership-publication'] = load(
+ 'resources/js/lib/partnership-publication.ts',
+ );
+ mocks['@/components/partnership-publication'] = load(
+ 'resources/js/components/partnership-publication.tsx',
+ );
+ mocks['@/lib/partnership-history'] = load(
+ 'resources/js/lib/partnership-history.ts',
+ );
+ mocks['@/components/partnership-publication-summary'] = load(
+ 'resources/js/components/partnership-publication-summary.tsx',
+ );
+ const Page = load('resources/js/pages/partnerships/detail.tsx').default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ all: () => nodes(tree),
+ form(name) {
+ return nodes(tree).find(
+ (node) => node.props?.['data-candidacy-form'] === name,
+ );
+ },
+ button(label, scope = tree) {
+ return nodes(scope).find(
+ (node) => node.type === 'button' && text(node) === label,
+ );
+ },
+ field(name, label) {
+ const root = this.form(name);
+ const field = nodes(root).find(
+ (node) => node.type === 'label' && node.props.label === label,
+ );
+ return nodes(field).find((node) =>
+ ['input', 'select', 'textarea'].includes(node.type),
+ );
+ },
+ change(name, label, value, rerender = true) {
+ const field = this.field(name, label);
+ if (!field) throw Error('Missing field ' + name + '/' + label);
+ field.props.onChange({
+ target: { value, checked: value, files: value ? [value] : [] },
+ });
+ if (rerender) render();
+ },
+ submit(name) {
+ const form = this.form(name);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, scope = tree) {
+ const button = this.button(label, scope);
+ if (!button) throw Error('Missing button ' + label);
+ button.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ success(next, request = sent.at(-1)) {
+ render(next);
+ request.options.onSuccess({ props: next });
+ request.form.processing = false;
+ render(next);
+ },
+ fail(request = sent.at(-1), status = null) {
+ if (status === null) request.options.onNetworkError();
+ else request.options.onHttpException({ status });
+ request.form.processing = false;
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ return prevented;
+ },
+ unload() {
+ let prevented = false;
+ for (const fn of unload)
+ fn({
+ preventDefault() {
+ prevented = true;
+ },
+ returnValue: null,
+ });
+ return prevented;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/partnership-room.mjs b/tests/frontend/helpers/partnership-room.mjs
new file mode 100644
index 00000000..605ba8ac
--- /dev/null
+++ b/tests/frontend/helpers/partnership-room.mjs
@@ -0,0 +1,459 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const participant = (id, name, parties = ['proponent']) => ({
+ id,
+ name,
+ parties,
+});
+export const original = {
+ id: 7,
+ title: 'SYNTHETIC milestone',
+ responsible_id: 1,
+ responsible_name: 'SYNTHETIC original author',
+ responsible_is_participant: true,
+ due_date: null,
+ status: 'pending',
+ evidence: null,
+ version: 3,
+ client_key: null,
+};
+export function props(patch = {}) {
+ return {
+ room: {
+ id: 10,
+ version: 2,
+ status: 'agreement_recorded',
+ agreement: {
+ title: 'SYNTHETIC instrument',
+ terms: 'SYNTHETIC terms',
+ confirmations: {},
+ legal_signature_status: 'not_verified',
+ },
+ },
+ agreementActorId: 1,
+ agreementCommands: [],
+ agreementParty: 'proponent',
+ partnership: {
+ id: 1,
+ title: 'SYNTHETIC partnership',
+ user_id: 1,
+ version: 4,
+ },
+ interest: { id: 2, user_id: 2, version: 3 },
+ canWrite: true,
+ participants: [
+ participant(1, 'SYNTHETIC original author'),
+ participant(2, 'SYNTHETIC original candidate', ['candidate']),
+ participant(4, 'SYNTHETIC authorised officer'),
+ ],
+ milestones: [],
+ messages: [],
+ documents: [],
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+const clone = (value) =>
+ Array.isArray(value)
+ ? value.map(clone)
+ : value && Object.getPrototypeOf(value) === Object.prototype
+ ? Object.fromEntries(
+ Object.entries(value).map(([k, v]) => [k, clone(v)]),
+ )
+ : value;
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ usePage: () => ({
+ props: { auth: { user: { id: current.actorId ?? 1 } } },
+ }),
+ Link: 'a',
+ router: {
+ reload(options) {
+ reloads.push(options);
+ },
+ on(name, callback) {
+ if (name === 'before') before.add(callback);
+ return () => before.delete(callback);
+ },
+ post(url, data) {
+ sent.push({ method: 'post', url, data, options: {} });
+ },
+ },
+ useForm(initialData) {
+ const i = cursor++;
+ if (active.cells[i]) return active.cells[i];
+ const form = {
+ data: clone(initialData),
+ defaults: clone(initialData),
+ errors: {},
+ processing: false,
+ setData(key, value) {
+ this.data =
+ typeof key === 'function'
+ ? key(this.data)
+ : typeof key === 'object'
+ ? key
+ : { ...this.data, [key]: value };
+ changed = true;
+ },
+ setDefaults(data) {
+ this.defaults = clone(data);
+ },
+ clearErrors() {
+ this.errors = {};
+ changed = true;
+ },
+ transform(callback) {
+ this.transformer = callback;
+ },
+ };
+ for (const method of ['post', 'put'])
+ form[method] = (url, options) => {
+ form.processing = true;
+ changed = true;
+ sent.push({
+ method,
+ url,
+ options,
+ data: clone(
+ form.transformer
+ ? form.transformer(form.data)
+ : form.data,
+ ),
+ form,
+ });
+ };
+ active.cells[i] = form;
+ return form;
+ },
+ },
+ '@/pages/partnerships/shared': {
+ labels: {
+ negotiation: 'Em negociação',
+ agreement_recorded: 'Acordo registado',
+ agreed: 'Confirmado pelas partes',
+ execution: 'Em execução',
+ closed: 'Concluída',
+ cancelled: 'Cancelada',
+ pending: 'Pendente',
+ progress: 'Em curso',
+ completed: 'Concluído',
+ },
+ },
+ './shared': {
+ Frame: 'main',
+ Field: 'label',
+ Errors: 'errors',
+ labels: {
+ pending: 'Submetida — legado',
+ progress: 'Em curso',
+ completed: 'Concluído',
+ },
+ },
+ };
+ const operation = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['./operation-key'] = operation;
+ mocks['@/lib/operation-key'] = operation;
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ target: ts.ScriptTarget.ES2022,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['@/lib/partnership-agreement'] = load(
+ 'resources/js/lib/partnership-agreement.ts',
+ );
+ mocks['@/components/partnership-agreement-instrument'] = load(
+ 'resources/js/components/partnership-agreement-instrument.tsx',
+ );
+ mocks['@/lib/partnership-room-edit'] = load(
+ 'resources/js/lib/partnership-room-edit.ts',
+ );
+ mocks['@/lib/partnership-room-delivery'] = load(
+ 'resources/js/lib/partnership-room-delivery.ts',
+ );
+ mocks['@/components/partnership-room-comparison'] = load(
+ 'resources/js/components/partnership-room-comparison.tsx',
+ );
+ const Page = load('resources/js/pages/partnerships/room.tsx').default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ all: () => nodes(tree),
+ form(name) {
+ return nodes(tree).find(
+ (node) => node.props?.['data-room-form'] === name,
+ );
+ },
+ button(label, scope = tree) {
+ return nodes(scope).find(
+ (node) => node.type === 'button' && text(node) === label,
+ );
+ },
+ field(name, label) {
+ const root = this.form(name);
+ const field = nodes(root).find(
+ (node) => node.type === 'label' && node.props.label === label,
+ );
+ return nodes(field).find((node) =>
+ ['input', 'select', 'textarea'].includes(node.type),
+ );
+ },
+ change(name, label, value, rerender = true) {
+ const field = this.field(name, label);
+ if (!field) throw Error('Missing field ' + name + '/' + label);
+ field.props.onChange({
+ target: { value, checked: value, files: value ? [value] : [] },
+ });
+ if (rerender) render();
+ },
+ submit(name) {
+ const form = this.form(name);
+ form.props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ },
+ click(label, scope = tree) {
+ const button = this.button(label, scope);
+ if (!button) throw Error('Missing button ' + label);
+ button.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ success(next, request = sent.at(-1)) {
+ render(next);
+ request.options.onSuccess({ props: next });
+ request.form.processing = false;
+ render(next);
+ },
+ fail(request = sent.at(-1), status = null) {
+ if (status === null) request.options.onNetworkError();
+ else request.options.onHttpException({ status });
+ request.form.processing = false;
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ return prevented;
+ },
+ unload() {
+ let prevented = false;
+ for (const fn of unload)
+ fn({
+ preventDefault() {
+ prevented = true;
+ },
+ returnValue: null,
+ });
+ return prevented;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/profile-support-installation.mjs b/tests/frontend/helpers/profile-support-installation.mjs
new file mode 100644
index 00000000..32442250
--- /dev/null
+++ b/tests/frontend/helpers/profile-support-installation.mjs
@@ -0,0 +1,378 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const apply = 'Aplicar actualiza\u00e7\u00e3o do Suporte t\u00e9cnico';
+export const refresh = 'Actualizar pr\u00e9via';
+export const adopt = 'Confirmar leitura da pr\u00e9via actual';
+export const retry = 'Repetir envio original';
+export const reason = 'Actualizacao sintetica explicitamente fundamentada';
+export function props(patch = {}) {
+ return {
+ actorId: 1,
+ target: { database: 'support_profile_installation_test', port: 55441 },
+ hash: 'a'.repeat(64),
+ code_hash: 'b'.repeat(64),
+ installed: false,
+ consistent: true,
+ repairable: false,
+ ready: true,
+ action: 'install',
+ schema: { state: 'base', ledger: false },
+ dependencies: { profiles_installed: true },
+ changes: [],
+ backupDate: '2026-11-03T00:00:00Z',
+ rollback: 'Conservar historico',
+ commands: [],
+ mfa_confirmed: true,
+ ...patch,
+ };
+}
+export function result(request, patch = {}) {
+ return {
+ actor_id: 1,
+ command_key: request.data.idempotency_key,
+ target: props().target,
+ migration: '2026_11_03_080000_add_technical_support_profile',
+ code_hash: props().code_hash,
+ installed: true,
+ ...patch,
+ };
+}
+export function committed(request, patch = {}) {
+ return props({
+ installed: true,
+ action: 'none',
+ hash: 'c'.repeat(64),
+ schema: { state: 'support', ledger: true },
+ commands: [
+ { key: request.data.idempotency_key, code_hash: props().code_hash },
+ ],
+ ...patch,
+ });
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+export function harness(initial = props(), mode = 'support') {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ class ApiError extends Error {
+ constructor(status, errors = {}) {
+ super('SYNTHETIC HTTP ' + status);
+ this.status = status;
+ this.errors = errors;
+ }
+ }
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {
+ reload: (options) => reloads.push(options),
+ on(name, fn) {
+ if (name === 'before') before.add(fn);
+ return () => before.delete(fn);
+ },
+ },
+ },
+ '../management/shared': { Management: 'main', button: '', control: '' },
+ '@/pages/management/shared': {
+ Management: 'main',
+ button: '',
+ control: '',
+ },
+ };
+ const request = (url, options = {}) =>
+ new Promise((resolve, reject) => {
+ const entry = {
+ url,
+ data: options.body ? JSON.parse(options.body) : null,
+ resolve,
+ reject,
+ };
+ (options.method === 'POST' ? sent : reloads).push(entry);
+ });
+ mocks['./portal-api'] = {
+ PortalApiError: ApiError,
+ portalRequest: request,
+ };
+ mocks['@/lib/profile-json'] = {
+ profileJson: (url, data, method = 'POST') =>
+ request(url, { method, body: JSON.stringify(data) }),
+ };
+ mocks['./operation-key'] = mocks['@/lib/operation-key'] = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['./page-preparation-guard'] = mocks['@/lib/page-preparation-guard'] =
+ load('resources/js/lib/page-preparation-guard.ts');
+ mocks['@/lib/profile-support-installation'] = load(
+ 'resources/js/lib/profile-support-installation.ts',
+ );
+ const Page = load(
+ 'resources/js/pages/profiles/' +
+ (mode === 'support' ? 'support-installation' : 'installation') +
+ '.tsx',
+ ).default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ get reason() {
+ return nodes(tree).find((n) => n.type === 'textarea').props.value;
+ },
+ button(label) {
+ return nodes(tree).find(
+ (n) => n.type === 'button' && text(n) === label,
+ );
+ },
+ change(value) {
+ nodes(tree)
+ .find((n) => n.type === 'textarea')
+ .props.onChange({ target: { value } });
+ render();
+ },
+ confirm(value = true) {
+ nodes(tree)
+ .find((n) => n.type === 'input' && n.props.type === 'checkbox')
+ .props.onChange({ target: { checked: value } });
+ render();
+ },
+ number(index, value) {
+ nodes(tree)
+ .filter((n) => n.type === 'input' && n.props.type === 'number')
+ [index].props.onChange({ target: { value } });
+ render();
+ },
+ get guards() {
+ return before.size;
+ },
+ click(label) {
+ const node = this.button(label);
+ if (!node) throw Error('Missing button ' + label);
+ node.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ async reply(value, request = sent.at(-1)) {
+ request.resolve(value);
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ async fail(status = null, request = sent.at(-1)) {
+ request.reject(
+ status === null
+ ? new Error('SYNTHETIC network loss')
+ : new ApiError(
+ status,
+ status === 422
+ ? { note: ['SYNTHETIC rejected note'] }
+ : {},
+ ),
+ );
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const old = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = old;
+ }
+ return prevented;
+ },
+ };
+}
diff --git a/tests/frontend/helpers/resource-incident-form.mjs b/tests/frontend/helpers/resource-incident-form.mjs
new file mode 100644
index 00000000..698e4430
--- /dev/null
+++ b/tests/frontend/helpers/resource-incident-form.mjs
@@ -0,0 +1,334 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export function props(patch = {}) {
+ return {
+ opportunity: {
+ id: 1,
+ title: 'SYNTHETIC resource investment',
+ status: 'draft',
+ deleted_at: null,
+ },
+ etag: 'a'.repeat(64),
+ resources: { documents: [], images: [], locations: [] },
+ existingLocations: [],
+ assessment: [],
+ imageProcessingAvailable: true,
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0;
+ const windowMock = {
+ confirm() {
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ class Form {
+ constructor() {
+ this.values = new Map();
+ }
+ set(k, v) {
+ this.values.set(k, v);
+ }
+ get(k) {
+ return this.values.get(k);
+ }
+ }
+ function globals() {
+ const saved = {
+ document: globalThis.document,
+ fetch: globalThis.fetch,
+ FormData: globalThis.FormData,
+ setTimeout: globalThis.setTimeout,
+ };
+ globalThis.document = {
+ cookie: 'XSRF-TOKEN=SYNTHETIC',
+ getElementById: () => ({ focus() {} }),
+ };
+ globalThis.FormData = Form;
+ globalThis.setTimeout = (fn) => {
+ fn();
+ return 0;
+ };
+ globalThis.fetch = (url, options) =>
+ new Promise((resolve, reject) =>
+ sent.push({ url, form: options.body, resolve, reject }),
+ );
+ return () => Object.assign(globalThis, saved);
+ }
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ usePage: () => ({
+ props: {
+ basePath: '/minhas-oportunidades',
+ countries: [],
+ readOnly: false,
+ },
+ url: '/minhas-oportunidades/1/resources',
+ }),
+ router: { reload: (o) => reloads.push(o) },
+ },
+ '@/components/opportunity-library-reuse': { default: () => null },
+ '@/components/territory-geometry-preview': { default: () => null },
+ '@/components/investment-territory': { TerritoryLevel: () => null },
+ './shared': {
+ Management: 'main',
+ Field: ({ label, children }) => ({
+ type: 'label',
+ props: { children: [label, children] },
+ }),
+ button: '',
+ control: '',
+ },
+ '@/lib/operation-key': {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ },
+ };
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['@/lib/technical-incident-labels'] = load(
+ 'resources/js/lib/technical-incident-labels.ts',
+ );
+ mocks['@/lib/value-text'] = load('resources/js/lib/value-text.ts');
+ mocks['@/components/opportunity-technical-incidents'] = load(
+ 'resources/js/components/opportunity-technical-incidents.tsx',
+ );
+ const Page = load(
+ 'resources/js/pages/management/opportunity-resources.tsx',
+ ).default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ const field = (label) =>
+ nodes(tree).find(
+ (n) =>
+ ['input', 'textarea', 'select'].includes(n.type) &&
+ n.props['aria-label'] === label,
+ );
+ return {
+ sent,
+ reloads,
+ render,
+ get tree() {
+ return tree;
+ },
+ get props() {
+ return current;
+ },
+ value(label) {
+ return field(label)?.props.value;
+ },
+ change(label, value) {
+ field(label).props.onChange({ target: { value } });
+ render();
+ },
+ choose(label) {
+ nodes(tree)
+ .find((n) => n.type === 'button' && text(n) === label)
+ .props.onClick();
+ render();
+ },
+ attach(value) {
+ nodes(tree)
+ .find((n) => n.type === 'input' && n.props.type === 'file')
+ .props.onChange({ target: { files: [value] } });
+ render();
+ },
+ submit() {
+ const restore = globals();
+ try {
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ render();
+ return sent.at(-1);
+ } finally {
+ restore();
+ }
+ },
+ async reply(status, data, request = sent.at(-1)) {
+ const restore = globals();
+ try {
+ request.resolve({
+ ok: status >= 200 && status < 300,
+ status,
+ json: async () => data,
+ });
+ for (let i = 0; i < 8; i++) await Promise.resolve();
+ render();
+ } finally {
+ restore();
+ }
+ },
+ };
+}
diff --git a/tests/frontend/helpers/technical-incident-handling.mjs b/tests/frontend/helpers/technical-incident-handling.mjs
new file mode 100644
index 00000000..eb01f238
--- /dev/null
+++ b/tests/frontend/helpers/technical-incident-handling.mjs
@@ -0,0 +1,348 @@
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+export const reference = '10000000-0000-4000-8000-000000000001';
+export function props(patch = {}) {
+ return {
+ actorId: 1,
+ commands: [],
+ backUrl: '/suporte-tecnico/incidentes',
+ history: {
+ data: [],
+ total: 0,
+ current_page: 1,
+ last_page: 1,
+ prev_page_url: null,
+ next_page_url: null,
+ },
+ incident: {
+ reference,
+ operation: 'submit',
+ observed_version: 4,
+ occurred_at: '2026-11-03',
+ error_code: 'workflow_unavailable',
+ handling: {
+ version: 0,
+ status: 'open',
+ assignee_user_id: null,
+ assignee_name: null,
+ updated_at: null,
+ resolved_at: null,
+ },
+ },
+ ...patch,
+ };
+}
+export function nodes(tree) {
+ return Array.isArray(tree)
+ ? tree.flatMap(nodes)
+ : tree && typeof tree === 'object'
+ ? [tree, ...nodes(tree.props?.children)]
+ : [];
+}
+export function text(tree) {
+ return Array.isArray(tree)
+ ? tree.map(text).join('')
+ : tree?.props
+ ? text(tree.props.children)
+ : typeof tree === 'string' || typeof tree === 'number'
+ ? String(tree)
+ : '';
+}
+export function harness(initial = props()) {
+ const frames = new Map(),
+ sent = [],
+ reloads = [],
+ before = new Set(),
+ unload = new Set();
+ let active,
+ cursor = 0,
+ changed = false,
+ effects = [],
+ current = initial,
+ tree,
+ sequence = 0,
+ confirmCalls = 0;
+ const windowMock = {
+ confirm() {
+ confirmCalls++;
+ return false;
+ },
+ addEventListener(name, callback) {
+ if (name === 'beforeunload') unload.add(callback);
+ },
+ removeEventListener(name, callback) {
+ if (name === 'beforeunload') unload.delete(callback);
+ },
+ };
+ const state = (initialValue) => {
+ const frame = active,
+ i = cursor++;
+ if (!(i in frame.cells))
+ frame.cells[i] =
+ typeof initialValue === 'function'
+ ? initialValue()
+ : initialValue;
+ return [
+ frame.cells[i],
+ (value) => {
+ const next =
+ typeof value === 'function' ? value(frame.cells[i]) : value;
+ if (!Object.is(next, frame.cells[i])) {
+ frame.cells[i] = next;
+ changed = true;
+ }
+ },
+ ];
+ };
+ const hooks = {
+ useState: state,
+ useRef(value) {
+ const i = cursor++;
+ active.cells[i] ??= { current: value };
+ return active.cells[i];
+ },
+ useEffect(callback, deps) {
+ const frame = active,
+ i = cursor++,
+ prior = frame.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j])) {
+ frame.cells[i] = { deps };
+ effects.push(() => {
+ prior?.cleanup?.();
+ frame.cells[i].cleanup = callback();
+ });
+ }
+ },
+ useCallback(callback, deps) {
+ const i = cursor++,
+ prior = active.cells[i];
+ if (!prior || !deps.every((value, j) => value === prior.deps[j]))
+ active.cells[i] = { deps, callback };
+ return active.cells[i].callback;
+ },
+ };
+ class ApiError extends Error {
+ constructor(status, errors = {}) {
+ super('SYNTHETIC HTTP ' + status);
+ this.status = status;
+ this.errors = errors;
+ }
+ }
+ const mocks = {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ router: {
+ reload: (options) => reloads.push(options),
+ on(name, fn) {
+ if (name === 'before') before.add(fn);
+ return () => before.delete(fn);
+ },
+ },
+ },
+ '../management/shared': { Management: 'main', Pagination: () => null },
+ '@/pages/management/shared': { button: '', control: '' },
+ };
+ mocks['./portal-api'] = {
+ PortalApiError: ApiError,
+ portalRequest: (url, options) =>
+ new Promise((resolve, reject) =>
+ sent.push({
+ url,
+ data: JSON.parse(options.body),
+ resolve,
+ reject,
+ }),
+ ),
+ };
+ mocks['./operation-key'] = {
+ createOperationKey: () =>
+ `00000000-0000-4000-8000-${String(++sequence).padStart(12, '0')}`,
+ };
+ mocks['@/lib/portal-api'] = mocks['./portal-api'];
+ function load(path) {
+ const code = ts.transpileModule(
+ fs.readFileSync(
+ new URL('../../../' + path, import.meta.url),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => mocks[name] ?? require(name),
+ module,
+ module.exports,
+ );
+ return module.exports;
+ }
+ mocks['@/lib/technical-incident-labels'] = load(
+ 'resources/js/lib/technical-incident-labels.ts',
+ );
+ mocks['@/lib/technical-incident-handling'] = load(
+ 'resources/js/lib/technical-incident-handling.ts',
+ );
+ mocks['@/components/technical-incident-handling'] = load(
+ 'resources/js/components/technical-incident-handling.tsx',
+ );
+ mocks['@/components/technical-incident-notice'] = load(
+ 'resources/js/components/technical-incident-notice.tsx',
+ );
+ const Page = load(
+ 'resources/js/pages/profiles/technical-incident.tsx',
+ ).default;
+ function expand(value, path, seen) {
+ if (Array.isArray(value))
+ return value.map((child, i) =>
+ expand(child, path + '/' + (child?.key ?? i), seen),
+ );
+ if (!value || typeof value !== 'object' || !value.props) return value;
+ if (typeof value.type === 'function') {
+ const id = path + '/' + value.type.name + ':' + (value.key ?? '');
+ seen.add(id);
+ const frame = frames.get(id) ?? { cells: [] };
+ frames.set(id, frame);
+ const previous = active,
+ priorCursor = cursor;
+ active = frame;
+ cursor = 0;
+ const rendered = value.type(value.props);
+ active = previous;
+ cursor = priorCursor;
+ return {
+ type: 'component',
+ props: {
+ name: value.type.name,
+ children: expand(rendered, id, seen),
+ },
+ };
+ }
+ return {
+ ...value,
+ props: {
+ ...value.props,
+ children: expand(
+ value.props.children,
+ path + '/children',
+ seen,
+ ),
+ },
+ };
+ }
+ function render(next = current) {
+ current = next;
+ const previousWindow = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ let loops = 0;
+ do {
+ changed = false;
+ const seen = new Set();
+ tree = expand(
+ { type: Page, key: 'page', props: current },
+ 'root',
+ seen,
+ );
+ for (const [id, frame] of frames)
+ if (!seen.has(id)) {
+ frame.cells.forEach((cell) => cell?.cleanup?.());
+ frames.delete(id);
+ }
+ const queue = effects;
+ effects = [];
+ queue.forEach((effect) => effect());
+ if (++loops > 12) throw Error('Component state did not settle');
+ } while (changed);
+ return tree;
+ } finally {
+ globalThis.window = previousWindow;
+ }
+ }
+ render();
+ return {
+ sent,
+ reloads,
+ render,
+ get props() {
+ return current;
+ },
+ get tree() {
+ return tree;
+ },
+ get confirmCalls() {
+ return confirmCalls;
+ },
+ get note() {
+ return nodes(tree).find((n) => n.type === 'textarea').props.value;
+ },
+ button(label) {
+ return nodes(tree).find(
+ (n) => n.type === 'button' && text(n) === label,
+ );
+ },
+ change(value) {
+ nodes(tree)
+ .find((n) => n.type === 'textarea')
+ .props.onChange({ target: { value } });
+ render();
+ },
+ click(label) {
+ const node = this.button(label);
+ if (!node) throw Error('Missing button ' + label);
+ node.props.onClick();
+ render();
+ return sent.at(-1);
+ },
+ async reply(value, request = sent.at(-1)) {
+ request.resolve(value);
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ async fail(status = null, request = sent.at(-1)) {
+ request.reject(
+ status === null
+ ? new Error('SYNTHETIC network loss')
+ : new ApiError(
+ status,
+ status === 422
+ ? { note: ['SYNTHETIC rejected note'] }
+ : {},
+ ),
+ );
+ for (let i = 0; i < 6; i++) await Promise.resolve();
+ render();
+ },
+ refreshed(next, request = reloads.at(-1)) {
+ render(next);
+ request.onSuccess?.({ props: next });
+ request.onFinish?.();
+ render(next);
+ },
+ leave(preserveState = false) {
+ let prevented = false;
+ const old = globalThis.window;
+ globalThis.window = windowMock;
+ try {
+ for (const fn of before)
+ fn({
+ detail: { visit: { method: 'get', preserveState } },
+ preventDefault() {
+ prevented = true;
+ },
+ });
+ } finally {
+ globalThis.window = old;
+ }
+ return prevented;
+ },
+ };
+}
diff --git a/tests/frontend/investment-guides.test.mjs b/tests/frontend/investment-guides.test.mjs
new file mode 100644
index 00000000..742278f1
--- /dev/null
+++ b/tests/frontend/investment-guides.test.mjs
@@ -0,0 +1,431 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { compileFunction } from 'node:vm';
+import { createRequire } from 'node:module';
+import { renderToStaticMarkup } from 'react-dom/server';
+import ts from 'typescript';
+const require = createRequire(import.meta.url);
+function load(file, mocks = {}) {
+ const code = ts.transpileModule(
+ fs.readFileSync(new URL(file, import.meta.url), 'utf8'),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+ ).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (key) => mocks[key] ?? require(key),
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+const lib = load('../../resources/js/lib/investment-guides.ts');
+const guide = {
+ slug: 'capitalizacao',
+ version: 'SYNTHETIC-v1',
+ sha256: 'a'.repeat(64),
+ title: 'SYNTHETIC capital guide',
+ reviewed_on: '2026-11-02',
+ scope: 'SYNTHETIC information, not approval',
+ instruments: {
+ debt: {
+ title: 'SYNTHETIC debt',
+ description: 'SYNTHETIC repayments',
+ risks: ['SYNTHETIC default'],
+ prepare: ['SYNTHETIC cashflows'],
+ sources: ['primary'],
+ },
+ equity: {
+ title: 'SYNTHETIC equity',
+ description: 'SYNTHETIC ownership',
+ risks: ['SYNTHETIC dilution'],
+ prepare: ['SYNTHETIC ownership'],
+ sources: ['primary'],
+ },
+ },
+ sources: {
+ primary: {
+ title: 'Primary ',
+ url: 'https://primary.test/page',
+ edition: 'SYNTHETIC edition',
+ locator: 'SYNTHETIC paragraph',
+ consulted_on: '2026-11-02',
+ sha256: 'b'.repeat(64),
+ },
+ },
+ eligibility: [
+ { text: 'SYNTHETIC provider criteria', sources: ['primary'] },
+ ],
+ preparation: [
+ {
+ title: 'SYNTHETIC documents',
+ text: 'SYNTHETIC proposed list',
+ sources: ['primary'],
+ },
+ ],
+ next: ['SYNTHETIC next action'],
+ limits: ['SYNTHETIC no automatic submission'],
+};
+const props = {
+ guide,
+ instruments: [],
+ note: '',
+ case: null,
+ saved: null,
+ canWrite: false,
+ historical: false,
+ olderEdition: false,
+ currentAvailable: true,
+ workingCopy: false,
+ contextChanged: false,
+ unavailableInstruments: [],
+ history: [],
+ historyNext: null,
+};
+const dossier = {
+ id: 'SYNTHETIC-case',
+ title: 'SYNTHETIC destination',
+ version: 1,
+};
+function nodes(tree) {
+ if (!tree || typeof tree !== 'object') return [];
+ if (Array.isArray(tree)) return tree.flatMap(nodes);
+ return [tree, ...nodes(tree.props?.children)];
+}
+const byName = (tree, name) => nodes(tree).find((n) => n.props?.name === name);
+const button = (tree, label) =>
+ nodes(tree).find((n) => n.type === 'button' && n.props.children === label);
+const tick = () => new Promise((resolve) => setImmediate(resolve));
+function harness() {
+ let cursor = 0,
+ reject = false,
+ withdrawn = false;
+ const values = [],
+ refs = [],
+ requests = [],
+ visits = [];
+ class ValidationError extends Error {}
+ const hooks = {
+ useState(initial) {
+ const i = cursor++;
+ if (!(i in values))
+ values[i] = structuredClone(
+ typeof initial === 'function' ? initial() : initial,
+ );
+ return [
+ values[i],
+ (v) => {
+ values[i] = typeof v === 'function' ? v(values[i]) : v;
+ },
+ ];
+ },
+ useRef(initial) {
+ const i = cursor++;
+ if (!(i in values)) {
+ values[i] = { current: initial };
+ refs.push(values[i]);
+ }
+ return values[i];
+ },
+ };
+ const component = load('../../resources/js/pages/investment/guide.tsx', {
+ react: hooks,
+ '@inertiajs/react': {
+ Link: 'a',
+ router: { visit: (...args) => visits.push(args) },
+ },
+ './shared': { Frame: 'main', input: '', card: '', button: '' },
+ '@/lib/investment-guides': lib,
+ '@/lib/operation-key': {
+ createOperationKey: () => 'SYNTHETIC-operation',
+ },
+ '@/lib/profile-json': {
+ ProfileValidationError: ValidationError,
+ profileJson: async (...args) => {
+ requests.push(args);
+ if (args[2] === 'GET')
+ return {
+ ...props,
+ case: { ...dossier, version: 4 },
+ canWrite: true,
+ olderEdition: withdrawn,
+ currentAvailable: !withdrawn,
+ note: 'SYNTHETIC saved by coeditor',
+ };
+ if (reject) throw new Error('SYNTHETIC conflict');
+ return { saved: true };
+ },
+ },
+ });
+ return {
+ render(extra = {}) {
+ cursor = 0;
+ const outer = component.default({ ...props, ...extra });
+ return outer.type(outer.props);
+ },
+ refs,
+ requests,
+ visits,
+ fail() {
+ reject = true;
+ },
+ withdraw() {
+ withdrawn = true;
+ },
+ };
+}
+async function withData(data, fn) {
+ const original = globalThis.FormData;
+ globalThis.FormData = class {
+ get(key) {
+ return data[key] ?? null;
+ }
+ getAll(key) {
+ return data[key] ?? [];
+ }
+ };
+ try {
+ return await fn();
+ } finally {
+ globalThis.FormData = original;
+ }
+}
+
+await test('public guide distinguishes instruments, risks, provider criteria, documents and exact source edition without identity fields', () => {
+ const tree = harness().render(),
+ html = renderToStaticMarkup(tree);
+ for (const text of [
+ 'SYNTHETIC debt',
+ 'SYNTHETIC equity',
+ 'SYNTHETIC default',
+ 'SYNTHETIC dilution',
+ 'SYNTHETIC provider criteria',
+ 'SYNTHETIC documents',
+ 'SYNTHETIC next action',
+ 'SYNTHETIC edition',
+ 'SYNTHETIC paragraph',
+ ])
+ assert.match(html, new RegExp(text));
+ assert.match(html, /Primary <SYNTHETIC>/);
+ assert.match(html, /https:\/\/primary.test\/page/);
+ assert.equal(byName(tree, 'note'), undefined);
+ assert.doesNotMatch(html, /name="(name|email|nuit|amount|return)"/);
+});
+
+await test('selection filters only the visible instruments and can return to the whole guide', () => {
+ const h = harness();
+ const checkbox = nodes(h.render()).find((n) => n.props?.value === 'debt');
+ checkbox.props.onChange({ target: { checked: true } });
+ let html = renderToStaticMarkup(h.render());
+ assert.match(html, /SYNTHETIC default/);
+ assert.doesNotMatch(html, /SYNTHETIC dilution/);
+ nodes(h.render())
+ .find((n) => n.props?.value === 'debt')
+ .props.onChange({ target: { checked: false } });
+ html = renderToStaticMarkup(h.render());
+ assert.match(html, /SYNTHETIC dilution/);
+});
+
+await test('authentication URLs carry only coded choices and edition pins, including an explicitly empty selection', async () => {
+ const h = harness();
+ h.render();
+ h.refs[0].current = {};
+ await withData(
+ { 'instruments[]': ['equity'], note: 'PRIVATE MUST NOT TRAVEL' },
+ async () => {
+ nodes(h.render())
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ },
+ );
+ const url = new URL(h.visits[0][0], 'https://portal.test');
+ assert.equal(url.pathname, '/investimentos');
+ assert.equal(
+ url.searchParams.get('investment_guide[sha256]'),
+ guide.sha256,
+ );
+ assert.deepEqual(
+ url.searchParams.getAll('investment_guide[instruments][]'),
+ ['equity'],
+ );
+ assert.doesNotMatch(url.href, /PRIVATE|note/);
+ const empty = new URL(
+ lib.guideUrl('/investimentos/id/guias/capitalizacao', {
+ slug: guide.slug,
+ sha256: guide.sha256,
+ instruments: [],
+ }),
+ 'https://portal.test',
+ );
+ assert.equal(empty.searchParams.get('current'), '1');
+ assert.equal(empty.searchParams.get('selection'), '1');
+ assert.equal(empty.searchParams.get('sha256'), guide.sha256);
+});
+
+await test('private saves use actual browser values and return to the same dossier without putting notes in URLs', async () => {
+ const h = harness(),
+ extra = { case: dossier, canWrite: true };
+ h.render(extra);
+ h.refs[0].current = {};
+ await withData(
+ {
+ 'instruments[]': ['debt'],
+ note: 'SYNTHETIC autofilled private note',
+ },
+ async () => {
+ nodes(h.render(extra))
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ },
+ );
+ assert.equal(h.requests[0][1].note, 'SYNTHETIC autofilled private note');
+ assert.deepEqual(h.requests[0][1].instruments, ['debt']);
+ assert.equal(h.requests[0][1].sha256, guide.sha256);
+ assert.deepEqual(h.visits, [
+ [
+ '/investimentos/SYNTHETIC-case/guias/capitalizacao',
+ { preserveState: false },
+ ],
+ ]);
+});
+
+await test('conflicts preserve private notes and require explicit comparison before adopting the current dossier version', async () => {
+ const h = harness(),
+ extra = { case: dossier, canWrite: true };
+ h.render(extra);
+ h.refs[0].current = {};
+ h.fail();
+ await withData(
+ { 'instruments[]': ['debt'], note: 'SYNTHETIC unsaved note' },
+ async () => {
+ nodes(h.render(extra))
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ },
+ );
+ assert.equal(
+ byName(h.render(extra), 'note').props.value,
+ 'SYNTHETIC unsaved note',
+ );
+ assert.equal(h.visits.length, 0);
+ await button(
+ h.render(extra),
+ 'Conferir a referência actual sem perder a nota',
+ ).props.onClick();
+ assert.equal(h.requests[1][2], 'GET');
+ assert.match(
+ renderToStaticMarkup(h.render(extra)),
+ /SYNTHETIC saved by coeditor/,
+ );
+ button(
+ h.render(extra),
+ 'Conferi: manter a minha preparação numa nova revisão',
+ ).props.onClick();
+ await withData({ 'instruments[]': ['debt'] }, async () => {
+ nodes(h.render(extra))
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ });
+ assert.equal(h.requests[2][1].version, 4);
+ assert.equal(h.requests[2][1].note, 'SYNTHETIC unsaved note');
+ h.withdraw();
+ await button(
+ h.render(extra),
+ 'Conferir a referência actual sem perder a nota',
+ ).props.onClick();
+ assert.equal(
+ button(
+ h.render(extra),
+ 'Conferi: manter a minha preparação numa nova revisão',
+ ),
+ undefined,
+ );
+ assert.equal(
+ byName(h.render(extra), 'note').props.value,
+ 'SYNTHETIC unsaved note',
+ );
+ assert.match(
+ renderToStaticMarkup(h.render(extra)),
+ /guia utilizado foi alterado/,
+ );
+});
+
+await test('historical or withdrawn guides and consultation members cannot write or silently upgrade a saved edition', async () => {
+ for (const flags of [
+ { historical: true },
+ { olderEdition: true, currentAvailable: false },
+ { canWrite: false },
+ ]) {
+ const h = harness(),
+ tree = h.render({ case: dossier, canWrite: true, ...flags });
+ assert.equal(
+ nodes(tree).find((n) => n.type === 'fieldset').props.disabled,
+ true,
+ );
+ nodes(tree)
+ .find((n) => n.type === 'form')
+ .props.onSubmit({ preventDefault() {} });
+ await tick();
+ assert.equal(h.requests.length, 0);
+ if (flags.currentAvailable === false) {
+ const html = renderToStaticMarkup(tree);
+ assert.match(html, /retirado da consulta actual/);
+ assert.doesNotMatch(html, /\?current=1/);
+ }
+ }
+});
+
+await test('dossier chooser preserves the selected source edition on existing and newly created investment paths', () => {
+ let created;
+ const selection = {
+ slug: guide.slug,
+ sha256: guide.sha256,
+ instruments: ['debt'],
+ };
+ const module = load('../../resources/js/pages/investor-path/index.tsx', {
+ react: { useState: (fn) => [typeof fn === 'function' ? fn() : fn] },
+ '@inertiajs/react': {
+ Head: 'title',
+ Link: 'a',
+ router: {},
+ useForm: (data) => {
+ created = data;
+ return { data, errors: {}, processing: false };
+ },
+ },
+ '@/lib/investment-guides': lib,
+ '@/lib/operation-key': {
+ createOperationKey: () => 'SYNTHETIC-operation',
+ },
+ '@/lib/company-comparison': {},
+ });
+ const tree = module.default({
+ contexts: [{ ...dossier, updated_at: '2026-11-02' }],
+ guideSelection: selection,
+ });
+ assert.deepEqual(created.investment_guide, selection);
+ const link = nodes(tree).find(
+ (n) =>
+ typeof n.props?.href === 'string' &&
+ n.props.href.includes('/guias/'),
+ );
+ const url = new URL(link.props.href, 'https://portal.test');
+ assert.equal(
+ url.pathname,
+ '/investimentos/SYNTHETIC-case/guias/capitalizacao',
+ );
+ assert.equal(url.searchParams.get('sha256'), guide.sha256);
+ assert.match(
+ renderToStaticMarkup(tree),
+ /só serão guardados quando confirmar/,
+ );
+});
diff --git a/tests/frontend/investment-profile-editor.test.mjs b/tests/frontend/investment-profile-editor.test.mjs
new file mode 100644
index 00000000..a4f73c15
--- /dev/null
+++ b/tests/frontend/investment-profile-editor.test.mjs
@@ -0,0 +1,234 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import {
+ harness,
+ props,
+ text,
+ nodes,
+ companyId,
+} from './helpers/investment-profile-editor.mjs';
+const account = 'Perfil de investimento',
+ company = 'Declaração de empresa',
+ fresh = 'Nova declaração de empresa',
+ residence = 'País de residência do investidor';
+
+test('the actual profile preserves the ISO selection and repeats the exact command after a lost response', async () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ const first = h.submit(account);
+ assert.equal(first.data.payload.residence_country_code, 'ZA');
+ await h.fail();
+ assert.equal(h.value(residence, account), 'ZA');
+ assert.equal(h.field(residence, account).props.disabled, true);
+ assert.match(text(h.tree), /preparação foi conservada/);
+ assert.equal(h.sent.length, 1);
+ h.submit(account);
+ assert.deepEqual(h.sent[1].data, first.data);
+ await h.reply({ version: 2 });
+ assert.equal(h.reloads.length, 1);
+ assert.match(text(h.tree), /Gravação confirmada/);
+ assert.equal(h.leave(), false);
+});
+test('a new company retry uses the original creation key and clears only its confirmed preparation', async () => {
+ const h = harness();
+ h.change('Nome da empresa', 'SYNTHETIC new', fresh);
+ h.change('País de constituição da entidade', 'MZ', fresh);
+ h.change('Função ou relação com a empresa', 'SYNTHETIC role', fresh);
+ h.change('Telefone', 'SYNTHETIC unsaved phone', account);
+ const first = h.submit(fresh);
+ await h.fail(503);
+ const second = h.submit(fresh);
+ assert.deepEqual(second.data, first.data);
+ await h.reply({ id: '10000000-0000-4000-8000-000000000002', version: 1 });
+ assert.equal(h.value('Nome da empresa', fresh), '');
+ assert.equal(h.value('Telefone', account), 'SYNTHETIC unsaved phone');
+ assert.equal(h.leave(), true);
+});
+test('a refreshed newer version preserves local edits until explicit comparison and adoption', async () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ h.render(
+ props({
+ account: {
+ version: 2,
+ payload: {
+ residence_country_code: 'MZ',
+ country: 'SYNTHETIC historical',
+ },
+ },
+ }),
+ );
+ assert.equal(h.value(residence, account), 'ZA');
+ assert.equal(
+ h.button('Guardar perfil de investimento', account).props.disabled,
+ true,
+ );
+ const read = h.click('Consultar registo guardado', account);
+ assert.equal(read.method, 'GET');
+ await h.reply(
+ props({
+ account: { version: 2, payload: { residence_country_code: 'MZ' } },
+ }),
+ );
+ assert.match(text(h.form(account)), /Compar|Preparação nesta página/);
+ h.click('Usar versão actual e manter a preparação', account);
+ assert.equal(h.value(residence, account), 'ZA');
+ const command = h.submit(account);
+ assert.equal(command.data.version, 2);
+ assert.equal(command.data.payload.residence_country_code, 'ZA');
+});
+test('conflict recovery reads current data without applying a write automatically', async () => {
+ const h = harness();
+ h.change('Nome da empresa', 'SYNTHETIC local name', company);
+ h.submit(company);
+ await h.fail(409);
+ assert.equal(h.value('Nome da empresa', company), 'SYNTHETIC local name');
+ const read = h.click('Consultar registo guardado', company);
+ await h.reply(
+ props({
+ companies: [
+ {
+ id: companyId,
+ version: 3,
+ payload: {
+ name: 'SYNTHETIC server name',
+ incorporation_country_code: 'MZ',
+ role: 'SYNTHETIC role',
+ },
+ },
+ ],
+ }),
+ );
+ assert.equal(h.sent.length, 2);
+ assert.equal(read.method, 'GET');
+ h.click('Usar versão actual e manter a preparação', company);
+ const command = h.submit(company);
+ assert.equal(command.data.version, 3);
+ assert.equal(command.data.payload.name, 'SYNTHETIC local name');
+});
+test('validation shows each field message once and preserves its value', async () => {
+ const h = harness();
+ h.change(residence, 'ZZ', account);
+ const sent = h.submit(account);
+ await h.fail(422, sent, {
+ 'payload.residence_country_code': ['SYNTHETIC invalid country'],
+ });
+ assert.equal(
+ text(h.form(account)).split('SYNTHETIC invalid country').length - 1,
+ 1,
+ );
+ assert.equal(h.value(residence, account), 'ZZ');
+ assert.equal(h.field(residence, account).props['aria-invalid'], true);
+});
+test('one page leave guard covers multiple dirty profile declarations', () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ h.change('Nome da empresa', 'SYNTHETIC edit', company);
+ assert.equal(h.leave(), true);
+ assert.equal(h.confirmCalls, 1);
+ assert.equal(h.leave(true), false);
+});
+test('a response from the prior actor cannot confirm or reload another account', async () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ const old = h.submit(account);
+ h.render(
+ props({
+ actorId: 2,
+ account: { version: 0, payload: {} },
+ companies: [],
+ }),
+ );
+ await h.reply({ version: 2 }, old);
+ assert.equal(h.reloads.length, 0);
+ assert.equal(h.value(residence, account), '');
+ assert.doesNotMatch(text(h.tree), /Gravação confirmada/);
+});
+test('an invalid creation acknowledgement keeps the new company and command unresolved', async () => {
+ const h = harness();
+ h.change('Nome da empresa', 'SYNTHETIC retained', fresh);
+ h.submit(fresh);
+ await h.reply({ version: 1, id: 'invalid-id' });
+ assert.equal(h.value('Nome da empresa', fresh), 'SYNTHETIC retained');
+ assert.equal(h.reloads.length, 0);
+ assert.match(text(h.tree), /Não foi possível confirmar/);
+});
+test('long answers use multiline controls and text limits match the server', () => {
+ const h = harness();
+ assert.equal(h.field('Experiência relevante', account).type, 'textarea');
+ assert.equal(h.field('Telefone', account).props.maxLength, 30);
+ assert.equal(
+ h.field('Referência de registo / NUIT', company).props.maxLength,
+ 100,
+ );
+ assert.equal(
+ nodes(h.form(account)).filter(
+ (node) => node.type === 'input' && node.props.required,
+ ).length,
+ 0,
+ );
+});
+test('consulting after an uncertain creation never unlocks editing or replaces its original command', async () => {
+ const h = harness();
+ h.change('Nome da empresa', 'SYNTHETIC original attempt', fresh);
+ const first = h.submit(fresh);
+ await h.fail();
+ h.click('Consultar registo guardado', fresh);
+ await h.reply(props());
+ assert.equal(
+ h.value('Nome da empresa', fresh),
+ 'SYNTHETIC original attempt',
+ );
+ assert.equal(h.field('Nome da empresa', fresh).props.disabled, true);
+ assert.equal(
+ h.button('Usar versão actual e manter a preparação', fresh),
+ undefined,
+ );
+ const retry = h.submit(fresh);
+ assert.deepEqual(retry.data, first.data);
+});
+test('company country validation is attached once to the selectable country field', async () => {
+ const h = harness();
+ const request = h.submit(fresh);
+ await h.fail(422, request, {
+ 'payload.country': ['SYNTHETIC company country required'],
+ });
+ assert.equal(
+ h.field('País de constituição da entidade', fresh).props[
+ 'aria-invalid'
+ ],
+ true,
+ );
+ assert.equal(
+ text(h.form(fresh)).split('SYNTHETIC company country required').length -
+ 1,
+ 1,
+ );
+});
+test('preparing a manifestation cannot discard unsaved profile data without the existing leave confirmation', () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ h.click('Preparar manifestação desta empresa');
+ assert.equal(h.confirmCalls, 1);
+ assert.equal(h.value(residence, account), 'ZA');
+ assert.equal(h.sent.length, 0);
+});
+test('a newer value read from the server requires explicit adoption before another write', async () => {
+ const h = harness();
+ h.change(residence, 'ZA', account);
+ h.click('Consultar registo guardado', account);
+ await h.reply(
+ props({
+ account: { version: 4, payload: { residence_country_code: 'MZ' } },
+ }),
+ );
+ const count = h.sent.length;
+ h.submit(account);
+ assert.equal(h.sent.length, count);
+ assert.equal(
+ h.button('Guardar perfil de investimento', account).props.disabled,
+ true,
+ );
+ h.click('Usar versão actual e manter a preparação', account);
+ assert.equal(h.submit(account).data.version, 4);
+});
diff --git a/tests/frontend/opportunity-technical-incidents.test.mjs b/tests/frontend/opportunity-technical-incidents.test.mjs
new file mode 100644
index 00000000..d1889d02
--- /dev/null
+++ b/tests/frontend/opportunity-technical-incidents.test.mjs
@@ -0,0 +1,354 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+const require = createRequire(import.meta.url),
+ module = { exports: {} };
+const output = ts.transpileModule(
+ fs.readFileSync(
+ new URL(
+ '../../resources/js/components/opportunity-technical-incidents.tsx',
+ import.meta.url,
+ ),
+ 'utf8',
+ ),
+ {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.ES2022,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ },
+).outputText;
+compileFunction(output, ['require', 'module', 'exports'])(
+ (name) =>
+ name === '@/lib/technical-incident-labels'
+ ? load('resources/js/lib/technical-incident-labels.ts')
+ : require(name),
+ module,
+ module.exports,
+);
+const render = (incidents) =>
+ renderToStaticMarkup(
+ React.createElement(module.exports.default, { incidents }),
+ );
+const base = {
+ reference: 'SYNTHETIC-reference',
+ operation: 'submit',
+ version: 4,
+ occurred_at: '2026-11-03',
+ error_code: 'database_failure',
+};
+test('no incident produces no empty form or duplicate question', () =>
+ assert.equal(render([]), ''));
+test('the reader identifies the attempt and support scope without a business retry or decision', () => {
+ const html = render([base]);
+ assert.match(html, /Submissão para validação/);
+ assert.match(html, /versão observada 4/);
+ assert.match(html, /SYNTHETIC-reference/);
+ assert.match(html, /Consulte o estado actual antes de repetir/);
+ assert.match(html, /Suporte técnico consulta os incidentes/);
+ assert.doesNotMatch(html, /
+ mocks[name] ??
+ (name === '@/components/technical-incident-notice'
+ ? { default: () => null }
+ : undefined) ??
+ (name.startsWith('@/')
+ ? load('resources/js/' + name.slice(2) + '.ts')
+ : require(name)),
+ result,
+ result.exports,
+ );
+ return result.exports;
+}
+test('the actual profile navigation exposes the support queue only through the server capability', () => {
+ const { profileLinks } = load(
+ 'resources/js/components/profile-navigation.tsx',
+ { '@inertiajs/react': { Link: 'a', usePage: () => ({ props: {} }) } },
+ );
+ const access = {
+ mine: null,
+ create: null,
+ request: '/perfil/promotor',
+ review: null,
+ administration: null,
+ };
+ assert.equal(
+ profileLinks(access).some(
+ (link) => link.href === '/suporte-tecnico/incidentes',
+ ),
+ false,
+ );
+ assert.equal(
+ profileLinks({
+ ...access,
+ technicalSupport: '/suporte-tecnico/incidentes',
+ }).find((link) => link.href === '/suporte-tecnico/incidentes').title,
+ 'Suporte técnico',
+ );
+});
+test('the actual queue presents minimal metadata and an honest empty state without private process links', () => {
+ const Queue = load('resources/js/pages/profiles/technical-support.tsx', {
+ '@inertiajs/react': {
+ Link: ({ href, children, ...rest }) =>
+ React.createElement('a', { href, ...rest }, children),
+ },
+ '../management/shared': {
+ Management: ({ children }) =>
+ React.createElement('main', null, children),
+ Pagination: () => null,
+ },
+ }).default;
+ const page = (data) =>
+ renderToStaticMarkup(
+ React.createElement(Queue, {
+ incidents: {
+ data,
+ total: data.length,
+ current_page: 1,
+ last_page: 1,
+ prev_page_url: null,
+ next_page_url: null,
+ },
+ }),
+ );
+ assert.match(page([]), /Não existem incidentes disponíveis neste âmbito/);
+ const html = page([base]);
+ assert.match(html, /SYNTHETIC-reference/);
+ assert.match(html, /não concede acesso aos processos ou documentos/);
+ assert.doesNotMatch(html, /minhas-oportunidades| {
+ const Queue = load('resources/js/pages/profiles/technical-support.tsx', {
+ '@inertiajs/react': {
+ Link: ({ href, children, ...rest }) =>
+ React.createElement('a', { href, ...rest }, children),
+ },
+ '../management/shared': {
+ Management: ({ children }) =>
+ React.createElement('main', null, children),
+ Pagination: () => null,
+ },
+ }).default;
+ const html = renderToStaticMarkup(
+ React.createElement(Queue, {
+ filters: { status: 'resolved' },
+ incidents: {
+ data: [
+ {
+ ...base,
+ details_url: '/suporte-tecnico/incidentes/one',
+ handling: {
+ status: 'resolved',
+ assignee_name: 'SYNTHETIC support',
+ },
+ },
+ ],
+ total: 1,
+ current_page: 3,
+ last_page: 3,
+ prev_page_url: null,
+ next_page_url: null,
+ },
+ }),
+ );
+ assert.ok(
+ html.includes(
+ 'href="/suporte-tecnico/incidentes/one?page=3&status=resolved"',
+ ),
+ );
+ assert.match(html, /Estado técnico: Resolvido/);
+ assert.match(html, /aria-current="page"/);
+ assert.doesNotMatch(html, /minhas-oportunidades/);
+});
+test('the existing JSON transport preserves the incident reference and never repeats a failed write', async () => {
+ const transport = load('resources/js/lib/profile-json.ts');
+ const oldFetch = globalThis.fetch,
+ oldDocument = globalThis.document;
+ let calls = 0;
+ globalThis.document = { cookie: 'XSRF-TOKEN=SYNTHETIC' };
+ globalThis.fetch = async () => {
+ calls++;
+ return {
+ ok: false,
+ status: 503,
+ headers: { get: () => null },
+ json: async () => ({
+ message: 'SYNTHETIC incident reference: one',
+ reference: 'one',
+ incident_recorded: true,
+ }),
+ };
+ };
+ try {
+ await assert.rejects(
+ transport.profileJson('/minhas-oportunidades/1/workflow', {
+ action: 'submit',
+ }),
+ /SYNTHETIC incident reference: one/,
+ );
+ assert.equal(calls, 1);
+ } finally {
+ globalThis.fetch = oldFetch;
+ globalThis.document = oldDocument;
+ }
+});
+test('publication is distinct and untrusted reference text remains escaped', () => {
+ const html = render([
+ {
+ ...base,
+ operation: 'publish',
+ error_code: 'workflow_unavailable',
+ reference: ' ',
+ },
+ ]);
+ assert.match(html, /Publicação/);
+ assert.match(html, /Falha técnica/);
+ assert.doesNotMatch(html, / {
+ const html = render([{ ...base, operation }]);
+ assert.ok(html.includes(label));
+ assert.doesNotMatch(html, />Publicação/);
+ });
+}
+
+test('the support link exposes only a valid count alongside the server capability', () => {
+ const { profileLinks } = load(
+ 'resources/js/components/profile-navigation.tsx',
+ { '@inertiajs/react': { Link: 'a', usePage: () => ({ props: {} }) } },
+ );
+ const access = {
+ request: '/perfil/promotor',
+ technicalSupport: '/suporte-tecnico/incidentes',
+ };
+ assert.match(
+ profileLinks({ ...access, technicalSupportUnread: 3 }).find(
+ (link) => link.href === access.technicalSupport,
+ ).title,
+ /3 por consultar/,
+ );
+ for (const count of [null, -1, 0, 1.2, Infinity, '4'])
+ assert.equal(
+ profileLinks({ ...access, technicalSupportUnread: count }).find(
+ (link) => link.href === access.technicalSupport,
+ ).title,
+ 'Suporte técnico',
+ );
+ assert.equal(
+ profileLinks({
+ request: access.request,
+ technicalSupportUnread: 3,
+ }).some((link) => link.href === access.technicalSupport),
+ false,
+ );
+});
+
+test('an unknown technical operation is not labelled as a publication', () => {
+ const html = render([{ ...base, operation: 'unknown_operation' }]);
+ assert.match(html, /Operação técnica não identificada/);
+ assert.doesNotMatch(html, />Publicação/);
+});
+
+for (const [code, label] of [
+ ['scan_dispatch_unconfirmed', 'Encaminhamento da análise sem confirmação.'],
+ ['scan_inconclusive', 'Análise de segurança inconclusiva.'],
+ ['scan_worker_failed', 'Falha na execução da análise de segurança.'],
+ [
+ 'scan_cleanup_unconfirmed',
+ 'Limpeza do ficheiro temporário por confirmar.',
+ ],
+]) {
+ test(
+ 'the scan reader distinguishes ' +
+ code +
+ ' from a failed resource save',
+ () => {
+ const html = render([
+ { ...base, operation: 'scan_document', error_code: code },
+ ]);
+ assert.ok(html.includes(label));
+ assert.match(html, /Análise de segurança de documento/);
+ assert.match(html, /O recurso já foi registado/);
+ assert.doesNotMatch(html, />Publicação/);
+ },
+ );
+}
+test('the scan reader never renders an unrecognized internal error code', () => {
+ const html = render([
+ {
+ ...base,
+ operation: 'scan_document',
+ error_code: 'PRIVATE INTERNAL TOKEN',
+ },
+ ]);
+ assert.doesNotMatch(html, /PRIVATE INTERNAL/);
+ assert.match(html, /Falha técnica durante a operação/);
+});
+
+test('unread and technical status filters preserve each other and the detail return context', () => {
+ const Queue = load('resources/js/pages/profiles/technical-support.tsx', {
+ '@inertiajs/react': {
+ Link: ({ children, ...rest }) =>
+ React.createElement('a', rest, children),
+ },
+ '../management/shared': {
+ Management: ({ children }) =>
+ React.createElement('main', null, children),
+ Pagination: () => null,
+ },
+ }).default;
+ const html = renderToStaticMarkup(
+ React.createElement(Queue, {
+ filters: { status: 'resolved', unread: true },
+ incidents: {
+ data: [
+ { ...base, details_url: '/suporte-tecnico/incidentes/one' },
+ ],
+ current_page: 2,
+ total: 1,
+ last_page: 2,
+ },
+ }),
+ );
+ assert.ok(
+ html.includes(
+ 'href="/suporte-tecnico/incidentes?status=open&unread=1"',
+ ),
+ );
+ assert.ok(
+ html.includes('href="/suporte-tecnico/incidentes?status=resolved"'),
+ );
+ assert.ok(
+ html.includes(
+ 'href="/suporte-tecnico/incidentes/one?page=2&status=resolved&unread=1"',
+ ),
+ );
+});
diff --git a/tests/frontend/organization-country-editor.test.mjs b/tests/frontend/organization-country-editor.test.mjs
new file mode 100644
index 00000000..25da9501
--- /dev/null
+++ b/tests/frontend/organization-country-editor.test.mjs
@@ -0,0 +1,165 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { harness, props, text } from './helpers/investment-profile-editor.mjs';
+const id = '20000000-0000-4000-8000-000000000001',
+ form = 'País da organização: SYNTHETIC master',
+ country = 'País de constituição da organização',
+ source = 'Fonte ou referência deste país';
+const org = (patch = {}) => ({
+ id,
+ name: 'SYNTHETIC master',
+ version: 1,
+ country: 'MZ',
+ canEdit: true,
+ provenance: {
+ kind: 'representative_declaration',
+ reference: 'SYNTHETIC saved reference',
+ },
+ ...patch,
+});
+const state = (organization = org(), patch = {}) =>
+ props({ organizations: [organization], ...patch });
+
+test('organization country and source are frozen and repeated together after an uncertain write', async () => {
+ const h = harness(state());
+ h.change(country, 'ZA', form);
+ h.change(source, 'SYNTHETIC new source', form);
+ const first = h.submit(form);
+ assert.equal(first.method, 'PUT');
+ assert.equal(
+ first.url,
+ '/api/v1/investment/organizations/' + id + '/country',
+ );
+ assert.equal(first.data.country, 'ZA');
+ assert.equal(first.data.source_reference, 'SYNTHETIC new source');
+ assert.equal(first.data.payload, undefined);
+ await h.fail();
+ assert.equal(h.field(source, form).props.disabled, true);
+ assert.equal(h.value(country, form), 'ZA');
+ const retry = h.submit(form);
+ assert.deepEqual(retry.data, first.data);
+ await h.reply({ version: 2, country: 'ZA' });
+ assert.match(text(h.form(form)), /Gravação confirmada/);
+ assert.deepEqual(h.reloads[0].only, ['organizations']);
+});
+test('an organization version refresh preserves both local values and uses explicit comparison before another write', async () => {
+ const h = harness(state());
+ h.change(country, 'ZA', form);
+ h.change(source, 'SYNTHETIC local reference', form);
+ h.render(
+ state(
+ org({
+ version: 3,
+ country: 'PT',
+ provenance: {
+ kind: 'representative_declaration',
+ reference: 'SYNTHETIC remote source',
+ },
+ }),
+ ),
+ );
+ assert.equal(h.value(source, form), 'SYNTHETIC local reference');
+ assert.equal(
+ h.button('Guardar país da organização', form).props.disabled,
+ true,
+ );
+ h.click('Consultar país guardado', form);
+ await h.reply(
+ state(
+ org({
+ version: 3,
+ country: 'PT',
+ provenance: {
+ kind: 'representative_declaration',
+ reference: 'SYNTHETIC remote source',
+ },
+ }),
+ ),
+ );
+ assert.match(text(h.form(form)), /SYNTHETIC remote source/);
+ h.click('Usar versão actual e manter a preparação', form);
+ const next = h.submit(form);
+ assert.equal(next.data.version, 3);
+ assert.equal(next.data.country, 'ZA');
+ assert.equal(next.data.source_reference, 'SYNTHETIC local reference');
+});
+test('a validation error belongs to the organization field once and does not remove the reference', async () => {
+ const h = harness(state());
+ h.change(source, 'x', form);
+ const sent = h.submit(form);
+ await h.fail(422, sent, {
+ source_reference: ['SYNTHETIC source too short'],
+ });
+ assert.equal(h.value(source, form), 'x');
+ assert.equal(h.field(source, form).props['aria-invalid'], true);
+ assert.equal(
+ text(h.form(form)).split('SYNTHETIC source too short').length - 1,
+ 1,
+ );
+});
+test('read-only representation has no write command and cannot send one by direct form submission', () => {
+ const h = harness(state(org({ canEdit: false })));
+ assert.equal(h.button('Guardar país da organização', form), undefined);
+ assert.equal(h.field(country, form).props.disabled, true);
+ h.submit(form);
+ assert.equal(h.sent.length, 0);
+});
+test('a lost write followed by revoked representation remains prepared but cannot be repeated', async () => {
+ const h = harness(state());
+ h.change(source, 'SYNTHETIC retained source', form);
+ h.submit(form);
+ await h.fail();
+ h.click('Consultar país guardado', form);
+ await h.reply(state(org({ canEdit: false })));
+ const count = h.sent.length;
+ h.submit(form);
+ assert.equal(h.sent.length, count);
+ assert.equal(h.value(source, form), 'SYNTHETIC retained source');
+ assert.equal(h.button('Repetir o mesmo pedido', form), undefined);
+});
+test('organization edits share one leave guard with the private profile', () => {
+ const h = harness(state());
+ h.change(source, 'SYNTHETIC dirty organization', form);
+ h.change('Telefone', 'SYNTHETIC dirty profile', 'Perfil de investimento');
+ assert.equal(h.leave(), true);
+ assert.equal(h.confirmCalls, 1);
+});
+test('an acknowledgement with the wrong country cannot confirm or erase the prepared source', async () => {
+ const h = harness(state());
+ h.change(country, 'ZA', form);
+ h.change(source, 'SYNTHETIC prepared source', form);
+ h.submit(form);
+ await h.reply({ version: 2, country: 'PT' });
+ assert.equal(h.reloads.length, 0);
+ assert.equal(h.value(source, form), 'SYNTHETIC prepared source');
+ assert.match(text(h.form(form)), /Não foi possível confirmar/);
+});
+test('two rapid consultations share one in-flight read and never write automatically', async () => {
+ const h = harness(state());
+ const read = h.button('Consultar país guardado', form);
+ read.props.onClick();
+ read.props.onClick();
+ h.render();
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.sent[0].method, 'GET');
+ await h.reply(state());
+ assert.equal(h.sent.length, 1);
+ assert.equal(
+ h.button('Guardar país da organização', form).props.disabled,
+ true,
+ );
+});
+test('a fresh authorized read can restore editing after a membership is restored while old page props are read-only', async () => {
+ const h = harness(state(org({ canEdit: false })));
+ h.click('Consultar país guardado', form);
+ await h.reply(state(org({ canEdit: true })));
+ h.click('Usar versão actual e manter a preparação', form);
+ assert.equal(h.field(source, form).props.disabled, false);
+ h.change(source, 'SYNTHETIC restored representation source', form);
+ const sent = h.submit(form);
+ assert.equal(
+ sent.data.source_reference,
+ 'SYNTHETIC restored representation source',
+ );
+ assert.equal(sent.method, 'PUT');
+});
diff --git a/tests/frontend/organization-country-reuse.test.mjs b/tests/frontend/organization-country-reuse.test.mjs
new file mode 100644
index 00000000..484c3753
--- /dev/null
+++ b/tests/frontend/organization-country-reuse.test.mjs
@@ -0,0 +1,158 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import {
+ harness,
+ props,
+ companyId,
+ text,
+} from './helpers/investment-profile-editor.mjs';
+const sourceId = '30000000-0000-4000-8000-000000000001',
+ form = 'Declaração de empresa',
+ country = 'País de constituição da entidade';
+const source = (patch = {}) => ({
+ id: sourceId,
+ name: 'SYNTHETIC reuse source',
+ version: 3,
+ country: 'FR',
+ canEdit: false,
+ provenance: {
+ kind: 'representative_declaration',
+ reference: 'SYNTHETIC stored reference',
+ },
+ ...patch,
+});
+const state = (patch = {}) => props({ organizations: [source()], ...patch });
+async function preview(h, response = state()) {
+ const read = h.click('Consultar país de SYNTHETIC reuse source');
+ assert.equal(read.method, 'GET');
+ await h.reply(response, read);
+}
+
+test('the actual reuse starts with a fresh preview and writes only after explicit confirmation', async () => {
+ const h = harness(state());
+ await preview(h);
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.value(country, form), 'MZ');
+ assert.match(text(h.tree), /SYNTHETIC stored reference/);
+ const request = h.click('Confirmar reutilização do país');
+ assert.equal(request.method, 'POST');
+ assert.equal(
+ request.url,
+ '/api/v1/investment/companies/' + companyId + '/organization-country',
+ );
+ assert.equal(request.data.organization_id, sourceId);
+ assert.equal(request.data.organization_version, 3);
+ assert.equal(request.data.version, 1);
+ assert.equal(request.data.payload, undefined);
+ await h.reply({ version: 2, country: 'FR' });
+ assert.equal(h.value(country, form), 'FR');
+ assert.equal(h.value('Nome da empresa', form), 'SYNTHETIC company');
+ assert.match(text(h.tree), /gravação confirmada/);
+ assert.deepEqual(h.reloads[0].only, ['companies', 'organizations']);
+});
+test('an uncertain reuse locks the company and repeats exactly the frozen source command', async () => {
+ const h = harness(state());
+ await preview(h);
+ const first = h.click('Confirmar reutilização do país');
+ await h.fail();
+ assert.equal(h.field(country, form).props.disabled, true);
+ const count = h.sent.length;
+ h.submit(form);
+ assert.equal(h.sent.length, count);
+ h.render(state({ organizations: [source({ version: 4, country: 'ZA' })] }));
+ const second = h.click('Repetir a mesma reutilização');
+ assert.deepEqual(second.data, first.data);
+ await h.reply({ version: 2, country: 'FR' });
+ assert.equal(h.value(country, form), 'FR');
+ assert.equal(h.field(country, form).props.disabled, false);
+});
+test('unsaved company edits prevent preview and a later edit also prevents confirming a prepared reuse', async () => {
+ const h = harness(state());
+ h.change('Nome da empresa', 'SYNTHETIC dirty company', form);
+ h.click('Consultar país de SYNTHETIC reuse source');
+ assert.equal(h.sent.length, 0);
+ h.change('Nome da empresa', 'SYNTHETIC company', form);
+ await preview(h);
+ h.change('Nome da empresa', 'SYNTHETIC later edit', form);
+ const count = h.sent.length;
+ h.click('Confirmar reutilização do país');
+ assert.equal(h.sent.length, count);
+ assert.equal(h.value('Nome da empresa', form), 'SYNTHETIC later edit');
+});
+test('a conflicting copy preserves the target and requires a new preview and key', async () => {
+ const h = harness(state());
+ await preview(h);
+ const first = h.click('Confirmar reutilização do país');
+ await h.fail(409);
+ assert.equal(h.value(country, form), 'MZ');
+ assert.equal(h.field(country, form).props.disabled, false);
+ assert.equal(h.button('Confirmar reutilização do país'), undefined);
+ await preview(
+ h,
+ state({ organizations: [source({ version: 4, country: 'ZA' })] }),
+ );
+ const next = h.click('Confirmar reutilização do país');
+ assert.notEqual(next.data.operation_key, first.data.operation_key);
+ assert.equal(next.data.organization_version, 4);
+});
+test('a known newer source on the page blocks a stale preview before any write', async () => {
+ const h = harness(state());
+ await preview(h);
+ h.render(state({ organizations: [source({ version: 4, country: 'ZA' })] }));
+ const count = h.sent.length;
+ h.click('Confirmar reutilização do país');
+ assert.equal(h.sent.length, count);
+ assert.match(text(h.tree), /organização.*alterada|organização mudou/);
+});
+test('an invalid acknowledgement retains the original copy and never clears the company', async () => {
+ const h = harness(state());
+ await preview(h);
+ const first = h.click('Confirmar reutilização do país');
+ await h.reply({ version: 2, country: 'ZA' });
+ assert.equal(h.value(country, form), 'MZ');
+ assert.equal(h.field(country, form).props.disabled, true);
+ assert.equal(h.reloads.length, 0);
+ const retry = h.click('Repetir a mesma reutilização');
+ assert.deepEqual(retry.data, first.data);
+});
+test('restored read representation can confirm an original copy while consulting never changes its command', async () => {
+ const h = harness(state());
+ await preview(h);
+ const first = h.click('Confirmar reutilização do país');
+ await h.fail(403);
+ const count = h.sent.length;
+ h.click('Repetir a mesma reutilização');
+ assert.equal(h.sent.length, count);
+ h.click('Consultar estado da reutilização');
+ await h.reply(
+ state({ organizations: [source({ version: 5, country: null })] }),
+ );
+ assert.equal(h.field(country, form).props.disabled, true);
+ const retry = h.click('Repetir a mesma reutilização');
+ assert.deepEqual(retry.data, first.data);
+});
+test('a receipt from a prior actor cannot update the new actor or reload their page', async () => {
+ const h = harness(state());
+ await preview(h);
+ const request = h.click('Confirmar reutilização do país');
+ h.render(state({ actorId: 2, companies: [], organizations: [] }));
+ await h.reply({ version: 2, country: 'FR' }, request);
+ assert.equal(h.reloads.length, 0);
+ assert.doesNotMatch(text(h.tree), /País reutilizado e gravação confirmada/);
+});
+test('a changed target discovered by preview directs comparison without applying a write', async () => {
+ const h = harness(state());
+ const company = { ...h.props.companies[0], version: 2 };
+ await preview(h, state({ companies: [company] }));
+ assert.equal(h.sent.length, 1);
+ assert.equal(h.button('Confirmar reutilização do país'), undefined);
+ assert.match(text(h.tree), /Consulte e compare/);
+ assert.equal(h.value(country, form), 'MZ');
+});
+test('reuse and another dirty form share one page leave guard', async () => {
+ const h = harness(state());
+ await preview(h);
+ h.change('Telefone', 'SYNTHETIC dirty profile', 'Perfil de investimento');
+ assert.equal(h.leave(), true);
+ assert.equal(h.confirmCalls, 1);
+});
diff --git a/tests/frontend/partnership-agreement-history.test.mjs b/tests/frontend/partnership-agreement-history.test.mjs
new file mode 100644
index 00000000..f3bb6d33
--- /dev/null
+++ b/tests/frontend/partnership-agreement-history.test.mjs
@@ -0,0 +1,284 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { harness, props, text } from './helpers/partnership-room.mjs';
+import fs from 'node:fs';
+import { createRequire } from 'node:module';
+import { compileFunction } from 'node:vm';
+import ts from 'typescript';
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+
+test('a legacy instrument without a confirmation map remains readable without inventing pending confirmations', () => {
+ for (const confirmations of [undefined, null, 'SYNTHETIC malformed map']) {
+ const initial = props();
+ initial.room.agreement.confirmations = confirmations;
+ const h = harness(initial);
+ assert.match(text(h.tree), /SYNTHETIC instrument/);
+ assert.match(text(h.tree), /confirmações.*(não.*registad|estrutura)/i);
+ assert.doesNotMatch(text(h.tree), /Confirmações: Pendentes/);
+ }
+});
+
+const require = createRequire(import.meta.url);
+const modules = {};
+const shared = fs.readFileSync(
+ 'resources/js/pages/partnerships/shared.tsx',
+ 'utf8',
+);
+const labels = compileFunction(
+ `return (${shared.match(/export const labels: Record = (\{[\s\S]*?\n\});/)[1]});`,
+ [],
+)();
+function load(file) {
+ const code = ts.transpileModule(fs.readFileSync(file, 'utf8'), {
+ compilerOptions: {
+ module: ts.ModuleKind.CommonJS,
+ jsx: ts.JsxEmit.ReactJSX,
+ },
+ }).outputText;
+ const module = { exports: {} };
+ compileFunction(code, ['require', 'module', 'exports'])(
+ (name) => {
+ if (Object.hasOwn(modules, name)) return modules[name];
+ if (name === './shared')
+ return {
+ labels,
+ Frame: ({ title, children }) =>
+ React.createElement(
+ 'main',
+ {},
+ React.createElement('h1', {}, title),
+ children,
+ ),
+ };
+ if (name === '@inertiajs/react')
+ return {
+ Link: ({ children, ...attributes }) =>
+ React.createElement('a', attributes, children),
+ };
+ return require(name);
+ },
+ module,
+ module.exports,
+ );
+ return module.exports;
+}
+modules['@/lib/partnership-agreement'] = load(
+ 'resources/js/lib/partnership-agreement.ts',
+);
+modules['@/components/partnership-agreement-instrument'] = load(
+ 'resources/js/components/partnership-agreement-instrument.tsx',
+);
+const Instrument =
+ modules['@/components/partnership-agreement-instrument'].default;
+const Page = load(
+ 'resources/js/pages/partnerships/agreement-history.tsx',
+).default;
+const instrument = () => ({
+ title: 'SYNTHETIC frozen title',
+ terms: 'SYNTHETIC frozen terms',
+ confirmations: {},
+ legal_signature_status: 'not_verified',
+});
+const snapshot = () => ({
+ availability: 'available',
+ version: 2,
+ status: 'agreement_recorded',
+ instrument_availability: 'available',
+ instrument: instrument(),
+ instrument_partnership_version: 4,
+ instrument_interest_version: 3,
+});
+const entry = () => ({
+ version: 2,
+ restricted: false,
+ action: 'record',
+ actor_name: 'SYNTHETIC actor',
+ occurred_at: '2026-11-03',
+ reason: 'SYNTHETIC reason',
+ confirmation_party: null,
+ partnership_version: 4,
+ interest_version: 3,
+ previous: { availability: 'not_recorded' },
+ after: snapshot(),
+});
+const history = () => ({
+ room_id: 1,
+ entries: [entry()],
+ first_url: '/parcerias/salas/1/historico',
+ next_url: null,
+ older_page: false,
+ room_href: '/parcerias/salas/1',
+ dashboard_href: '/parcerias/painel',
+});
+const render = (p) => renderToStaticMarkup(React.createElement(Page, p));
+
+test('the stored empty array is an empty confirmation map while nonempty lists stay unrecognized', () => {
+ const value = instrument();
+ value.confirmations = [];
+ assert.match(
+ renderToStaticMarkup(React.createElement(Instrument, { value })),
+ /Confirmações: Pendentes/,
+ );
+ value.confirmations = [{ actor_id: 1 }];
+ assert.match(
+ renderToStaticMarkup(React.createElement(Instrument, { value })),
+ /não têm uma estrutura reconhecida/,
+ );
+});
+
+test('invalid instrument fields never become React children or fabricated confirmations', () => {
+ for (const value of [
+ false,
+ ['SYNTHETIC invalid'],
+ {
+ title: { secret: 'SYNTHETIC PRIVATE' },
+ terms: ['SYNTHETIC PRIVATE'],
+ confirmations: null,
+ },
+ ]) {
+ const html = renderToStaticMarkup(
+ React.createElement(Instrument, { value }),
+ );
+ assert.doesNotMatch(
+ html,
+ /SYNTHETIC PRIVATE|\[object Object\]|Pendentes/,
+ );
+ assert.match(html, /estrutura reconhecida|Título não registado/);
+ }
+});
+
+test('incomplete and unknown confirmation references do not impersonate a party', () => {
+ const initial = props();
+ initial.room.agreement.confirmations = {
+ proponent: { actor_id: 'wrong', date: {}, reason: [] },
+ unknown: { actor_id: 2 },
+ };
+ const h = harness(initial);
+ assert.match(text(h.tree), /Registo de confirmação incompleto/);
+ assert.match(text(h.tree), /não substituem a confirmação de cada parte/);
+ assert.ok(h.button('Confirmar pela minha parte'));
+ assert.equal(h.button('Actualizar confirmação da minha parte'), undefined);
+ assert.doesNotMatch(text(h.tree), /\[object Object\]/);
+});
+
+test('history renders frozen before and after instruments with their decision context and no write actions', () => {
+ const p = history();
+ p.entries[0].previous = snapshot();
+ p.entries[0].previous.instrument.title = 'SYNTHETIC previous title';
+ p.entries[0].after.instrument.confirmations = {
+ candidate: {
+ actor_id: 2,
+ actor_name: 'SYNTHETIC candidate',
+ reason: 'SYNTHETIC confirmation reason',
+ date: '2026-11-03',
+ },
+ };
+ p.entries[0].confirmation_party = 'candidate';
+ const html = render(p);
+ for (const fragment of [
+ 'SYNTHETIC previous title',
+ 'SYNTHETIC frozen title',
+ 'SYNTHETIC candidate',
+ 'SYNTHETIC confirmation reason',
+ 'Contexto da decisão: proposta 4',
+ 'candidatura 3',
+ 'não verificada',
+ 'Parte que confirmou: Candidata',
+ ])
+ assert.ok(html.includes(fragment), fragment);
+ assert.doesNotMatch(html, / {
+ for (const availability of [
+ 'restricted',
+ 'scope_unknown',
+ 'not_recorded',
+ 'malformed',
+ ]) {
+ const p = history();
+ p.entries[0].restricted = true;
+ p.entries[0].reason = 'SYNTHETIC HIDDEN reason';
+ p.entries[0].actor_name = 'SYNTHETIC HIDDEN actor';
+ p.entries[0].previous = {
+ ...snapshot(),
+ availability,
+ instrument: { title: 'SYNTHETIC HIDDEN instrument' },
+ };
+ p.entries[0].after = {
+ ...snapshot(),
+ instrument_availability: availability,
+ instrument: { title: 'SYNTHETIC HIDDEN instrument' },
+ };
+ const html = render(p);
+ assert.doesNotMatch(html, /SYNTHETIC HIDDEN/);
+ assert.match(html, /Conteúdo reservado/);
+ }
+});
+
+test('legacy absence is explicit and history never fills it with a current instrument', () => {
+ const p = history();
+ p.entries[0].after = { availability: 'not_recorded' };
+ const html = render(p);
+ assert.match(html, /Não foi preenchida com a versão actual/);
+ assert.doesNotMatch(html, /SYNTHETIC frozen/);
+});
+
+test('history navigation uses the scoped server URLs and distinguishes older pages', () => {
+ const p = history();
+ p.older_page = true;
+ p.next_url = '/parcerias/salas/1/historico?before=SYNTHETIC-token';
+ const html = render(p);
+ for (const fragment of [
+ 'Voltar à sala',
+ 'Versões mais recentes',
+ 'Consultar versões anteriores',
+ 'before=SYNTHETIC-token',
+ 'href="/parcerias/painel"',
+ ])
+ assert.ok(html.includes(fragment));
+ assert.doesNotMatch(html, / {
+ const p = history();
+ p.entries = [];
+ const html = render(p);
+ assert.match(html, /Ainda não existem alterações do acordo guardadas/);
+ assert.doesNotMatch(
+ html,
+ /Consultar versões anteriores|Antes da alteração/,
+ );
+});
+
+test('stored conditions and reasons are escaped and cannot add links or markup', () => {
+ const p = history();
+ p.entries[0].reason = '';
+ p.entries[0].after.instrument.terms =
+ 'SYNTHETIC ';
+ const html = render(p);
+ assert.ok(html.includes('<script>SYNTHETIC</script>'));
+ assert.ok(html.includes('<a href='));
+ assert.doesNotMatch(html, /',
+ href: '/parcerias/candidaturas/10/historico',
+ read_at: null,
+ },
+ ];
+ const html = render(p);
+ assert.ok(html.includes('<script>'));
+ assert.ok(!html.includes('';
+ p.entries[0].after.assessment = [
+ {
+ code: 'capacity',
+ label: 'SYNTHETIC current catalogue',
+ state: 'unknown',
+ evidence: 'SYNTHETIC recorded evidence',
+ },
+ ];
+ const html = render(p);
+ assert.ok(!html.includes('';
+ p.entries[0].reason = 'synthetic reason ';
+ const html = render(p);
+ assert.ok(!html.includes('';
+ value.entries[0].actor_name = 'SYNTHETIC actor ';
+ const html = renderToStaticMarkup(
+ React.createElement(Component, { value }),
+ );
+ assert.ok(html.includes('<script>SYNTHETIC</script>'));
+ assert.ok(html.includes('<a>SYNTHETIC actor</a>'));
+ assert.doesNotMatch(html, /