oportunidades 7
tests / ci (push) Waiting to run

This commit is contained in:
2026-10-13 11:40:29 +02:00
parent 20971d523f
commit 287e991486
2902 changed files with 1085456 additions and 25957 deletions
+5
View File
@@ -63,6 +63,11 @@ jobs:
npm ci
npm run build
- name: Prevent accidental diagnostic exposure (C132)
run: |
php tools/portal-diagnostics-deployment-guard.php --self-test
php tools/portal-diagnostics-deployment-guard.php
- name: Run CI Checks
run: composer ci:check
+25 -1
View File
@@ -1,4 +1,28 @@
# Regras do acervo documental InvestMoz
# Instruções permanentes do projeto InvesteMoz
## Regras permanentes do InvesteMoz — decisão da Tempo, 12/10/2026
1. O portal InvesteMoz é propriedade da Tempo, Lda.
2. As regras de funcionamento são ditadas pela Tempo, Lda.
3. Os papéis dos seus funcionários são determinados e regidos pela Tempo, Lda.
4. As funcionalidades do portal são determinadas pela Tempo, Lda.
5. Este portal é de âmbito nacional e serve tanto a pessoas nacionais como estrangeiras e exigirá vários intervenientes para a sua operação (manutenção, cadastro, viabilização dos negócios, etc.). Se as regras não são ditadas por quem opera e, ao mesmo tempo, é proprietário, a sua viabilidade é nula.
6. Os constrangimentos criados sem a autorização da Tempo e que impedem o desenvolvimento normal devem ser removidos ou alterados.
7. Antes de iniciar a execução de uma nova funcionalidade, verificar quais são os constrangimentos que podem criar atrasos e círculos viciosos de correcção de erros que poderiam ter sido evitados.
8. As instruções anteriores ditadas pela Tempo mantêm-se.
Registar a origem das restrições: decisão expressa da Tempo, requisito anterior aprovado ou escolha de implementação. Uma escolha de implementação não constitui uma nova exigência organizacional. As autorizações e limites específicos de cada tarefa mantêm-se, incluindo a separação entre preparação em QA e alteração no ativo.
### Aplicação na execução — referência permanente confirmada em 12/10/2026
A Tempo, Lda define o produto, as regras operacionais e as funções dos seus funcionários. As instruções anteriores mantêm-se. Esta formulação consolida as oito regras acima e orienta a leitura das especificações e da matriz de auditoria existente.
- Cada restrição deve ter origem identificável: decisão expressa da Tempo, referência e versão de uma instrução anterior aprovada ou escolha técnica. Escolhas técnicas não se tornam regras de negócio sem autorização da Tempo.
- Constrangimentos introduzidos sem autorização devem ser identificados e removidos ou ajustados, preservando dados, relações, histórico e instruções aprovadas.
- Antes de implementar, verificar as dependências técnicas e operacionais que possam causar bloqueios previsíveis. Distinguir dependências reais de opções de implementação e apresentar antecipadamente as decisões concretas necessárias.
- O portal deve contemplar investidores nacionais e estrangeiros e os diferentes intervenientes da operação, incluindo manutenção, cadastro e viabilização de negócios. O âmbito do portal é nacional.
Referenciar estas orientações nos requisitos correspondentes da matriz existente, sem criar outra matriz ou backlog. A referência documental não encerra um requisito funcional nem substitui a demonstração do seu critério de aceitação.
## Aceitação das fontes oficiais — decisão do responsável, 08/10/2026
@@ -15,6 +15,7 @@ use App\Services\InvestmentZones;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
@@ -51,6 +52,9 @@ class InvestmentSubmissionController extends Controller
abort_unless($company !== null, 404);
$companyData = json_decode(Crypt::decryptString($company->payload), true, 512, JSON_THROW_ON_ERROR);
$payload = [...$payload, 'organisation' => $companyData['name'], 'representative_role' => $companyData['role'], 'incorporation_country_code' => $companyData['incorporation_country_code'] ?? null];
if (isset($companyData['organization_country_snapshot'])) {
$payload['organization_country_snapshot'] = $companyData['organization_country_snapshot'];
}
}
unset($data['company_id']);
if (! empty($data['opportunity_id'])) {
@@ -145,7 +149,8 @@ class InvestmentSubmissionController extends Controller
{
$required = $submitting ? 'required' : 'nullable';
$data = $request->validate(['version' => ['required', 'integer', 'min:1'],
'payload' => ['required', 'array:full_name,email,phone,country,residence_country_code,incorporation_country_code,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload' => ['required', 'array:full_name,email,phone,country,residence_country_code,incorporation_country_code,organization_country_snapshot,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload.organization_country_snapshot' => ['sometimes', 'array', 'max:10'],
'payload.residence_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.incorporation_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.declared_origin_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
@@ -217,7 +222,7 @@ class InvestmentSubmissionController extends Controller
$version = DB::transaction(function () use ($request, $id, $data) {
$row = $this->owned($request, $id, true, true);
abort_unless($row->status === 'draft' && $row->version === (int) $data['version'], 409, 'Rascunho alterado. Recarregue antes de guardar.');
$row->update(['payload' => $data['payload'], 'version' => $row->version + 1]);
$row->update(['payload' => $this->preserveCountrySource($row, $data['payload']), 'version' => $row->version + 1]);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
foreach ($data['needs'] ?? [] as $need) {
InvestmentSpecificNeed::create([...$need, 'submission_id' => $id]);
@@ -230,6 +235,23 @@ class InvestmentSubmissionController extends Controller
return $request->expectsJson() ? response()->json(['version' => $version]) : back()->with('success', 'Rascunho guardado.');
}
/** @param array<string, mixed> $payload
* @return array<string, mixed> */
private function preserveCountrySource(InvestmentSubmission $row, array $payload): array
{
$source = $row->payload['organization_country_snapshot'] ?? null;
if (isset($payload['organization_country_snapshot']) && (! is_array($payload['organization_country_snapshot']) || ! is_array($source) ||
Arr::sortRecursive($payload['organization_country_snapshot']) !== Arr::sortRecursive($source))) {
throw ValidationException::withMessages(['payload.organization_country_snapshot' => 'A proveniência é recuperada no servidor; não pode ser substituída pelo formulário.']);
}
unset($payload['organization_country_snapshot']);
if ($source && ($row->payload['incorporation_country_code'] ?? null) === ($payload['incorporation_country_code'] ?? null)) {
$payload['organization_country_snapshot'] = $source;
}
return $payload;
}
public function submit(Request $request, string $id, InterestSubmission $intake): RedirectResponse|JsonResponse
{
// Replaying a completed submission returns only the owner's existing receipt.
@@ -248,7 +270,7 @@ class InvestmentSubmissionController extends Controller
if ($row->dossier_id) {
InvestmentPortfolioController::visible()->findOrFail($row->dossier_id);
}
$p = $data['payload'];
$p = $this->preserveCountrySource($row, $data['payload']);
$zoneOrigin = DB::table('investment_submission_zones')->where('submission_id', $id)->first(['zone_id', 'zone_version', 'intent']);
if ($zoneOrigin) {
$zone = app(InvestmentZones::class)->visible()->whereKey($zoneOrigin->zone_id)->lockForUpdate()->firstOrFail();
@@ -268,6 +290,7 @@ class InvestmentSubmissionController extends Controller
'declared_origin_country_code' => $p['declared_origin_country_code'] ?? null,
'residence_country_code' => $p['residence_country_code'] ?? null,
'incorporation_country_code' => $p['incorporation_country_code'] ?? null,
...(isset($p['organization_country_snapshot']) ? ['organization_country_snapshot' => $p['organization_country_snapshot']] : []),
...($zoneOrigin ? ['zone_origin' => (array) $zoneOrigin] : [])]]));
$row->update(['payload' => $p, 'version' => $row->version + 1, 'interest_request_id' => $interest->id, 'status' => 'submitted']);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
@@ -6,6 +6,7 @@ use App\Models\InvestmentSubmission;
use App\Models\User;
use App\Services\CountryCatalogue;
use App\Services\InvestmentWorkspace;
use App\Services\OrganizationCountry;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -19,9 +20,10 @@ class InvestmentWorkspaceController extends Controller
{
public function profile(Request $request, InvestmentWorkspace $workspace): Response|JsonResponse
{
$data = ['countries' => app(CountryCatalogue::class)->all(), 'account' => $workspace->account($request->user()->id), 'companies' => DB::table('investment_company_declarations')
$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')
->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;
return $company;
})];
@@ -68,9 +70,15 @@ class InvestmentWorkspaceController extends Controller
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();
$version = (int) $data['version'] + 1;
$previous = $row ? json_decode(Crypt::decryptString($row->payload), true, 512, JSON_THROW_ON_ERROR) : [];
$payload = [...$previous, ...$data['payload']];
if (($previous['incorporation_country_code'] ?? null) !== ($payload['incorporation_country_code'] ?? null)) {
unset($payload['organization_country_snapshot']);
}
$encrypted = Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR));
DB::table('investment_company_declarations')->updateOrInsert(['id' => $id], ['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, 'company_declared', 'investment_company_declarations', $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]);
return ['id' => $id, 'version' => $version];
});
@@ -78,6 +86,36 @@ class InvestmentWorkspaceController extends Controller
return $request->expectsJson() ? response()->json($result) : back()->with('success', 'Declaração de empresa guardada.');
}
public function organizationCountry(Request $request, string $id, OrganizationCountry $service): RedirectResponse|JsonResponse
{
$result = $service->save($request->user(), $id, $request->all());
return $request->expectsJson() ? response()->json($result) : back()->with('success', 'País de constituição guardado no cadastro mestre; submissões anteriores preservadas.');
}
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']);
$result = DB::transaction(function () use ($request, $id, $data, $service) {
$row = DB::table('investment_company_declarations')->where('id', $id)->where('user_id', $request->user()->id)->lockForUpdate()->first();
abort_unless($row !== null, 404);
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.');
$payload = json_decode(Crypt::decryptString($row->payload), true, 512, JSON_THROW_ON_ERROR);
$payload['incorporation_country_code'] = $snapshot['country'];
$payload['organization_country_snapshot'] = $snapshot;
$encrypted = Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR));
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']]);
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.');
}
public function notifications(Request $request): Response|JsonResponse
{
$query = DB::table('investment_notifications')->where('user_id', $request->user()->id);
@@ -25,8 +25,9 @@ class InvestorPathController extends Controller
{
$source = $request->input('content_resource_id');
if ($source !== null) {
abort_unless(filter_var($source, FILTER_VALIDATE_INT), 422);
app(LegacyContent::class)->articleForResource((int) $source);
$resourceId = filter_var($source, FILTER_VALIDATE_INT);
abort_unless(is_int($resourceId) && $resourceId !== 0, 422);
app(LegacyContent::class)->articleForResource($resourceId);
}
$id = DB::transaction(function () use ($path, $request, $source): string {
$id = $path->create($request->user(), $request->all());
@@ -309,6 +309,8 @@ class LandAssistanceController extends Controller
'case' => $case->only(['reference', 'version', 'payload', 'updated_at']),
'disclaimer' => self::DISCLAIMER,
'modelVersion' => 'land-assistance-v1',
'country' => app(CountryCatalogue::class)->describe($case->payload['country'] ?? null),
'declaredOrigin' => app(CountryCatalogue::class)->describe($case->payload['declared_origin_country_code'] ?? null),
]);
}
@@ -9,6 +9,7 @@ use App\Services\OpportunityImageProcessor;
use App\Services\OpportunityManagement;
use App\Services\OpportunityResourceInstallation;
use App\Services\OpportunityResources;
use App\Services\OrganizationCountryInstallation;
use App\Services\PortalProfileAccess;
use App\Services\VerifiedDocumentBinary;
use Illuminate\Http\JsonResponse;
@@ -16,6 +17,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -38,6 +40,39 @@ class OpportunityResourceController extends Controller
return back()->with('success', 'Recursos instalados; nenhum ficheiro publicado ou oportunidade submetida.');
}
public function organizationCountryPreview(Request $request, OrganizationCountryInstallation $service): JsonResponse|Response
{
$plan = $service->preview($request->user());
$scope = $this->countryOperationScope($request, $plan);
$operation = $request->session()->get('portal.country_installation_operation');
if (! is_array($operation) || ($operation['scope'] ?? null) !== $scope) {
$operation = ['scope' => $scope, 'key' => (string) Str::uuid()];
$request->session()->put('portal.country_installation_operation', $operation);
}
$plan = [...$plan, 'operationKey' => $operation['key'], 'actionUrl' => '/management/opportunity-resources-install/organization-country', 'extension' => true];
return $request->expectsJson() ? response()->json($plan) : Inertia::render('management/opportunity-install', $plan);
}
public function organizationCountryApply(Request $request, OrganizationCountryInstallation $service): JsonResponse|RedirectResponse
{
// Preview authorizes the actor; the UUID remains stable until this scope changes or logout.
$plan = $service->preview($request->user());
$operation = $request->session()->get('portal.country_installation_operation');
$data = $request->validate(['idempotency_key' => 'required|uuid']);
abort_unless(is_array($operation) && ($operation['scope'] ?? null) === $this->countryOperationScope($request, $plan)
&& hash_equals($operation['key'], $data['idempotency_key']), 409, 'A operação não corresponde a esta prévia. Atualize a página antes de tentar novamente.');
$result = $service->apply($request->user(), $request->all());
return $request->expectsJson() ? response()->json($result) : back()->with('success', 'País mestre instalado; nenhuma submissão anterior alterada.');
}
/** @param array<string, mixed> $plan */
private function countryOperationScope(Request $request, array $plan): string
{
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
{
$opportunity = Opportunity::withTrashed()->findOrFail($id);
@@ -14,6 +14,7 @@ use App\Services\InvestmentGeography;
use App\Services\InvestmentWorkspace;
use App\Services\OpportunityManagement;
use App\Services\PortalAudit;
use App\Services\PortalProfileAccess;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -126,7 +127,7 @@ class PortalManagementController extends Controller
'id', 'reference', 'full_name', 'email', 'phone', 'investor_type', 'country',
'sector_interest', 'opportunity_reference', 'investment_range', 'message',
'privacy_consent', 'consented_at', 'status', 'created_at', 'reviewed_at', 'reviewed_by', 'metadata',
'existing_business_id', 'modality', 'assigned_to', 'next_action', 'next_action_due_at',
'existing_business_id', 'modality', 'assigned_to', 'next_action', 'next_action_due_at', 'source_page',
]),
'history' => $history,
'consents' => $consents,
@@ -231,7 +232,7 @@ class PortalManagementController extends Controller
$query = $model::query();
if ($resource === 'opportunities') {
if (Schema::hasColumn('opportunities', 'owner_user_id')) {
$query = app(\App\Services\PortalProfileAccess::class)->scope(Opportunity::query(), $request->user());
$query = app(PortalProfileAccess::class)->scope(Opportunity::query(), $request->user());
}
$query->with('primaryTerritory:id,name,location_type,source_system,source_code');
if (isset($filters['geography_scope'])) {
@@ -3,8 +3,11 @@
namespace App\Http\Controllers;
use App\Models\Opportunity;
use App\Services\OpportunityCanonicalContract;
use App\Services\OpportunityContacts;
use App\Services\OpportunityManagement;
use App\Services\OpportunityProfileWorkflow;
use App\Services\PortalInternalDesignation;
use App\Services\PortalProfileAccess;
use App\Services\PortalProfileAdministration;
use App\Services\PortalSuperusers;
@@ -47,6 +50,8 @@ class PortalProfileController extends Controller
return Inertia::render('profiles/administration', ['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(),
'internalTypes' => OpportunityCanonicalContract::BASE_CATEGORIES,
'actorId' => $request->user()->id, 'types' => OpportunityManagement::CATEGORIES,
'organizations' => DB::table('organizations')->whereNull('deleted_at')->get(['id', 'name']),
'securityRequests' => DB::table('portal_security_approvals')->latest()->limit(30)->get(),
@@ -83,6 +88,11 @@ class PortalProfileController extends Controller
return Inertia::render('profiles/audit', ['records' => $records, 'filters' => $filters]);
}
public function registerOperatorOrganization(Request $request, PortalInternalDesignation $service): JsonResponse
{
return response()->json($service->registerOrganization($request->user(), $request->all()), 201);
}
public function grant(Request $request, PortalProfileAdministration $service): JsonResponse
{
return response()->json(['id' => $service->grant($request->user(), $request->all())], 201);
@@ -131,6 +141,11 @@ class PortalProfileController extends Controller
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.']);
}
public function contact(Request $request, int $id, OpportunityContacts $service): JsonResponse
{
return response()->json($service->save($request->user(), $id, $request->all()));
}
public function replacement(Request $request, PortalSuperusers $service): JsonResponse
{
$data = $request->validate(['old_user_id' => 'required|integer', 'new_user_id' => 'required|integer', 'reason' => 'required|string|min:20|max:1000']);
@@ -26,4 +26,15 @@ class PortalProfileInstallationController extends Controller
{
return response()->json($installation->bootstrap($request->user(), $request->all()));
}
public function bootstrapPreview(Request $request, string $id, PortalProfileInstallation $installation): JsonResponse|Response
{
$plan = $installation->bootstrapPreview($request->user(), $id);
return $request->expectsJson() ? response()->json($plan) : Inertia::render('profiles/bootstrap-confirmation', $plan);
}
public function confirmBootstrap(Request $request, string $id, PortalProfileInstallation $installation): JsonResponse
{
return response()->json($installation->confirmBootstrap($request->user(), $id, $request->all()));
}
}
@@ -236,13 +236,22 @@ class PortalServicesController extends Controller
abort_unless(DB::table('portal_partnerships')->where('id', $data['partnership_id'])->where('status', 'published')->exists(), 422);
}
$data['portal_user_id'] = $request->user()?->id;
// Preserve the actual entry form, not only the shared POST endpoint. Never accept an external or administrative referrer as the entry page.
$entry = parse_url($request->headers->get('referer', ''));
$sourcePage = '/apoio';
if (is_array($entry) && strtolower($entry['scheme'] ?? '') === $request->getScheme()
&& strtolower($entry['host'] ?? '') === strtolower($request->getHost())
&& (int) ($entry['port'] ?? (($entry['scheme'] ?? '') === 'https' ? 443 : 80)) === $request->getPort()
&& in_array($entry['path'] ?? '', ['/apoio', '/formularios/investidor', '/formularios/empresa', '/parcerias', '/parcerias/painel'], true)) {
$sourcePage = $entry['path'];
}
try {
$interest = $submission->receive($data, $data['submission_key'], fn () => InterestRequest::create([
'reference' => 'AP-'.now()->year.'-'.Str::ulid(), 'full_name' => $data['fullName'], 'email' => $data['email'],
'phone' => $data['phone'] ?? null, 'country' => $data['country'],
'investor_type' => $data['kind'] === 'company' ? 'empresa' : 'individual',
'sector_interest' => $data['sectorInterest'], 'message' => $data['message'],
'privacy_consent' => true, 'consented_at' => now(), 'status' => 'received', 'source_page' => '/apoio',
'privacy_consent' => true, 'consented_at' => now(), 'status' => 'received', 'source_page' => $sourcePage,
'metadata' => ['kind' => $data['kind'], 'company' => $data['company'] ?? null,
'portal_user_id' => $data['portal_user_id'], 'partnership_id' => $data['partnership_id'] ?? null,
'declared_origin_country_code' => $data['declared_origin_country_code'] ?? null],
@@ -637,7 +646,7 @@ class PortalServicesController extends Controller
'document_id' => ['required', 'uuid'], 'title' => ['required', 'string', 'max:200'],
'description' => ['nullable', 'string', 'max:4000'], 'category' => ['required', 'string', 'max:80'],
// QA legacy originals may have no theme (e.g. a shared image). Do not invent a sector to disclose an authorized original.
'topic' => [app(\App\Services\LegacyContent::class)->available() ? 'nullable' : 'required', 'string', 'max:80'],
'topic' => [app(LegacyContent::class)->available() ? 'nullable' : 'required', 'string', 'max:80'],
'document_type' => ['required', 'in:legislation,procedure,official_form,digital_adaptation,guidance_template,guide,study,reference_data,unknown'],
'issuer' => ['nullable', 'string', 'max:180'], 'document_number' => ['nullable', 'string', 'max:120'],
'document_date' => ['nullable', 'date_format:Y-m-d'], 'source_url' => ['nullable', 'url:https', 'max:2000'],
@@ -3,12 +3,14 @@
namespace App\Http\Controllers;
use App\Services\TerritoryGeometryImport;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class TerritoryGeometryImportController extends Controller
{
public function preview(Request $request, TerritoryGeometryImport $service)
public function preview(Request $request, TerritoryGeometryImport $service): JsonResponse|Response
{
$data = $request->validate(['level' => 'nullable|integer|in:1,2,3']);
$plan = $service->preview($request->user(), (int) ($data['level'] ?? 1));
@@ -16,12 +18,12 @@ class TerritoryGeometryImportController extends Controller
return $request->expectsJson() ? response()->json($plan) : Inertia::render('management/territory-geometry-import', ['plan' => $plan]);
}
public function apply(Request $request, TerritoryGeometryImport $service)
public function apply(Request $request, TerritoryGeometryImport $service): JsonResponse
{
return response()->json($service->apply($request->user(), $request->all()));
}
public function reverse(Request $request, string $batch, TerritoryGeometryImport $service)
public function reverse(Request $request, string $batch, TerritoryGeometryImport $service): JsonResponse
{
return response()->json($service->reverse($request->user(), $batch, $request->all()));
}
+1 -1
View File
@@ -14,7 +14,7 @@ class AuditProfileDecision
public function handle(Request $request, Closure $next): Response
{
$access = app(PortalProfileAccess::class);
if (! $request->user() || ! $access->available() || ! preg_match('#^(perfil/|perfis/|minhas-oportunidades)#', $request->path())) {
if (! $request->user() || ! $access->governanceAvailable() || ! preg_match('#^(perfil/|perfis/|minhas-oportunidades)#', $request->path())) {
return $next($request);
}
try {
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Middleware;
use App\Services\PortalProfileAccess;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsurePortalProfileAdministration
{
public function handle(Request $request, Closure $next): Response
{
abort_unless(config('portal.profile_administration_enabled') || config('portal.profile_access_enabled'), 404);
abort_unless(app(PortalProfileAccess::class)->governanceAvailable(), 503, 'Autorização por perfis ainda não instalada.');
return $next($request);
}
}
+2 -2
View File
@@ -14,8 +14,8 @@ class PortalProfileSession
public function handle(Request $request, Closure $next): Response
{
$access = app(PortalProfileAccess::class);
$available = $access->available();
if ($request->user() && config('portal.profile_access_enabled') && ! $available) {
$available = $access->governanceAvailable();
if ($request->user() && (config('portal.profile_access_enabled') || config('portal.profile_administration_enabled')) && ! $available) {
$recovery = $request->is('management/profile-install', 'management/profile-install/bootstrap')
|| ($request->is('logout') && $request->isMethod('POST'));
abort_if(! in_array($request->method(), ['GET', 'HEAD', 'OPTIONS'], true) && ! $recovery, 503,
@@ -14,7 +14,7 @@ class ProtectPrivilegedIdentity
{
$actor = $request->user();
$access = app(PortalProfileAccess::class);
if (! $actor || ! $access->available()) {
if (! $actor || ! $access->governanceAvailable()) {
return $next($request);
}
if (! in_array($request->method(), ['GET', 'HEAD', 'OPTIONS'], true) && $access->has($actor, 'auditor')
+18 -4
View File
@@ -43,13 +43,27 @@ class AppServiceProvider extends ServiceProvider
{
$this->configureDefaults();
// Fortify calls this response AFTER invalidating/regenerating the server session.
// Clear the client's encryption key too, so Back must reauthorize private pages.
$this->app->bind(\Laravel\Fortify\Contracts\LogoutResponse::class, function () {
return new class extends \Laravel\Fortify\Http\Responses\LogoutResponse
{
public function toResponse($request)
{
\Inertia\Inertia::clearHistory();
return parent::toResponse($request);
}
};
});
Event::listen(ValidTwoFactorAuthenticationCodeProvided::class, function ($event): void {
if (app(PortalProfileAccess::class)->available()) {
session()->put(['portal.mfa_actor' => $event->user->id, 'portal.mfa_at' => time()]);
}
// The authenticated installers also operate before the optional profile schema exists.
// Record a completed Fortify challenge, never enrollment or a password-only login.
session()->put(['portal.mfa_actor' => $event->user->id, 'portal.mfa_at' => time()]);
});
Event::listen(Login::class, function ($event): void {
if (app(PortalProfileAccess::class)->available()) {
if (app(PortalProfileAccess::class)->governanceAvailable()) {
session()->put('portal.access_revision', (int) DB::table('users')->where('id', $event->user->id)->value('portal_access_revision'));
}
});
+12 -4
View File
@@ -78,6 +78,7 @@ final class LegacyContent
}
/** Resolve a library identity, preserving the already stored source URLs and versions. */
/** @return array<string, mixed> */
public function articleForResource(int $resourceId): array
{
abort_unless($this->available(), 404);
@@ -99,14 +100,14 @@ final class LegacyContent
$articles[] = $this->article($item['slug']);
}
abort_unless($articles !== [], 404);
return $articles;
}
/** @return list<array<string,mixed>> */
private function related(string $group, ?string $except = null): array
{
$identities = array_filter(config('legacy_content.articles', []), fn ($identity, $slug) =>
$identity['group'] === $group && $identity['publishable'] && $slug !== $except, ARRAY_FILTER_USE_BOTH);
$identities = array_filter(config('legacy_content.articles', []), fn ($identity, $slug) => $identity['group'] === $group && $identity['publishable'] && $slug !== $except, ARRAY_FILTER_USE_BOTH);
$resources = $this->publicResources()->whereIn('d.external_id', array_column($identities, 'external_id'))->get()->keyBy('external_id');
$result = [];
foreach ($identities as $slug => $identity) {
@@ -115,6 +116,7 @@ final class LegacyContent
$result[] = ['slug' => $slug, 'id' => (int) $row->resource_id, 'title' => $row->title, 'href' => '/'.$slug];
}
}
return $result;
}
@@ -134,11 +136,17 @@ final class LegacyContent
$doc->loadHTML('<?xml encoding="UTF-8"><html><body>'.$html.'</body></html>', LIBXML_NONET);
foreach ($doc->getElementsByTagName('a') as $anchor) {
$href = $anchor->getAttribute('href');
if (isset($links[rtrim($href, '/')])) { $anchor->setAttribute('href', $links[rtrim($href, '/')]); }
if (isset($links[rtrim($href, '/')])) {
$anchor->setAttribute('href', $links[rtrim($href, '/')]);
}
}
$body = $doc->getElementsByTagName('body')->item(0);
return $body ? implode('', array_map(fn ($child) => $doc->saveHTML($child), iterator_to_array($body->childNodes))) : '';
} finally { libxml_clear_errors(); libxml_use_internal_errors($old); }
} finally {
libxml_clear_errors();
libxml_use_internal_errors($old);
}
}
/** @param array<string, mixed> $input */
+52 -5
View File
@@ -15,6 +15,33 @@ use Opis\JsonSchema\Errors\ValidationError;
/** Explicit adapter of §25/26 to existing IDs and resource collections; never renumbers records. */
class OpportunityCanonicalContract
{
public const BASE_CATEGORIES = ['investment_project', 'real_estate', 'land_rights', 'business_sale', 'business_partnership', 'franchise'];
/** Availability of this bounded base-category delivery, without rewriting existing contracts/data. */
public function deliveryBlockers(array $payload): array
{
$errors = [];
if (! in_array($payload['opportunity_category'] ?? '', self::BASE_CATEGORIES, true) && ! app(OpportunityModularProfiles::class)->enabled()) {
$errors['canonical.opportunity_category'] = 'Categoria fora desta entrega: concessão, financiamento, fornecimento e outros permanecem indisponíveis. Os registos anteriores são preservados.';
}
if (($payload['opportunity_category'] ?? '') === 'real_estate') {
$property = $payload['real_estate'] ?? [];
foreach (['construction_status' => ['completed'], 'occupancy_status' => ['vacant'], 'transaction_type' => ['sale', 'lease']] as $field => $values) {
if (! empty($property[$field]) && ! in_array($property[$field], $values, true)) {
$errors['canonical.real_estate.'.$field] = 'Variante indisponível para submissão nesta entrega. Pode guardar e recuperar a preparação; estão incluídas venda e arrendamento de imóvel concluído e desocupado.';
}
}
if (array_filter($property['encumbrances'] ?? [], fn ($row) => ! empty($row['type']) && $row['type'] !== 'none')) {
$errors['canonical.real_estate.encumbrances'] = 'Imóvel com encargos: pode preparar e guardar; a submissão deste ramo não está incluída nesta entrega.';
}
if (! empty($property['max_built_area']) || ! empty($property['urban_limit_document_id'])) {
$errors['canonical.real_estate.max_built_area'] = 'Limitações urbanísticas adicionais: preparação disponível; este ramo de submissão aguarda demonstração própria.';
}
}
return $errors;
}
public const VERSION = 'opportunity-canonical-adapter-20261010-semantic1';
/** @return array<string,mixed> */
@@ -178,7 +205,7 @@ class OpportunityCanonicalContract
}
};
$check(($payload['opportunity_category'] ?? null) === $record->opportunity_category, 'opportunity_category', 'A categoria deve coincidir com o registo e a autorização.');
$check(($payload['promoter_id'] ?? null) === ($record->organization_id ?? (int) $record->owner_user_id), 'promoter_id', 'Use a organização representada ou o autor individual; não outra identidade.');
$check(($payload['promoter_id'] ?? null) === ($record->organization_id ?? (int) $record->owner_user_id), 'promoter_id', 'Identifique o promotor real da oportunidade; o operador do portal não o substitui.');
$sector = DB::table('sectors')->where('id', $payload['sector_id'])->whereNull('deleted_at')->where('is_active', true)->first();
$subsector = DB::table('economic_activities')->where('id', $payload['subsector_id'])->where('status', 'published')->first();
$activity = DB::table('economic_activities')->where('id', $payload['economic_activity_id'])->where('status', 'published')->first();
@@ -244,11 +271,18 @@ class OpportunityCanonicalContract
'payload' => $payload, 'resources' => $resources];
if (isset(OpportunityModularProfiles::PROFILES[$record->opportunity_category]) || ($payload['module_profile_version'] ?? '') === OpportunityModularProfiles::HISTORY_VERSION) {
$snapshot['qa_extension'] = ['version' => OpportunityModularProfiles::VERSION, 'profile_version' => $payload['module_profile_version'],
'functional_decision' => 'User recommendations accepted for QA, 10/10/2026; no active approval or security-holder nomination',
'functional_decision' => 'Experimental QA proposal; functional approval of modular contracts and SLA remains pending. Legacy integration authorization does not approve these modules.',
'gates' => $this->gates($record)];
if ($record->opportunity_category === 'other') {
$snapshot['qa_extension']['subtype'] = config('portal.opportunity_other_qa_subtypes.'.($payload['module_details']['subtype'] ?? ''), []);
}
// A documentary correction must not rewrite the checksum of an already
// signed, unchanged version. Its historical annotation is explicitly
// reconciled by the read adapter; new/changed content uses the current note.
$prior = $record->workflow_context['submission'] ?? [];
if (isset($prior['qa_extension']) && ($prior['payload'] ?? null) == $snapshot['payload'] && ($prior['resources'] ?? null) == $snapshot['resources']) {
$snapshot['qa_extension']['functional_decision'] = $prior['qa_extension']['functional_decision'];
}
}
$snapshot['hash'] = hash('sha256', json_encode($snapshot, JSON_THROW_ON_ERROR));
@@ -297,8 +331,16 @@ class OpportunityCanonicalContract
}
if ($category === 'real_estate') {
$re = $p['real_estate'];
if (($re['transaction_type'] === 'sale' && ($re['price'] ?? 0) <= 0) || ($re['transaction_type'] === 'lease' && (($re['rent'] ?? 0) <= 0 || empty($re['rent_periodicity'])))) {
$errors['canonical.real_estate.price'] = 'Venda exige preço positivo; arrendamento exige renda positiva e periodicidade.';
if ($re['transaction_type'] === 'sale' && ($re['price'] ?? 0) <= 0) {
$errors['canonical.real_estate.price'] = 'Venda exige preço positivo.';
}
if ($re['transaction_type'] === 'lease') {
if (($re['rent'] ?? 0) <= 0) {
$errors['canonical.real_estate.rent'] = 'Arrendamento exige renda positiva.';
}
if (empty($re['rent_periodicity'])) {
$errors['canonical.real_estate.rent_periodicity'] = 'Indique a periodicidade da renda.';
}
}
if (in_array($re['construction_status'], ['completed', 'occupied', 'renovation'], true) && empty($re['property_condition'])) {
$errors['canonical.real_estate.property_condition'] = 'Imóvel existente exige condição identificada.';
@@ -438,6 +480,10 @@ class OpportunityCanonicalContract
public function options(User $actor, ?Opportunity $record): array
{
$orgs = array_values(array_unique(array_column(app(PortalProfileAccess::class)->navigation($actor)['contexts'] ?? [], 'organization_id')));
if (! $record && (app(PortalProfileAccess::class)->navigation($actor)['internalPromoter'] ?? false)) {
// A staff creation scope does not expose unrelated private contact lists.
$orgs = [];
}
if ($record?->organization_id) {
$orgs = [$record->organization_id];
}
@@ -451,7 +497,8 @@ class OpportunityCanonicalContract
'schema' => $this->schema(true)['$defs']['opportunityCreate'],
'definitions' => $this->schema(true)['$defs'],
'activities' => DB::table('economic_activities')->where('status', 'published')->get(['id', 'parent_id', 'sector_id', 'label_pt_mz', 'catalog_version_id']),
'contacts' => $contacts, 'countries' => app(CountryCatalogue::class)->all(),
'contacts' => $contacts, 'contactInvestors' => $record?->organization_id ? DB::table('investors')->where('organization_id', $record->organization_id)->whereNull('deleted_at')->whereIn('status', ['prospect', 'active'])->get(['id', 'legal_name']) : [],
'countries' => app(CountryCatalogue::class)->all(),
'authorities' => DB::table('authorities')->where('status', 'published')->get(['id', 'label_pt_mz']),
'gates' => $record ? $this->gates($record) : [], 'resources' => $record ? array_combine(['locations', 'documents', 'images'], array_map(fn ($k) => array_values(array_filter(app(OpportunityResources::class)->listing($record->id, $k), fn ($row) => empty($row->deleted_at))), ['locations', 'documents', 'images'])) : []];
}
@@ -0,0 +1,112 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
/** Identities and mutation history inside the existing workflow JSON, never parallel tables. */
class OpportunityCanonicalMetadata
{
/** @param array<string,mixed> $payload
* @return array<string,array<string,mixed>> */
private function items(array $payload, string $path = ''): array
{
$found = [];
foreach ($payload as $key => $value) {
$pointer = ltrim($path.'.'.$key, '.');
if (! is_array($value)) {
continue;
}
if (! array_is_list($value)) {
$found[$pointer] = $value;
}
$found += $this->items($value, $pointer);
}
return $found;
}
/** @param array<string,mixed> $before
* @param array<string,mixed> $after
* @param array<string,mixed> $metadata
* @return array<string,mixed> */
public function mutate(array $before, array $after, array $metadata, User $actor, string $reason): array
{
$old = $this->items($before);
$new = $this->items($after);
$active = $metadata['active'] ?? [];
$retired = $metadata['deleted'] ?? [];
$next = [];
$used = [];
foreach ($new as $path => $value) {
$fingerprint = OpportunityCanonicalValue::hash($value);
$match = null;
// A collection reorder preserves identity by bytes, not by its new index.
foreach ($active as $previousPath => $item) {
if (! isset($used[$previousPath]) && ($item['fingerprint'] ?? '') === $fingerprint
&& preg_replace('/\.\d+(?=\.|$)/', '.*', $previousPath) === preg_replace('/\.\d+(?=\.|$)/', '.*', $path)) {
$match = $previousPath;
break;
}
}
// Named singleton modules have a stable path; list rows need an unambiguous match.
if ($match === null && ! preg_match('/\.\d+(?:\.|$)/', $path) && isset($active[$path]) && ! isset($used[$path])) {
$match = $path;
}
$item = $match !== null ? $active[$match] : null;
if ($match !== null) {
$used[$match] = true;
}
$changed = $item === null || ($item['fingerprint'] ?? '') !== $fingerprint;
$legacy = $item === null && isset($old[$path]);
$item ??= ['id' => (string) Str::uuid(), 'version' => 0, 'created_by' => $legacy ? null : $actor->id,
'created_at' => $legacy ? null : now()->toIso8601String(), 'first_observed_at' => now()->toIso8601String(),
'identity_source' => $legacy ? 'legacy_first_observation_not_creation' : 'server_generated_new_item'];
if ($changed) {
$item['version']++;
$item['updated_by'] = $actor->id;
$item['updated_at'] = now()->toIso8601String();
}
$next[$path] = [...$item, 'fingerprint' => $fingerprint, 'is_deleted' => false,
'active' => true, 'deleted_at' => null, 'deleted_by' => null, 'delete_reason' => null];
}
foreach ($active as $path => $item) {
if (isset($used[$path])) {
continue;
}
$retired[$item['id']] = [...$item, 'path' => $path, 'version' => $item['version'] + 1,
'is_deleted' => true, 'active' => false, 'deleted_at' => now()->toIso8601String(),
'deleted_by' => $actor->id, 'delete_reason' => $reason, 'last_value' => $old[$path] ?? null];
}
return ['active' => $next, 'deleted' => $retired, 'rule' => 'existing-json-identities-v1'];
}
/** @param array<string,mixed> $payload
* @param array<string,mixed> $metadata
* @return array<string,mixed> */
public function project(array $payload, array $metadata): array
{
// Deepest paths first so a parent does not overwrite the children's identities.
$paths = array_keys($metadata['active'] ?? []);
foreach ($paths as $path) {
if (! is_string($path)) {
throw new \UnexpectedValueException('Canonical item paths must be named fields.');
}
}
usort($paths, fn ($a, $b) => substr_count($b, '.') <=> substr_count($a, '.'));
foreach ($paths as $path) {
$value = Arr::get($payload, $path);
if (! is_array($value)) {
continue;
}
$item = $metadata['active'][$path];
unset($item['fingerprint']);
Arr::set($payload, $path, [...$value, ...$item]);
}
return $payload;
}
}
+86 -8
View File
@@ -4,11 +4,15 @@ namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
/** Read adapter only: preserve persisted identifiers and make unresolved metadata explicit. */
class OpportunityCanonicalResponse
{
public const VERSION = 'opportunity-response-existing-ids-20261010-1';
public const VERSION = 'opportunity-response-existing-ids-20261011-4';
/** @return array<string,mixed> */
public function read(User $actor, Opportunity $record): array
@@ -17,14 +21,32 @@ class OpportunityCanonicalResponse
$access->authorize($actor, 'view', $record);
$payload = app(OpportunityManagement::class)->values($record)['canonical'] ?? [];
$context = $record->workflow_context ?? [];
$data = [...$payload, 'id' => $record->id, 'opportunity_code' => $record->reference,
$data = [...app(OpportunityCanonicalMetadata::class)->project($payload, $context['canonical_items'] ?? []), 'id' => $record->id, 'opportunity_code' => $record->reference,
'opportunity_category' => $record->opportunity_category, 'status' => $access->state($record),
'version' => (int) $record->management_version, 'is_deleted' => $record->trashed(),
'deleted_at' => $record->deleted_at?->toIso8601String()];
foreach (['submitted' => 'submission', 'approved' => 'approval', 'published' => 'publication'] as $prefix => $key) {
'deleted_at' => $record->deleted_at?->toIso8601String(), ...$this->rootMetadata($record)];
foreach (['submitted' => 'submission', 'approved' => 'approval', 'published' => 'publication', 'archived' => 'archive'] as $prefix => $key) {
$data[$prefix.'_by'] = $context[$key]['actor_id'] ?? null;
$data[$prefix.'_at'] = $context[$key]['at'] ?? null;
}
$completion = app(OpportunityCompleteness::class)->calculate($payload);
$data['completion_percentage'] = $completion['percentage'];
$errors = [];
try {
app(OpportunityCanonicalContract::class)->validateSubmission($record);
} catch (ValidationException $failure) {
$errors = $failure->errors();
} catch (HttpExceptionInterface $failure) {
$errors = ['canonical.resources' => ['Recurso indisponível para validação; estado HTTP '.$failure->getStatusCode().'. Preserve o original e resolva a operação afetada.']];
}
$data['validation_result'] = ['errors' => $errors, 'warnings' => [], 'rule' => OpportunityCanonicalContract::VERSION,
'evaluated_at' => now()->toIso8601String(), 'persisted_submission_hash' => $context['submission']['hash'] ?? null,
'external_decision' => 'not_inferred'];
$mutations = [];
foreach (DB::table('audit_events')->where('source_system', 'opportunity-resources')->where('after_data->opportunity_id', $record->id)->orderBy('occurred_at')->orderBy('id')->get(['actor_user_id', 'action', 'occurred_at', 'after_data']) as $event) {
$detail = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR);
$mutations[$detail['resource_id']][] = ['actor' => $event->actor_user_id, 'action' => $event->action, 'at' => $event->occurred_at, 'reason' => $detail['reason'] ?? null];
}
$references = [];
foreach (OpportunityResources::KINDS as $kind) {
$references[$kind] = $payload[$kind] ?? [];
@@ -34,7 +56,7 @@ class OpportunityCanonicalResponse
$rows[$row->id] = $row;
}
}
$data[$kind] = array_map(function (string $id) use ($rows, $kind): array {
$data[$kind] = array_map(function (string $id) use ($rows, $kind, $mutations): array {
$row = $rows[$id] ?? null;
if ($row === null) {
return ['id' => $id, 'availability' => 'unavailable'];
@@ -42,6 +64,13 @@ class OpportunityCanonicalResponse
$value = [...$row->payload, 'id' => $row->id, 'version' => (int) $row->version,
'is_deleted' => $row->deleted_at !== null, 'deleted_at' => $row->deleted_at,
'created_by' => $row->created_by, 'created_at' => $row->created_at, 'updated_at' => $row->updated_at];
$events = $mutations[$id] ?? [];
$last = $events ? $events[array_key_last($events)] : null;
$deletion = $row->deleted_at && ($last['action'] ?? '') === 'delete' ? $last : null;
$value['updated_by'] = $last['actor'] ?? ((int) $row->version === 1 ? $row->created_by : null);
$value['deleted_by'] = $deletion['actor'] ?? null;
$value['delete_reason'] = $deletion && $deletion['reason'] ? Crypt::decryptString($deletion['reason']) : null;
$value['mutation_metadata_source'] = $last ? 'existing_audit_events' : 'creation_record_only';
if ($kind !== 'locations') {
$value['original_name'] = $row->file?->file_name;
$value['mime_type'] = $row->file?->media_type;
@@ -56,15 +85,64 @@ class OpportunityCanonicalResponse
return ['adapter_version' => self::VERSION,
'source_schema_sha256' => hash_file('sha256', resource_path('data/investmoz-opportunity-modular.schema.json')),
'data' => $data, 'resource_references' => $references,
'validation_result' => ['scope' => 'recorded_submission_only', 'submission_hash' => $context['submission']['hash'] ?? null,
'completion' => $completion, 'materiality' => $context['materiality'] ?? null,
'review_conditions' => array_values($context['conditions'] ?? []),
'deleted_inline_items' => array_values($context['canonical_items']['deleted'] ?? []),
'validation_result' => ['scope' => 'current_payload_validation_and_recorded_submission_metadata', 'submission_hash' => $context['submission']['hash'] ?? null,
'submitted_content_revision' => $context['submission']['content_revision'] ?? null,
'current_content_revision' => $context['content_revision'] ?? 1,
'revalidated_on_read' => false, 'external_decision' => 'not_inferred'],
'revalidated_on_read' => true, 'external_decision' => 'not_inferred'],
'publication' => $record->publicationPresentation(),
'compatibility' => ['normative_response_complete' => false, 'opportunity_actor_sector_ids' => 'existing bigint, not converted to UUID',
'modular_decision' => 'Functional approval of four modular contracts and SLA remains pending; legacy integration did not approve them. Historical snapshot annotations are preserved, not current approvals.',
'opportunity_code' => 'existing reference preserved; no INV-MZ code invented',
'states' => 'existing workflow values preserved; no implicit stage equivalence',
'inline_modules' => 'management_draft canonical JSON with audited revisions; no parallel specialized tables',
'metadata_gaps' => ['completion_percentage algorithm', 'inline item IDs and mutation metadata', 'resource updated_by/deleted_by recovery']]];
'state_correspondence' => ['draft' => 'draft', 'needs_information' => 'returned', 'submitted' => 'submitted', 'approved' => 'approved', 'published' => 'published', 'suspended' => 'suspended', 'archived' => 'archived', 'rejected' => 'rejected'],
'unmapped_review_states' => 'in_review/information_pending preserve parallel gates; no single normative stage inferred',
'metadata_gaps' => ['Legacy inline creation metadata can be unknown; first observation is not creation. Ambiguous changed collection rows get new identities with previous identities retained as deleted.', 'Existing bigint IDs remain explicit compatibility differences; no renumbering.']]];
}
/**
* Recover actors from existing audited versions; an imported creator must never be inferred.
*
* @return array<string,mixed>
*/
private function rootMetadata(Opportunity $record): array
{
$events = [];
foreach (DB::table('audit_events')->whereIn('source_system', ['opportunity-management', 'portal-profiles-v1'])
->where('after_data->record_id', $record->id)->get(['source_system', 'actor_user_id', 'action', 'after_data']) as $event) {
$detail = json_decode($event->after_data, true, 512, JSON_THROW_ON_ERROR);
$version = $detail['version'] ?? $detail['after']['version'] ?? null;
if (! is_int($version)) {
continue;
}
$events[$version] = ['actor' => $event->actor_user_id, 'action' => $event->action,
'reason' => $detail['reason'] ?? null, 'encrypted_reason' => $event->source_system === 'opportunity-management'];
}
ksort($events);
$creation = null;
$deletion = null;
foreach ($events as $event) {
if ($event['action'] === 'draft_created') {
$creation = $event;
}
if ($event['action'] === 'delete') {
$deletion = $event;
}
}
$latest = $events[(int) $record->management_version] ?? null;
$deletion = $record->trashed() ? $deletion : null;
return ['created_by' => $creation['actor'] ?? null, 'created_at' => $record->created_at?->toIso8601String(),
'updated_by' => $latest['actor'] ?? null, 'updated_at' => $record->updated_at?->toIso8601String(),
'deleted_by' => $deletion['actor'] ?? null,
'delete_reason' => $deletion && $deletion['reason'] ? ($deletion['encrypted_reason'] ? Crypt::decryptString($deletion['reason']) : $deletion['reason']) : null,
'mutation_metadata_source' => 'existing_audit_events_and_record_timestamps',
'mutation_metadata_gaps' => array_values(array_filter([
$creation === null ? 'No recorded creation actor; imported ownership does not establish creation.' : null,
$latest === null ? 'No audit actor matching the current management version; no updater inferred.' : null,
]))];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Services;
/** Normalize object key order only. Ordered coordinates and lists retain their meaning. */
class OpportunityCanonicalValue
{
public static function hash(mixed $value): string
{
return hash('sha256', json_encode(self::normalize($value), JSON_THROW_ON_ERROR));
}
private static function normalize(mixed $value): mixed
{
if (! is_array($value)) {
return $value;
}
$result = array_map(self::normalize(...), $value);
if (! array_is_list($result)) {
ksort($result);
}
return $result;
}
}
@@ -61,6 +61,9 @@ class OpportunityCategoryFields
foreach (['markets' => 'marketCreate', 'risks' => 'riskCreate', 'licenses' => 'licenseCreate', 'milestones' => 'milestoneCreate'] as $field => $def) {
$common[$field]['items'] = ['$ref' => '#/$defs/'.$def];
}
// Reuse the existing canonical object definition in both editor and validation.
// The extracted Create property was opaque, preventing completion through the UI.
$common['environmental_social'] = ['$ref' => '#/$defs/environmentalSocialCreate'];
$common['maturity_stage']['enum'] = [...array_keys(OpportunityMaturity::STAGES), null];
$common['financial_indicators'] = $this->object(['npv' => ['type' => 'number'], 'irr' => ['type' => 'number'], 'payback_years' => $n, 'scenario' => $s, 'horizon_years' => ['type' => 'integer', 'minimum' => 1], 'currency' => ['type' => 'string', 'pattern' => '^[A-Z]{3}$'], 'discount_rate' => $n, 'model_document_id' => $d], ['npv', 'irr', 'payback_years', 'scenario', 'horizon_years', 'currency', 'discount_rate', 'model_document_id']);
$defs['milestoneCreate']['properties'] += ['start_date' => $date, 'end_date' => $date, 'responsible_name' => $s, 'dependencies' => $strings];
@@ -219,7 +222,11 @@ class OpportunityCategoryFields
}
$fail(! $lr['exploitation_plan_required'] || ! empty($lr['exploitation_plan_document_id']), 'land_rights.exploitation_plan_document_id', 'Plano de exploração aplicável exige documento.');
$fail(! $lr['communities_affected'] || (! empty($lr['communities']) && ! empty($lr['community_consultation'])), 'land_rights.community_consultation', 'Comunidade afetada exige comunidade, representantes e consulta documentada.');
$communityKeys = [];
foreach ($lr['communities'] ?? [] as $i => $row) {
$key = json_encode([$row['name'] ?? null, $row['location_id'] ?? null]);
$fail(! isset($communityKeys[$key]), "land_rights.communities.$i.name", 'A mesma comunidade/localização já está incluída (§27).');
$communityKeys[$key] = true;
foreach (['representative_name', 'consultation_date', 'location_id'] as $field) {
$fail(! empty($row[$field]), "land_rights.communities.$i.$field", 'Identifique representante, data e localização da comunidade.');
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace App\Services;
use Opis\JsonSchema\Validator;
/** Transparent field completion, separate from validation, approval and external decisions. */
class OpportunityCompleteness
{
/** @param array<string,mixed> $payload
* @return array<string,mixed> */
public function calculate(array $payload): array
{
$schema = app(OpportunityCanonicalContract::class)->schema();
$validator = new Validator;
$paths = [];
$walk = function (mixed $value, array $node, string $path) use (&$walk, &$paths, $schema, $validator): void {
if (isset($node['$ref'])) {
$node = $schema['$defs'][basename($node['$ref'])] ?? $node;
}
$requirements = $node['required'] ?? [];
foreach ($node['allOf'] ?? [] as $condition) {
if (! isset($condition['if'])) {
$walk($value, $condition, $path);
continue;
}
$test = $condition['if'];
if (str_contains(json_encode($test, JSON_THROW_ON_ERROR), '#/$defs/')) {
$test['$defs'] = $schema['$defs'];
}
$actual = json_decode(json_encode(is_array($value) && ! array_is_list($value) ? (object) $value : $value, JSON_THROW_ON_ERROR), false, 512, JSON_THROW_ON_ERROR);
$yes = $validator->validate($actual, json_decode(json_encode($test, JSON_THROW_ON_ERROR), false, 512, JSON_THROW_ON_ERROR))->isValid();
$walk($value, $condition[$yes ? 'then' : 'else'] ?? [], $path);
}
foreach ($requirements as $key) {
$v = is_array($value) ? ($value[$key] ?? null) : null;
$paths[ltrim($path.'.'.$key, '.')] = $v !== null && $v !== '' && $v !== [];
}
foreach ($node['properties'] ?? [] as $key => $child) {
if (is_array($value) && array_key_exists($key, $value)) {
$walk($value[$key], $child, ltrim($path.'.'.$key, '.'));
}
}
if (isset($node['items']) && is_array($value) && array_is_list($value)) {
foreach ($value as $i => $child) {
$walk($child, $node['items'], $path.'.'.$i);
}
}
};
$walk($payload, ['$ref' => '#/$defs/opportunityCreate'], '');
$filled = count(array_filter($paths));
$total = count($paths);
return ['percentage' => $total ? round(100 * $filled / $total, 2) : 0, 'filled' => $filled, 'applicable' => $total,
'missing_paths' => array_keys(array_filter($paths, fn ($filled) => ! $filled)),
'rule' => 'required-applicable-fields-v1', 'scope' => 'Required fields and activated schema conditions; optional/hidden modules excluded. Presence is not validation or approval.'];
}
}
+93
View File
@@ -0,0 +1,93 @@
<?php
namespace App\Services;
use App\Models\Contact;
use App\Models\Investor;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
/** Reuse the CRM master without manufacturing an interest, lead or consent. */
class OpportunityContacts
{
public function save(User $actor, int $id, array $input): array
{
$access = app(PortalProfileAccess::class);
$record = Opportunity::withTrashed()->findOrFail($id);
$access->authorize($actor, 'edit', $record);
abort_unless($access->mfa($actor), 403, 'Confirme a autenticação multifator nesta sessão.');
$data = Validator::make($input, [
'etag' => 'required|string|size:64',
'full_name' => 'required|string|min:2|max:150',
'email' => 'required|email:rfc|max:150',
'phone' => ['required', 'regex:/^\+[1-9]\d{7,14}$/'],
'investor_id' => 'nullable|uuid',
'investor_type' => ['nullable', Rule::in(['domestic', 'foreign', 'institutional', 'individual'])],
])->validate();
$data['email'] = strtolower(trim($data['email']));
$data['full_name'] = trim(preg_replace('/\s+/u', ' ', $data['full_name']));
return DB::transaction(function () use ($actor, $id, $data, $access) {
$record = Opportunity::withTrashed()->whereKey($id)->lockForUpdate()->firstOrFail();
$access->authorize($actor, 'edit', $record);
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $data['etag']), 409, 'A oportunidade mudou. Recupere a versão atual antes de cadastrar o contacto.');
DB::select('SELECT pg_advisory_xact_lock(170925, hashtext(?))', [$data['email']]);
$matches = Contact::withTrashed()->whereRaw('lower(trim(email)) = ?', [$data['email']])->lockForUpdate()->get();
$scoped = function (Contact $contact) use ($record): bool {
return $record->organization_id
? DB::table('investor_contacts as ic')->join('investors as i', 'i.id', '=', 'ic.investor_id')
->where('ic.contact_id', $contact->id)->where('i.organization_id', $record->organization_id)->whereNull('i.deleted_at')->exists()
: $contact->source_system === 'portal-user-contact' && $contact->external_id === 'user:'.$record->owner_user_id;
};
if ($matches->isNotEmpty()) {
$contact = $matches->first(fn ($row) => ! $row->trashed() && $scoped($row));
if ($matches->count() !== 1 || ! $contact || $contact->full_name !== $data['full_name'] || $contact->phone !== $data['phone']) {
throw ValidationException::withMessages(['email' => 'Não foi possível reutilizar este contacto neste âmbito. Escolha um contacto autorizado existente ou reconcilie os dados no cadastro mestre; nenhum registo foi alterado.']);
}
return ['contact' => $contact->only(['id', 'full_name']), 'reused' => true, 'message' => 'Contacto existente recuperado, sem duplicação. Guarde a seleção no rascunho.'];
}
$investor = null;
if ($record->organization_id) {
DB::select('SELECT pg_advisory_xact_lock(170926, hashtext(?))', [$record->organization_id]);
$investors = Investor::where('organization_id', $record->organization_id)->whereIn('status', ['prospect', 'active'])->lockForUpdate()->get();
if (! empty($data['investor_id'])) {
$investor = $investors->firstWhere('id', $data['investor_id']);
abort_unless($investor, 403, 'O cadastro selecionado não pertence ao promotor desta oportunidade.');
} elseif ($investors->count() === 1) {
$investor = $investors->first();
} elseif ($investors->count() > 1) {
throw ValidationException::withMessages(['investor_id' => 'Selecione o cadastro mestre do promotor; não será criada outra entidade.']);
} else {
if (empty($data['investor_type'])) {
throw ValidationException::withMessages(['investor_type' => 'Indique a classificação do promotor no cadastro existente.']);
}
$organization = DB::table('organizations')->where('id', $record->organization_id)->whereNull('deleted_at')->first();
abort_unless($organization, 422, 'Organização indisponível.');
$investor = new Investor;
PortalAudit::save($investor, ['organization_id' => $organization->id, 'legal_name' => $organization->name,
'investor_type' => $data['investor_type'], 'status' => 'prospect', 'source_system' => 'portal-promoter-master',
'external_id' => 'organization:'.$organization->id], $actor->id);
}
} else {
abort_unless(empty($data['investor_id']) && empty($data['investor_type']), 422);
}
$contact = new Contact;
PortalAudit::save($contact, ['full_name' => $data['full_name'], 'email' => $data['email'], 'phone' => $data['phone'],
'source_system' => $record->organization_id ? 'portal-promoter-contact' : 'portal-user-contact',
'external_id' => $record->organization_id ? null : 'user:'.$record->owner_user_id,
'data_classification' => 'internal'], $actor->id);
if ($investor) {
DB::table('investor_contacts')->insertOrIgnore(['investor_id' => $investor->id, 'contact_id' => $contact->id, 'is_primary' => false]);
}
$access->audit($actor, 'opportunity_contact_registered', ['record_id' => $id, 'contact_id' => $contact->id,
'organization_id' => $record->organization_id, 'investor_id' => $investor?->id, 'automatically_published' => false]);
return ['contact' => $contact->only(['id', 'full_name']), 'reused' => false, 'message' => 'Contacto guardado no cadastro existente. Guarde a seleção no rascunho; não foi publicado.'];
});
}
}
@@ -41,6 +41,33 @@ class OpportunityImageProcessor
abort_unless(hash_equals(trim($doc->sha256), hash('sha256', $bytes)), 409, 'Integridade divergente.');
$size = @getimagesizefromstring($bytes);
abort_unless($size && $size[0] >= 400 && $size[1] >= 400 && $size[0] * $size[1] <= 40000000, 422, 'Dimensões inválidas ou imagem excessiva para processamento seguro.');
$previousPayload = json_decode($image->payload, true, 512, JSON_THROW_ON_ERROR);
$previousDerivatives = $previousPayload['derivatives'] ?? [];
$expectedWidths = array_unique(array_map(fn ($width) => min($width, $size[0]), [320, 640, 1280]));
if (($previousPayload['derived_from_sha256'] ?? null) === trim($doc->sha256)
&& array_values(array_column($previousDerivatives, 'width')) === array_values($expectedWidths)) {
$reusable = true;
$retry = [];
foreach ($previousDerivatives as $derivative) {
$existing = DB::table('documents')->where('id', $derivative['document_id'])->whereNull('deleted_at')->first();
if (! $existing || $existing->source_system !== 'opportunity-image-derivatives' || ! $disk->exists($existing->storage_key)) {
$reusable = false;
break;
}
$existingBytes = Crypt::decryptString($disk->get($existing->storage_key));
if (! hash_equals(trim($existing->sha256), hash('sha256', $existingBytes))) {
$reusable = false;
break;
}
if ($existing->malware_scan_status !== 'clean') {
$retry[] = $existing->id;
}
}
if ($reusable) {
$documents = $retry;
return; // Retry scans of the same streams, without new files, versions or audit decisions.
}
}
$decoded = @imagecreatefromstring($bytes);
abort_unless($decoded !== false, 422, 'Não foi possível descodificar a imagem.');
$derivatives = [];
+21 -2
View File
@@ -9,6 +9,7 @@ use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
@@ -64,6 +65,15 @@ class OpportunityManagement
abort_unless($access->legacyWriteAllowed($actor), 403, 'O papel v1 não usa a criação legada para contornar o seu âmbito.');
}
abort_unless($this->installed(), 503, 'Instalação autenticada ainda necessária.');
// Canonical common fields are authoritative. The editor may echo legacy
// mirrors, but they must not impose a second, incompatible contract.
if (is_array($input['canonical'] ?? null)) {
foreach (['official_title' => 'title', 'executive_summary' => 'summary', 'demand_statement' => 'description', 'sector_id' => 'sector_id', 'promoter_type' => 'promoter_type'] as $source => $target) {
if (array_key_exists($source, $input['canonical'])) {
unset($input[$target]);
}
}
}
$data = Validator::make($input, [
'etag' => [$id ? 'required' : 'nullable', 'string', 'size:64'],
'creation_key' => [$id ? 'nullable' : 'required', 'uuid'],
@@ -115,6 +125,7 @@ class OpportunityManagement
abort_if($record->trashed() || $record->status === 'archived', 409, 'Restaure antes de editar.');
}
$before = $record->getAttributes();
$previousCanonical = $record->exists ? ($this->values($record)['canonical'] ?? []) : [];
$changes = array_intersect_key($data, array_flip([...self::FIELDS, ...self::PRIVATE_DRAFT_FIELDS]));
if (array_key_exists('canonical', $changes)) {
$previous = $record->exists ? $this->values($record) : [];
@@ -125,7 +136,10 @@ class OpportunityManagement
// One entry of common data feeds the existing fields; a closed/public version stays untouched.
foreach (['official_title' => 'title', 'executive_summary' => 'summary', 'demand_statement' => 'description', 'sector_id' => 'sector_id', 'promoter_type' => 'promoter_type'] as $source => $target) {
if (array_key_exists($source, $changes['canonical'])) {
$changes[$target] = $changes['canonical'][$source];
$value = $changes['canonical'][$source];
// Preserve the full text in canonical JSON; the legacy
// summary column is only a bounded presentation mirror.
$changes[$target] = $target === 'summary' && is_string($value) ? Str::limit($value, 499, '…') : $value;
}
}
}
@@ -156,6 +170,9 @@ class OpportunityManagement
$record->owner_user_id = $actor->id;
$record->organization_id = $data['organization_id'] ?? null;
$record->workflow_context = ['policy_version' => PortalProfileAccess::VERSION, 'contributors' => [$actor->id]];
if (($internal=$access->internalAssignment($actor,$data['opportunity_category'] ?? '')) !== null) {
$record->workflow_context=[...$record->workflow_context,'operator_organization_id'=>$internal->organization_id,'internal_assignment_id'=>$internal->id];
}
}
} else {
$record->management_version++;
@@ -179,9 +196,11 @@ class OpportunityManagement
}
if ($record->owner_user_id !== null) {
$context = $record->workflow_context ?? [];
unset($context['approval'], $context['reviews']);
unset($context['approval']);
$context['content_revision'] = ($context['content_revision'] ?? 0) + 1;
$context['contributors'] = array_values(array_unique([...($context['contributors'] ?? []), $actor->id]));
$context['canonical_items'] = app(OpportunityCanonicalMetadata::class)->mutate(
$previousCanonical, $this->values($record)['canonical'] ?? [], $context['canonical_items'] ?? [], $actor, $data['reason']);
$record->workflow_context = $context;
}
$record->save();
@@ -21,6 +21,7 @@ class OpportunityManagementInstallation
$files = [...$files, resource_path('js/lib/portal-navigation.ts'), resource_path('js/components/portal-grouped-menu.tsx')];
$files = [...$files, ...PortalProfileAccess::fingerprintFiles()];
return hash('sha256', json_encode(array_map(fn ($file) => hash_file('sha256', $file), $files), JSON_THROW_ON_ERROR));
}
+99 -11
View File
@@ -22,7 +22,7 @@ class OpportunityProfileWorkflow
}
$actions = [];
$state = $this->access->state($record);
if ($this->access->scoped($actor, 'promoter', $record->organization_id, $record->opportunity_category)
if ($this->access->promoterRecordScope($actor, $record)
&& ($record->organization_id !== null || (int) $record->owner_user_id === $actor->id)
&& $this->access->operational($actor, 'edit', $record->id)) {
if (in_array($state, ['draft', 'needs_information'], true)) {
@@ -40,6 +40,9 @@ class OpportunityProfileWorkflow
}
if ($this->access->mfa($actor) && ! $this->access->conflict($actor, $record)) {
if ($this->access->scoped($actor, 'validator', $record->organization_id, $record->opportunity_category) && $this->access->operational($actor, 'validate', $record->id)) {
if ($state === 'approved' && count(array_filter($record->workflow_context['conditions'] ?? [], fn ($condition) => $condition['status'] === 'open' && $condition['blocking_action'] === 'publish')) > 0) {
$actions[] = 'review_gate';
}
if ($state === 'submitted') {
$actions[] = 'start_review';
}
@@ -93,10 +96,14 @@ class OpportunityProfileWorkflow
{
$this->access->authorize($actor, 'view', $record);
if (! $this->access->has($actor, 'validator') && ! $this->access->has($actor, 'publisher')) {
return ['validators' => [], 'publishers' => []];
return ['validators' => [], 'publishers' => [], 'condition_responsibles' => []];
}
$result = ['validators' => [], 'publishers' => []];
$result = ['validators' => [], 'publishers' => [], 'condition_responsibles' => []];
foreach (User::whereNotNull('email_verified_at')->whereNotNull('two_factor_confirmed_at')->get() as $candidate) {
if ($this->access->canView($candidate, $record) && (($this->access->promoterRecordScope($candidate, $record) && $this->access->operational($candidate, 'edit', $record->id))
|| ($this->access->scoped($candidate, 'validator', $record->organization_id, $record->opportunity_category) && $this->access->operational($candidate, 'validate', $record->id)))) {
$result['condition_responsibles'][] = ['id' => $candidate->id, 'name' => $candidate->name];
}
if ($this->access->conflict($candidate, $record)) {
continue;
}
@@ -138,8 +145,17 @@ class OpportunityProfileWorkflow
'opinion_id' => 'sometimes|uuid', 'recipient_user_id' => 'sometimes|integer|min:1',
'evidence_document_ids' => 'sometimes|array', 'evidence_document_ids.*' => 'uuid', 'due_at' => 'prohibited',
'confirm_publication' => 'sometimes|boolean', 'preview_hash' => 'sometimes|string|size:64',
'condition' => 'sometimes|array:description,responsible_user_id,due_on,blocking_action',
'condition.description' => 'required_with:condition|string|min:10|max:1000',
'condition.responsible_user_id' => 'required_with:condition|integer|min:1',
'condition.due_on' => 'sometimes|nullable|date_format:Y-m-d',
'condition.blocking_action' => 'required_with:condition|in:approve,publish',
'resolve_condition_ids' => 'sometimes|array', 'resolve_condition_ids.*' => 'uuid|distinct',
])->validate();
$action = $data['action'];
if ($action !== 'review_gate' && (isset($data['condition']) || ! empty($data['resolve_condition_ids']))) {
throw ValidationException::withMessages(['condition' => 'Condições só podem ser verificadas numa revisão especializada autorizada.']);
}
$this->authorizeAction($actor, $record, $action);
return DB::transaction(function () use ($actor, $id, $data, $action) {
@@ -151,7 +167,8 @@ class OpportunityProfileWorkflow
$before = ['status' => $state, 'publication_status' => $record->status, 'version' => $record->management_version];
$from = match ($action) {
'submit' => ['draft', 'needs_information'], 'start_review' => ['submitted'],
'request_correction', 'pending_opinion', 'respond_opinion', 'reject', 'approve', 'review_gate', 'assign_review' => ['submitted', 'in_review', 'information_pending'],
'request_correction', 'pending_opinion', 'respond_opinion', 'reject', 'approve', 'assign_review' => ['submitted', 'in_review', 'information_pending'],
'review_gate' => ['submitted', 'in_review', 'information_pending', 'approved'],
'publish' => ['approved'], 'suspend' => [$state],
'assign_publication' => ['approved'],
'request_revision' => ['approved', 'published', 'suspended'],
@@ -163,24 +180,52 @@ class OpportunityProfileWorkflow
abort_unless(in_array($state, $from, true), 409, 'Transição incompatível com o estado atual.');
$decision = ['actor_id' => $actor->id, 'action' => $action, 'reason' => $data['reason'], 'at' => now()->toIso8601String(),
'content_revision' => $context['content_revision'] ?? 1];
if (isset($context['review_cycle'])) {
$decision['review_cycle'] = $context['review_cycle'];
}
$next = $state;
$snapshot = [];
if ($action === 'submit' && $record->opportunity_category === 'land_rights') {
// Serialize the existing JSON-backed §27 uniqueness check across records.
DB::select('SELECT pg_advisory_xact_lock(111026,270000)');
}
if (in_array($action, ['submit', 'review_gate', 'pending_opinion', 'respond_opinion', 'approve', 'publish'], true)) {
$snapshot = $this->contract->validateSubmission($record);
$blockers = $this->contract->deliveryBlockers($this->management->values($record)['canonical'] ?? []);
try {
$snapshot = $this->contract->validateSubmission($record);
} catch (ValidationException $error) {
$errors = $error->errors();
foreach ($blockers as $field => $message) {
$errors[$field][] = $message;
}
throw ValidationException::withMessages($errors);
}
if ($blockers !== []) {
throw ValidationException::withMessages($blockers);
}
if ($action !== 'submit') {
abort_unless(hash_equals($context['submission']['hash'] ?? '', $snapshot['hash']), 409, 'Conteúdo ou recursos mudaram desde a submissão. Exige nova submissão/revisão.');
}
}
if ($action === 'submit') {
// New review attempt, even when the canonical content is unchanged.
// Historical decisions/tasks and the content revision keep their IDs.
$context['review_cycle'] = max((int) ($context['review_cycle'] ?? 0), $this->submissionCount($context)) + 1;
$decision['review_cycle'] = $context['review_cycle'];
foreach ($context['opinions'] ?? [] as $opinionId => $opinion) {
if (($opinion['status'] ?? '') === 'pending') {
$context['opinions'][$opinionId]['status'] = 'superseded';
$this->tasks->complete($opinion['task_id'] ?? null, 'Nova versão submetida; parecer anterior preservado.');
}
}
$baseline = $context['review_baseline'] ?? $context['submission'] ?? [];
$materiality = app(OpportunityReviewMateriality::class)->reconcile($baseline, $snapshot, $context['reviews'] ?? [], $this->contract->gates($record), ! empty($context['force_review']));
$context['materiality'] = array_diff_key($materiality, ['reviews' => true]);
$context['reviews'] = $materiality['reviews'];
app(OpportunityReviewConditions::class)->reconcile($context, $snapshot, $materiality['reopened']);
$context['submission'] = [...$snapshot, ...$decision];
$context['sla'] = ['policy_version' => null, 'due_at' => null, 'status' => 'unconfigured'];
unset($context['approval'], $context['reviews'], $context['assignment'],$context['publication_assignment']);
unset($context['approval'], $context['assignment'], $context['publication_assignment'], $context['review_baseline'], $context['force_review']);
$record->first_submitted_at ??= now()->toIso8601String();
$record->management_closed_once = true;
$record->workflow_context = $context;
@@ -192,11 +237,25 @@ class OpportunityProfileWorkflow
abort_unless($this->access->scoped($subject, 'validator', $record->organization_id, $record->opportunity_category)
&& $this->access->operational($subject, 'validate', $record->id) && ! $this->access->conflict($subject, $record)
&& $subject->two_factor_confirmed_at !== null, 403, 'Responsável requer papel válido, MFA configurado e independência.');
if ($this->tasks->closedReviewBinding($record, $context['review_task_id'] ?? null)) {
// Recover only a completed task of this opportunity in an
// already submitted legacy attempt. Never reopen/delete it.
$oldTask = $context['review_task_id'];
$context['review_cycle'] = max(1, (int) ($context['review_cycle'] ?? 0), $this->submissionCount($context));
$record->workflow_context = $context;
$context['review_task_id'] = $this->tasks->ensure($record, 'opportunity_review', 'Validação da oportunidade '.$record->reference);
$context['review_task_binding_history'][] = ['previous_task_id' => $oldTask, 'task_id' => $context['review_task_id'],
'review_cycle' => $context['review_cycle'], 'at' => now()->toIso8601String(), 'reason' => 'Completed legacy review binding replaced for the current submission; original preserved.'];
$decision['review_cycle'] = $context['review_cycle'];
}
$context['review_task_id'] ??= $this->tasks->ensure($record, 'opportunity_review', 'Validação da oportunidade '.$record->reference);
$this->tasks->assign($record, $context['review_task_id'], $subject);
$context['assignment'] = [...$decision, 'assignee_user_id' => $subject->id];
$next = 'in_review';
} elseif ($action === 'review_gate') {
if ($state === 'approved') {
throw_unless(! empty($data['resolve_condition_ids']) && empty($data['condition']) && ($data['gate_decision'] ?? '') === 'approved', ValidationException::withMessages(['resolve_condition_ids' => 'Após aprovação, só verificar condições de publicação existentes; alterações exigem nova revisão.']));
}
$gate = $data['gate'] ?? '';
abort_unless(in_array($gate, $this->contract->gates($record), true), 422, 'Gate não aplicável.');
$legal = preg_match('/legal|registry|authority|confidentiality|license/', $gate) === 1;
@@ -204,14 +263,19 @@ class OpportunityProfileWorkflow
$documents = $data['evidence_document_ids'] ?? [];
abort_unless($documents !== [] && array_diff($documents, array_keys($snapshot['resources']['documents'] ?? [])) === [], 422, 'Selecione evidência documental desta versão.');
abort_unless(isset($data['gate_decision']), 422, 'Indique decisão fundamentada do gate.');
app(OpportunityReviewConditions::class)->review($record, $actor, $data, $snapshot, $context);
$context['reviews'][$gate] = [...$decision, 'decision' => $data['gate_decision'], 'hash' => $snapshot['hash'], 'evidence_document_ids' => $documents];
$context['reviews'][$gate]['scope_hash'] = app(OpportunityReviewMateriality::class)->hash($snapshot, $gate, $context['reviews'][$gate]);
$context['reviews'][$gate]['scope_rule'] = OpportunityReviewMateriality::VERSION;
$next = 'in_review';
} elseif ($action === 'approve') {
app(OpportunityReviewConditions::class)->authorize($context, $snapshot, 'approve');
abort_if(count(array_filter($context['opinions'] ?? [], fn ($o) => ($o['hash'] ?? '') === $snapshot['hash'] && ($o['status'] ?? '') === 'pending')) > 0, 422, 'Parecer da versão atual ainda pendente.');
abort_if(count(array_filter($context['opinions'] ?? [], fn ($o) => ($o['hash'] ?? '') === $snapshot['hash'] && ($o['response']['decision'] ?? '') === 'rejected')) > 0, 422, 'Parecer desfavorável exige correção e nova versão.');
foreach ($this->contract->gates($record) as $gate) {
$review = $context['reviews'][$gate] ?? [];
abort_unless(($review['decision'] ?? null) === 'approved' && ($review['hash'] ?? '') === $snapshot['hash'], 422, 'Gate '.$gate.' pendente, rejeitado ou de outra versão.');
abort_unless(($review['decision'] ?? null) === 'approved' && (($review['hash'] ?? '') === $snapshot['hash'] || ($review['accepted_submission_hash'] ?? '') === $snapshot['hash']), 422, 'Gate '.$gate.' pendente, rejeitado ou de outra versão.');
abort_unless(app(OpportunityReviewMateriality::class)->matches($snapshot, $gate, $review), 409, 'Âmbito da revisão alterado.');
$reviewer = User::whereKey($review['actor_id'])->firstOrFail();
abort_unless($this->access->scoped($reviewer, 'validator', $record->organization_id, $record->opportunity_category)
&& ! $this->access->conflict($reviewer, $record) && $this->access->operational($reviewer, 'validate', $record->id)
@@ -229,13 +293,14 @@ class OpportunityProfileWorkflow
$this->tasks->assign($record, $context['publication_task_id'], $subject);
$context['publication_assignment'] = [...$decision, 'assignee_user_id' => $subject->id];
} elseif ($action === 'publish') {
app(OpportunityReviewConditions::class)->authorize($context, $snapshot, 'publish');
Validator::make($data, ['confirm_publication' => 'required|accepted', 'preview_hash' => 'required|string|size:64'])->validate();
$this->contract->validatePublication($snapshot);
abort_unless(hash_equals($snapshot['hash'], $data['preview_hash']), 409, 'Pré-visualização diferente da versão aprovada.');
abort_unless(($context['approval']['hash'] ?? '') === $snapshot['hash'], 409, 'Aprovação não corresponde ao conteúdo atual.');
foreach ($this->contract->gates($record) as $gate) {
$review = $context['approval']['gates'][$gate] ?? [];
abort_unless(($review['decision'] ?? null) === 'approved' && ($review['hash'] ?? '') === $snapshot['hash'], 422, 'Revisão aprovada desta versão necessária.');
abort_unless(($review['decision'] ?? null) === 'approved' && (($review['hash'] ?? '') === $snapshot['hash'] || ($review['accepted_submission_hash'] ?? '') === $snapshot['hash']), 422, 'Revisão aprovada desta versão necessária.');
$reviewer = User::whereKey($review['actor_id'])->firstOrFail();
abort_unless($this->access->scoped($reviewer, 'validator', $record->organization_id, $record->opportunity_category)
&& ! $this->access->conflict($reviewer, $record) && $this->access->operational($reviewer, 'validate', $record->id)
@@ -312,7 +377,9 @@ class OpportunityProfileWorkflow
$this->tasks->complete($context['review_task_id'] ?? null, $data['reason']);
$this->tasks->complete($context['publication_task_id'] ?? null, $data['reason']);
$context['decision_history'][] = ['approval' => $context['approval'] ?? null, 'reviews' => $context['reviews'] ?? null, 'submission' => $context['submission'] ?? null];
unset($context['approval'], $context['reviews']);
$context['review_baseline'] = $context['submission'] ?? [];
$context['force_review'] = $action === 'appeal_reopen' || $state === 'suspended';
unset($context['approval']);
$next = 'needs_information';
} elseif ($action === 'request_archive') {
$context['request_archive'] = $decision;
@@ -330,6 +397,9 @@ class OpportunityProfileWorkflow
$context['rejection'] = $decision;
$this->tasks->complete($context['review_task_id'] ?? null, $data['reason']);
}
if ($action === 'archive') {
$context['archive'] = $decision;
}
if (in_array($action, ['suspend', 'archive'], true)) {
$record->status = $next;
foreach (['review_task_id', 'correction_task_id', 'publication_task_id', 'appeal_task_id'] as $task) {
@@ -343,7 +413,10 @@ class OpportunityProfileWorkflow
$this->tasks->complete($context['appeal_task_id'] ?? null, $data['reason']);
}
if (in_array($action, ['request_correction', 'reject'], true)) {
unset($context['approval'], $context['reviews']);
if ($action === 'reject') {
$context['force_review'] = true;
}
unset($context['approval']);
}
if (in_array($action, ['request_correction', 'reject', 'suspend', 'archive', 'request_revision', 'appeal_reopen'], true)) {
foreach ($context['opinions'] ?? [] as $opinionId => $opinion) {
@@ -369,6 +442,21 @@ class OpportunityProfileWorkflow
});
}
/** @param array<array-key, mixed> $context */
private function submissionCount(array $context): int
{
$events = $context['events'] ?? [];
abort_unless(is_array($events), 409, 'Histórico de submissões inconsistente; preservar e recuperar antes de continuar.');
$count = 0;
foreach ($events as $event) {
if (is_array($event) && ($event['action'] ?? null) === 'submit') {
$count++;
}
}
return $count;
}
private function responsibility(User $actor, Opportunity $record, string $name): bool
{
foreach ($this->access->grants($actor, $name === 'publication_coordinator' ? 'publisher' : 'validator') as $grant) {
@@ -385,7 +473,7 @@ class OpportunityProfileWorkflow
private function authorizeAction(User $actor, Opportunity $record, string $action): void
{
$this->access->authorize($actor, 'view', $record);
$promoter = $this->access->scoped($actor, 'promoter', $record->organization_id, $record->opportunity_category)
$promoter = $this->access->promoterRecordScope($actor, $record)
&& ($record->organization_id !== null || (int) $record->owner_user_id === $actor->id);
if (in_array($action, ['submit', 'request_archive', 'appeal', 'request_revision'], true)) {
abort_unless($promoter && $this->access->operational($actor, 'edit', $record->id), 403);
@@ -35,7 +35,9 @@ class OpportunityResourceInstallation
$files = [...$files, resource_path('js/lib/portal-navigation.ts'), resource_path('js/components/portal-grouped-menu.tsx')];
$files = [...$files, ...PortalProfileAccess::fingerprintFiles()];
$files = [...$files, ...PortalProfileAccess::fingerprintFiles(), app_path('Services/OrganizationCountry.php'), app_path('Services/OrganizationCountryInstallation.php'),
database_path('migrations/2026_10_10_050000_extend_organization_country.php'), base_path('routes/investment.php')];
return hash('sha256', json_encode(array_map(fn ($file) => hash_file('sha256', $file), $files), JSON_THROW_ON_ERROR));
}
@@ -0,0 +1,90 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
/** Explicit internal review conditions in the existing workflow JSON and audit. */
class OpportunityReviewConditions
{
/** @param array<string,mixed> $data
* @param array<string,mixed> $snapshot
* @param array<string,mixed> $context */
public function review(Opportunity $record, User $actor, array $data, array $snapshot, array &$context): void
{
$gate = $data['gate'];
foreach ($data['resolve_condition_ids'] ?? [] as $id) {
$condition = $context['conditions'][$id] ?? null;
$this->require($condition !== null && $condition['gate'] === $gate && $condition['status'] === 'open', 'resolve_condition_ids', 'Selecione uma condição aberta desta revisão.');
$this->require(($data['gate_decision'] ?? '') === 'approved', 'gate_decision', 'A resolução exige verificação interna aprovada com evidência.');
$documents = [];
foreach ($data['evidence_document_ids'] ?? [] as $documentId) {
$documents[$documentId] = $snapshot['resources']['documents'][$documentId]['sha256'];
}
$this->require($documents !== [], 'evidence_document_ids', 'A resolução exige documento ativo e analisado desta oportunidade.');
$context['conditions'][$id]['status'] = 'resolved';
$context['conditions'][$id]['resolution'] = ['actor_id' => $actor->id, 'at' => now()->toIso8601String(), 'reason' => $data['reason'], 'document_hashes' => $documents, 'content_revision' => $context['content_revision'] ?? 1, 'scope' => 'internal_verification_not_external_decision'];
}
if (! empty($data['condition'])) {
$input = $data['condition'];
$subject = User::query()->whereKey($input['responsible_user_id'])->first();
$access = app(PortalProfileAccess::class);
$this->require($subject !== null && $access->canView($subject, $record)
&& (($access->scoped($subject, 'promoter', $record->organization_id, $record->opportunity_category) && $access->operational($subject, 'edit', $record->id))
|| ($access->scoped($subject, 'validator', $record->organization_id, $record->opportunity_category) && $access->operational($subject, 'validate', $record->id))),
'condition.responsible_user_id', 'Selecione um responsável autorizado neste âmbito; não atribua responsabilidade externa.');
$id = (string) Str::uuid();
$context['conditions'][$id] = ['id' => $id, 'gate' => $gate, 'description' => $input['description'], 'responsible_user_id' => $subject->id,
'responsible_name' => $subject->name, 'due_on' => $input['due_on'] ?? null, 'blocking_action' => $input['blocking_action'],
'status' => 'open', 'created_by' => $actor->id, 'created_at' => now()->toIso8601String(), 'scope' => 'internal_review_condition', 'resolution_history' => []];
}
}
/** @param array<string,mixed> $context
* @param array<string,mixed> $snapshot
* @param list<string> $reopened */
public function reconcile(array &$context, array $snapshot, array $reopened): void
{
foreach ($context['conditions'] ?? [] as $id => $condition) {
if ($condition['status'] !== 'resolved') {
continue;
}
$matches = ! in_array($condition['gate'], $reopened, true);
foreach ($condition['resolution']['document_hashes'] ?? [] as $documentId => $sha) {
$matches = $matches && ($snapshot['resources']['documents'][$documentId]['sha256'] ?? null) === $sha;
}
if (! $matches) {
$context['conditions'][$id]['resolution_history'][] = $condition['resolution'];
unset($context['conditions'][$id]['resolution']);
$context['conditions'][$id]['status'] = 'open';
$context['conditions'][$id]['reopened_at'] = now()->toIso8601String();
}
}
}
/** @param array<string,mixed> $context
* @param array<string,mixed> $snapshot */
public function authorize(array $context, array $snapshot, string $action): void
{
foreach ($context['conditions'] ?? [] as $condition) {
if ($action === 'approve' && $condition['blocking_action'] !== 'approve') {
continue;
}
$resolved = $condition['status'] === 'resolved';
foreach ($condition['resolution']['document_hashes'] ?? [] as $id => $sha) {
$resolved = $resolved && ($snapshot['resources']['documents'][$id]['sha256'] ?? null) === $sha;
}
$this->require($resolved, 'conditions.'.$condition['id'], 'Condição pendente: '.$condition['description'].'. Responsável: '.$condition['responsible_name'].'. Prazo: '.($condition['due_on'] ?? 'não definido').'.');
}
}
private function require(bool $ok, string $field, string $message): void
{
if (! $ok) {
throw ValidationException::withMessages([$field => $message]);
}
}
}
@@ -0,0 +1,166 @@
<?php
namespace App\Services;
use Illuminate\Support\Arr;
/** §28.1: preserve signed decisions; only changed review scopes need new decisions. */
class OpportunityReviewMateriality
{
public const VERSION = 'review-scopes-20261011-v3';
public const PREVIOUS_VERSION = 'review-scopes-20261011-v2';
/** @param array<string,mixed> $snapshot
* @return array<string,mixed> */
private function scope(array $snapshot, string $gate, bool $extended = true): array
{
$p = $snapshot['payload'] ?? [];
$common = ['opportunity_category', 'promoter_id', 'promoter_type', 'sector_id', 'subsector_id', 'economic_activity_id', 'demand_statement', 'executive_summary'];
$fields = match ($gate) {
'property_review' => ['real_estate.property_type', 'real_estate.land_area', 'real_estate.built_area', 'real_estate.area_unit', 'real_estate.units', 'real_estate.occupancy_status', 'real_estate.price', 'real_estate.rent', 'real_estate.rent_periodicity', 'real_estate.valuation', 'real_estate.utilities'],
'registry_urban_review' => ['real_estate.transaction_type', 'real_estate.title_type', 'real_estate.registration_number', 'real_estate.encumbrances', 'real_estate.land_area', 'real_estate.area_unit'],
'building_compliance_review' => ['real_estate.construction_status', 'real_estate.property_condition', 'real_estate.built_area', 'real_estate.floors', 'real_estate.planning_permit_document_id', 'real_estate.use_license_document_id'],
'cadastral_screening' => ['land_rights.parcels', 'land_rights.overlaps_conflicts'],
'land_legal_review' => ['land_rights.operation_type', 'land_rights.duat_status', 'land_rights.duat_number', 'land_rights.holder_id', 'land_rights.holder_name', 'land_rights.issuing_authority_id', 'land_rights.issue_date', 'land_rights.expiry_date', 'land_rights.authorized_purpose', 'land_rights.improvements', 'land_rights.consideration'],
'community_environment_review' => ['land_rights.communities', 'land_rights.community_consultation', 'environmental_social'],
'competent_authority_clearance' => ['land_rights.required_authorizations', 'land_rights.exploitation_plan_document_id', 'land_rights.authorized_purpose'],
'corporate_screening' => ['business_transaction.legal_entity_id', 'business_transaction.legal_form', 'business_transaction.beneficial_owners', 'business_transaction.percentage_offered'],
'financial_review' => ['business_transaction.asking_price', 'business_transaction.valuation', 'business_transaction.financial_periods', 'business_transaction.assets_liabilities', 'business_transaction.employees', 'business_transaction.partner_contribution'],
'legal_tax_due_diligence' => ['business_transaction.transaction_type', 'business_transaction.percentage_offered', 'business_transaction.contracts_licenses', 'business_transaction.litigation_contingencies', 'business_transaction.governance_rights', 'business_transaction.franchise_terms', 'business_transaction.tax_labor_compliance'],
'partnership_governance_review' => ['business_transaction.percentage_offered', 'business_transaction.partner_contribution', 'business_transaction.governance_rights'],
'brand_license_review' => ['business_transaction.franchise_terms', 'business_transaction.contracts_licenses'],
'franchise_legal_review' => ['business_transaction.franchise_terms', 'business_transaction.contracts_licenses', 'business_transaction.litigation_contingencies'],
'confidentiality_clearance' => ['visibility', 'publish_contact', 'public_contact_id', 'business_transaction.confidentiality_level', 'business_transaction.teaser', 'business_transaction.nda_document_id', 'business_transaction.data_room_index_document_id'],
'technical_review' => ['demand_statement', 'opportunity_type', 'maturity_stage', 'investment_modalities', 'investor_profiles', 'products', 'assets', 'inputs', 'markets', 'competitive_advantage', 'employment', 'impact_indicators', 'total_investment', 'currency', 'investment_breakdown', 'secured_financing', 'funding_sought', 'financial_indicators', 'milestones', 'risks'],
'legal_territorial_review' => ['licenses', 'environmental_social', 'relations', 'truth_declaration'],
// Experimental modules have no approved scope contract: never carry their decisions.
default => array_keys($p),
};
if ($extended) {
$fields = [...$fields, ...match ($gate) {
'land_legal_review' => ['land_rights.holder_document_id', 'land_rights.area_unit'],
'community_environment_review' => ['land_rights.communities_affected'],
'competent_authority_clearance' => ['land_rights.exploitation_plan_required'],
'corporate_screening' => ['business_transaction.entity_registration'],
'financial_review' => ['business_transaction.available_financial_years', 'business_transaction.history_status', 'business_transaction.history_declaration', 'business_transaction.history_declaration_document_id', 'business_transaction.projections'],
'franchise_legal_review' => ['business_transaction.legal_entity_id', 'business_transaction.legal_form', 'business_transaction.beneficial_owners', 'business_transaction.entity_registration', 'business_transaction.governance_rights', 'business_transaction.tax_labor_compliance'],
'confidentiality_clearance' => ['internal_contact_id'],
default => [],
}];
}
$data = [];
foreach ([...$common, ...$fields] as $field) {
if (! is_string($field)) {
throw new \UnexpectedValueException('Canonical review fields must be named fields.');
}
$data[$field] = Arr::get($p, $field);
}
// Explicitly unclassified specialised fields conservatively reopen reviews.
// They cannot silently become immaterial when a schema gains a new field.
$classified = match ($p['opportunity_category'] ?? '') {
'real_estate' => ['transaction_type', 'property_type', 'construction_status', 'property_condition', 'land_area', 'built_area', 'area_unit', 'units', 'rooms', 'floors', 'amenities', 'utilities', 'occupancy_status', 'title_type', 'registration_number', 'encumbrances', 'price', 'rent', 'rent_periodicity', 'deposit', 'valuation', 'viewing', 'planning_permit_document_id', 'use_license_document_id', 'title_document_id', 'title_holder_name', 'issuing_authority_id', 'expected_completion_date', 'occupancy_details', 'occupancy_document_id', 'amenities_other', 'urban_limit_document_id', 'max_built_area'],
default => [],
};
if ($classified !== []) {
$data['unclassified_module_fields'] = array_diff_key($p['real_estate'] ?? [], array_flip($classified));
}
if ($gate === 'property_review') {
foreach (['rooms', 'amenities', 'deposit', 'occupancy_details', 'occupancy_document_id', 'amenities_other'] as $key) {
$data['real_estate.'.$key] = Arr::get($p, 'real_estate.'.$key);
}
}
if ($gate === 'registry_urban_review') {
foreach (['title_document_id', 'title_holder_name', 'issuing_authority_id', 'urban_limit_document_id', 'max_built_area'] as $key) {
$data['real_estate.'.$key] = Arr::get($p, 'real_estate.'.$key);
}
}
if ($gate === 'building_compliance_review') {
$data['real_estate.expected_completion_date'] = Arr::get($p, 'real_estate.expected_completion_date');
}
// A changed evidence file always invalidates a decision relying on it.
// Unrelated documents/images and editorial timestamps are not review evidence.
return $data;
}
/** @param array<string,mixed> $snapshot
* @param array<string,mixed> $review */
public function hash(array $snapshot, string $gate, array $review = [], bool $legacy = false, ?string $rule = null): string
{
$extended = ! $legacy && ($rule ?? self::VERSION) !== self::PREVIOUS_VERSION;
$data = $this->scope($snapshot, $gate, $extended);
$locationGates = ['registry_urban_review', 'cadastral_screening', 'legal_territorial_review', 'property_review'];
if (! $legacy) {
$locationGates = [...$locationGates, 'land_legal_review', 'community_environment_review', 'competent_authority_clearance'];
}
if (in_array($gate, $locationGates, true)) {
$data['locations'] = array_map(fn ($r) => $r['payload'], $snapshot['resources']['locations'] ?? []);
}
foreach ($review['evidence_document_ids'] ?? [] as $id) {
$r = $snapshot['resources']['documents'][$id] ?? null;
$data['evidence'][$id] = $r ? ['sha256' => $r['sha256'] ?? null, 'payload' => $r['payload'] ?? [], 'deleted_at' => $r['deleted_at'] ?? null] : null;
}
if ($extended) {
// Nested references are part of the decision even when the reviewer
// selected a different supporting file. Preserve the original bytes.
$referenced = function (array $node) use (&$referenced, &$data, $snapshot): void {
foreach ($node as $key => $value) {
if (is_array($value)) {
$referenced($value);
} elseif (is_string($key) && is_string($value) && $value !== '' && (str_ends_with($key, 'document_id') || $key === 'image_id')) {
$kind = $key === 'image_id' ? 'images' : 'documents';
$resource = $snapshot['resources'][$kind][$value] ?? null;
$data['referenced_resources'][$kind][$value] = $resource ? ['sha256' => $resource['sha256'] ?? null, 'payload' => $resource['payload'] ?? [], 'deleted_at' => $resource['deleted_at'] ?? null] : null;
}
}
};
$referenced($data);
}
return $legacy ? hash('sha256', json_encode(Arr::sortRecursive($data), JSON_THROW_ON_ERROR)) : OpportunityCanonicalValue::hash($data);
}
/** @param array<string,mixed> $snapshot
* @param array<string,mixed> $review */
public function matches(array $snapshot, string $gate, array $review): bool
{
if (! isset($review['scope_hash'])) {
return true; // Caller must independently verify the original signed submission hash.
}
$rule = $review['scope_rule'] ?? '';
$legacy = ! in_array($rule, [self::VERSION, self::PREVIOUS_VERSION], true);
$expected = $this->hash($snapshot, $gate, $review, $legacy, $rule);
return hash_equals($review['scope_hash'], $expected);
}
/** @param array<string,mixed> $before
* @param array<string,mixed> $after
* @param array<string,mixed> $reviews
* @param list<string> $gates
* @return array<string,mixed> */
public function reconcile(array $before, array $after, array $reviews, array $gates, bool $force = false): array
{
$kept = [];
$reopened = [];
foreach ($gates as $gate) {
$review = $reviews[$gate] ?? [];
// Compare the signed baseline and new content with the new scope;
// separately validate old scope signatures under their original rule.
$priorHash = $this->hash($before, $gate, $review);
$currentHash = $this->hash($after, $gate, $review);
if (! $force && $before !== [] && ($review['decision'] ?? '') === 'approved' && $this->matches($before, $gate, $review) && hash_equals($priorHash, $currentHash)) {
$kept[$gate] = [...$review, 'scope_hash' => $priorHash, 'scope_rule' => self::VERSION, 'accepted_submission_hash' => $after['hash'],
'carried_forward' => ['rule' => self::VERSION, 'from_scope_hash' => $review['scope_hash'] ?? null, 'from_scope_rule' => $review['scope_rule'] ?? 'legacy_unspecified', 'from_submission_hash' => $before['hash'] ?? null, 'at' => now()->toIso8601String()]];
} else {
$reopened[] = $gate;
}
}
return ['rule' => self::VERSION, 'reviews' => $kept, 'reopened' => $reopened, 'retained' => array_keys($kept),
'reason' => $force ? 'Suspensão, rejeição ou recurso exige nova decisão; motivo anterior preservado.' : 'Comparação dos campos e evidências aplicáveis a cada revisão (§28.1).',
'final_approval' => 'Nova assinatura independente da versão; nenhum parecer ou decisão externa inventado.'];
}
}
+13 -1
View File
@@ -13,6 +13,9 @@ class OpportunityWorkflowTasks
public function ensure(Opportunity $record, string $kind, string $title): string
{
$key = 'portal-opportunity:'.$record->id.':'.$kind.':'.($record->workflow_context['content_revision'] ?? 1);
if (isset($record->workflow_context['review_cycle'])) {
$key .= ':cycle:'.$record->workflow_context['review_cycle'];
}
$existing = DB::table('tasks')->where('source_system', 'opportunity-workflow')->where('external_id', $key)->first();
if ($existing) {
return $existing->id;
@@ -32,11 +35,20 @@ class OpportunityWorkflowTasks
DB::table('tasks')->where('id', $taskId)->update(['assignee_user_id' => $subject->id, 'status' => 'in_progress', 'version_no' => DB::raw('version_no+1')]);
}
public function closedReviewBinding(Opportunity $record, ?string $id): bool
{
return $id !== null && DB::table('tasks')->where('id', $id)->where('source_system', 'opportunity-workflow')
->where('external_id', 'like', 'portal-opportunity:'.$record->id.':opportunity_review:%')->where('status', 'done')->exists();
}
public function complete(?string $taskId, string $outcome): void
{
if ($taskId) {
// Existing CRM outcome is a varchar(80) summary. The full reason is
// retained in the versioned workflow decision and its audit event.
$summary = mb_strlen($outcome) > 80 ? mb_substr($outcome, 0, 79).'…' : $outcome;
DB::table('tasks')->where('id', $taskId)->where('source_system', 'opportunity-workflow')->whereIn('status', ['open', 'in_progress'])
->update(['status' => 'done', 'outcome' => $outcome, 'completed_at' => now(), 'version_no' => DB::raw('version_no+1')]);
->update(['status' => 'done', 'outcome' => $summary, 'completed_at' => now(), 'version_no' => DB::raw('version_no+1')]);
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
/** Country of constitution in the existing identity master, with explicit provenance. */
class OrganizationCountry
{
public function available(): bool
{
return config('portal.organization_country_enabled', false)
&& Schema::hasColumns('organizations', ['incorporation_country_code', 'incorporation_country_provenance']);
}
/** @return list<array<string, mixed>> */
public function represented(User $actor): array
{
if (! $this->available()) {
return [];
}
$readOnly = app(PortalProfileAccess::class)->has($actor, 'auditor');
return array_values(DB::table('memberships as m')->join('organizations as o', 'o.id', '=', 'm.organization_id')
->where('m.user_id', $actor->id)->whereNull('m.deleted_at')->whereNull('o.deleted_at')
->get(['o.id', 'o.name', 'o.version_no', 'o.incorporation_country_code', 'o.incorporation_country_provenance', 'm.role'])
->unique('id')->map(fn ($o) => ['id' => $o->id, 'name' => $o->name, 'version' => $o->version_no,
'country' => $o->incorporation_country_code, 'provenance' => json_decode($o->incorporation_country_provenance ?? 'null', true),
'canEdit' => ! $readOnly && in_array($o->role, ['admin', 'manager', 'officer'], true)])->all());
}
public function authorize(User $actor, string $id, bool $write = false): void
{
abort_unless($this->available(), 409, 'Extensão do país de constituição ainda não instalada.');
abort_if($write && app(PortalProfileAccess::class)->has($actor, 'auditor'), 403, 'Auditor só consulta o cadastro mestre, mesmo com representação ou outros papéis.');
$roles = $write ? ['admin', 'manager', 'officer'] : ['admin', 'manager', 'officer', 'viewer'];
abort_unless(DB::table('memberships')->where('organization_id', $id)->where('user_id', $actor->id)
->whereNull('deleted_at')->whereIn('role', $roles)->exists()
&& DB::table('organizations')->where('id', $id)->whereNull('deleted_at')->exists(), 403, 'Representação da organização não autorizada.');
}
/** @param array<string, mixed> $data
* @return array{version:int, country:string} */
public function save(User $actor, string $id, array $data): array
{
$this->authorize($actor, $id, true);
$data = Validator::make($data, ['version' => 'required|integer|min:1',
'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.',
'source_reference.required' => 'Indique a fonte ou referência deste país.',
'source_reference.min' => 'A referência deve ter pelo menos cinco caracteres.',
])->validate();
return DB::transaction(function () use ($actor, $id, $data) {
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();
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,
'external_id' => $row->external_id, 'verification' => 'country_declared_not_independently_verified'];
DB::table('organizations')->where('id', $id)->update(['incorporation_country_code' => $data['country'],
'incorporation_country_provenance' => json_encode($provenance, JSON_THROW_ON_ERROR), 'version_no' => $row->version_no + 1]);
DB::table('audit_events')->insert(['source_system' => 'organization-country', 'entity_type' => 'organizations',
'actor_user_id' => $actor->id, 'action' => 'incorporation_country_saved', 'data_classification' => 'restricted',
'before_data' => json_encode(['organization_id' => $id, 'snapshot' => Crypt::encryptString(json_encode($row, JSON_THROW_ON_ERROR))]),
'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))])]);
return ['version' => $row->version_no + 1, 'country' => $data['country']];
});
}
/** @return array<string, mixed> */
public function snapshot(User $actor, string $id): array
{
$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.');
return ['organization_id' => $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];
}
}
@@ -0,0 +1,118 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
/** An explicit extension of the existing authenticated resource installer. */
class OrganizationCountryInstallation
{
public const MIGRATION = '2026_10_10_050000_extend_organization_country';
/** @return list<string> */
public function files(): array
{
return ['app/Services/OrganizationCountry.php', 'app/Services/OrganizationCountryInstallation.php', 'app/Providers/AppServiceProvider.php',
'app/Services/CountryCatalogue.php', 'app/Services/PortalProfileAccess.php', 'app/Services/PortalProfileInstallation.php',
'app/Http/Controllers/InvestmentWorkspaceController.php', 'app/Http/Controllers/InvestmentSubmissionController.php',
'app/Http/Controllers/OpportunityResourceController.php', 'app/Models/User.php', 'config/portal.php',
'routes/web.php', 'routes/investment.php', 'database/migrations/'.self::MIGRATION.'.php',
'resources/js/components/country-select.tsx', 'resources/js/pages/investment/profile.tsx',
'resources/js/pages/investment/submission.tsx', 'resources/js/pages/management/opportunity-install.tsx',
'resources/data/iso3166.tab', 'config/portal_profiles.php', 'composer.json', 'composer.lock'];
}
public function fingerprint(): string
{
return hash('sha256', json_encode(array_map(fn ($file) => [$file, hash_file('sha256', base_path($file))], $this->files()), JSON_THROW_ON_ERROR));
}
/** Separate bounded evidence: partial opportunity modules are not an installation dependency.
* @return array<string,mixed> */
public function evidence(object $identity): array
{
$path = storage_path('app/private/investmoz-v2/organization-country-installation/readiness.json');
$bytes = is_file($path) ? file_get_contents($path) : false;
$p = is_string($bytes) ? json_decode($bytes, true) : [];
$p = is_array($p) ? $p : [];
$target = get_object_vars($identity);
$ready = ($p['code_hash'] ?? '') === $this->fingerprint()
&& isset($target['database'], $target['port'])
&& ($p['target']['database'] ?? '') === $target['database'] && (int) ($p['target']['port'] ?? 0) === (int) $target['port']
&& strtotime($p['verified_at'] ?? '') >= time() - 86400
&& ($p['restore_verified'] ?? false) && ($p['files_verified'] ?? false) && ($p['qa_passed'] ?? false)
&& ($p['compatibility_verified'] ?? false) && ($p['reversal_verified'] ?? false)
&& is_file($p['dump_path'] ?? '') && hash_file('sha256', $p['dump_path']) === ($p['dump_sha256'] ?? '')
&& is_file($p['files_path'] ?? '') && hash_file('sha256', $p['files_path']) === ($p['files_sha256'] ?? '');
return ['ready' => $ready, 'backupDate' => $p['verified_at'] ?? null];
}
/** @return array<string, mixed> */
public function preview(User $actor): array
{
app(PortalProfileInstallation::class)->authorize($actor);
$identity = DB::selectOne('SELECT current_database() AS database, inet_server_port() AS port');
$evidence = $this->evidence($identity);
$columns = array_map(fn ($column) => Schema::hasColumn('organizations', $column), ['incorporation_country_code', 'incorporation_country_provenance']);
$ledger = DB::table('migrations')->where('migration', self::MIGRATION)->exists();
$installed = $ledger && ! in_array(false, $columns, true);
$consistent = ($ledger && ! in_array(false, $columns, true)) || (! $ledger && ! in_array(true, $columns, true));
$dependencies = array_reduce(['organizations', 'memberships', 'audit_events'], fn ($ok, $table) => $ok && Schema::hasTable($table), true);
$plan = ['migration' => self::MIGRATION, 'installed' => $installed, 'consistent' => $consistent, 'ready' => $consistent && $dependencies && $evidence['ready'],
'target' => $identity, 'code_hash' => $this->fingerprint(), 'backupDate' => $evidence['backupDate'],
'dependencies' => ['existing_organizations_memberships_audit' => $dependencies],
'changes' => ['Duas colunas opcionais no cadastro mestre organizations; zero tabelas, organizações, contas ou atribuições.',
'Preserva source_system, external_id, valores anteriores, versões e submissões; reutilização explícita, sem inferência por nome.',
'Ação independente de 030000, 040000 e 190000; não ativa flags, cálculos, publicação nem o percurso.'],
'rollback' => 'Desabilitar o consumidor mantém os dados. Não remover colunas com histórico; ensaiar a reversão de código e, se necessário, restauro no clone verificado.'];
$plan['hash'] = hash('sha256', json_encode($plan, JSON_THROW_ON_ERROR));
return $plan;
}
/** @param array<string, mixed> $input
* @return array<string, mixed> */
public function apply(User $actor, array $input): array
{
app(PortalProfileInstallation::class)->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();
return DB::transaction(function () use ($actor, $data) {
DB::select('SELECT pg_advisory_xact_lock(101026,50000)');
$requestHash = hash('sha256', json_encode($data, JSON_THROW_ON_ERROR));
$previous = DB::table('audit_events')->where('source_system', 'organization-country-installation')->where('actor_user_id', $actor->id)->where('correlation_id', $data['idempotency_key'])->first();
if ($previous) {
$receipt = json_decode($previous->after_data, true, 512, JSON_THROW_ON_ERROR);
abort_unless(hash_equals($receipt['request_hash'], $requestHash), 409, 'Chave de repetição reutilizada com outro conteúdo.');
return $receipt['result'];
}
$plan = $this->preview($actor);
abort_unless(hash_equals($plan['hash'], $data['hash']), 409, 'Plano alterado; consulte a pré-visualização.');
abort_unless($plan['consistent'], 409, 'Ledger/schema incoerentes. Recuperar antes de instalar.');
$changed = ! $plan['installed'];
if ($changed) {
abort_unless($plan['ready'], 422, 'Exige provas atuais da revisão, alvo, backup/restauro e compatibilidade.');
config(['organization_country.authenticated_installation' => true]);
try {
abort_unless(Artisan::call('migrate', ['--path' => 'database/migrations/'.self::MIGRATION.'.php', '--force' => true]) === 0, 500);
} finally {
config(['organization_country.authenticated_installation' => false]);
}
abort_unless($this->preview($actor)['installed'], 500, 'Verificação pós-instalação falhou.');
}
$result = ['installed' => true, 'changed' => $changed, 'migration' => self::MIGRATION, 'new_columns' => $changed ? 2 : 0, 'new_tables' => 0, 'new_organizations' => 0, 'flags_changed' => false];
DB::table('audit_events')->insert(['source_system' => 'organization-country-installation', 'entity_type' => 'installation', 'action' => 'install',
'actor_user_id' => $actor->id, 'correlation_id' => $data['idempotency_key'], 'data_classification' => 'restricted',
'after_data' => json_encode(['request_hash' => $requestHash, 'reason' => $data['reason'], 'result' => $result, 'code_hash' => $plan['code_hash']], JSON_THROW_ON_ERROR)]);
return $result;
});
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
/** Owner-directed staff assignments use existing identities, organizations and grants. */
class PortalInternalDesignation
{
public function organizations(): array
{
return DB::table('organizations')->whereIn(DB::raw('id::text'), DB::table('audit_events')->where('source_system','portal-profiles-v1')->where('action','operator_organization_registered')->selectRaw("after_data->>'organization_id'"))->whereNull('deleted_at')
->get(['id','name','external_id','version_no'])->map(fn($r)=>$this->organization($r->id))->filter()->values()->all();
}
public function organization(?string $id): ?array
{
if ($id===null) return null;
$r=DB::table('organizations')->where('id',$id)->whereNull('deleted_at')->first();
if (!$r) return null;
$event=DB::table('audit_events')->where('source_system','portal-profiles-v1')->where('action','operator_organization_registered')
->where('after_data->organization_id',$id)->orderByDesc('occurred_at')->first();
if (!$event) return null;
$data=json_decode($event->after_data,true,512,JSON_THROW_ON_ERROR);
if (($data['organization']['name'] ?? null)!==$r->name || ($data['organization']['nuit'] ?? null)!==$r->external_id) return null;
return ['id'=>$r->id,'version'=>$r->version_no,...$data['organization'],'source_reference'=>$data['source_reference']];
}
public function registerOrganization(User $actor,array $input): array
{
app(PortalProfileAdministration::class)->administrative($actor);
$v=Validator::make($input,['operation_key'=>'required|uuid','name'=>'required|string|max:200','nuit'=>'required|string|regex:/^[0-9]{9}$/',
'contact'=>'required|string|regex:/^\+258[0-9]{9}$/','director'=>'required|string|max:200',
'function'=>'required|in:portal_owner_operator','source_reference'=>'required|string|min:20|max:1000'])->validate();
return DB::transaction(function()use($actor,$v){
DB::select('SELECT pg_advisory_xact_lock(101026,40001)');
$payload=array_intersect_key($v,array_flip(['name','nuit','contact','director','function']));
$existingEvent=DB::table('audit_events')->where('source_system','portal-profiles-v1')->whereIn('action',['operator_organization_registered','operator_organization_registration_recovered'])->where('after_data->operation_key',$v['operation_key'])->first();
if($existingEvent){
$e=json_decode($existingEvent->after_data,true);
abort_unless($e['organization']==$payload && $e['source_reference']===$v['source_reference'],409,'Esta chave corresponde a outro cadastro.');
return ['id'=>$e['organization_id'],'organization'=>$this->organization($e['organization_id']),'message'=>'Cadastro recuperado; não repetido.'];
}
$names=array_unique([$v['name'],preg_replace('/\s*,\s*/',' ',$v['name'])]);
$matches=DB::table('organizations')->where(fn($q)=>$q->where('external_id',$v['nuit'])->orWhereIn('name',$names)->orWhere('name',str_replace(' Lda',', Lda',$v['name'])))->lockForUpdate()->get();
abort_if($matches->count()>1,409,'Correspondência ambígua no cadastro mestre; não criar duplicado.');
$r=$matches->first();
if($r){
abort_if($r->deleted_at!==null || ($r->external_id!==null && $r->external_id!==$v['nuit']),409,'Identidade ou estado da organização exige reconciliação.');
$known=$this->organization($r->id);
if($known){
abort_unless(array_intersect_key($known,$payload)==$payload,409,'Dados do cadastro já existente diferem; preservar a versão anterior.');
app(PortalProfileAccess::class)->audit($actor,'operator_organization_registration_recovered',['operation_key'=>$v['operation_key'],'organization_id'=>$r->id,'organization'=>$payload,'source_reference'=>$v['source_reference']]);
return ['id'=>$r->id,'organization'=>$known,'message'=>'Organização existente recuperada.'];
}
$id=$r->id;
$before=['name'=>$r->name,'external_id'=>$r->external_id,'source_system'=>$r->source_system,'version_no'=>$r->version_no];
abort_unless(in_array($r->name,$names,true) || $r->name===str_replace(' Lda',', Lda',$v['name']),409,'Denominação divergente exige reconciliação expressa.');
DB::table('organizations')->where('id',$id)->update(['name'=>$v['name'],'external_id'=>$v['nuit'],'updated_at'=>now(),'version_no'=>$r->version_no+1]);
// Reconcile only the explicit comma alias; preserve previous values in audit.
}else{
$id=(string)Str::uuid();
DB::table('organizations')->insert(['id'=>$id,'name'=>$v['name'],'external_id'=>$v['nuit'],'source_system'=>'portal-operator-master','organization_type'=>'private']);
}
app(PortalProfileAccess::class)->audit($actor,'operator_organization_registered',['operation_key'=>$v['operation_key'],'organization_id'=>$id,
'organization'=>$payload,'previous_master_values'=>$before??null,'source_reference'=>$v['source_reference'],'metadata_storage'=>'existing_audit_snapshot','no_corporate_membership_created'=>true]);
return ['id'=>$id,'organization'=>$this->organization($id),'message'=>'Organização operadora registada no cadastro mestre. Nenhuma representação ou papel foi atribuído.'];
});
}
public function grant(User $actor,array $input): string
{
app(PortalProfileAdministration::class)->administrative($actor);
$v=Validator::make($input,['operation_key'=>'required|uuid','user_id'=>'required|integer|exists:users,id','role'=>['required',Rule::in(['promoter','validator','publisher'])],
'operator_organization_id'=>'required|uuid|exists:organizations,id','organization_id'=>'nullable|uuid|exists:organizations,id',
'opportunity_types'=>'required|array|min:1','opportunity_types.*'=>['required',Rule::in(OpportunityCanonicalContract::BASE_CATEGORIES)],
'confirmed_internal_designation'=>'required|accepted','reason'=>'required|string|min:20|max:1000',
'responsibilities'=>'sometimes|array|max:0','expires_at'=>'nullable|date|after:now'])->validate();
abort_if((int)$v['user_id']===$actor->id,403,'Não pode aprovar a sua atribuição.');
$subject=User::findOrFail($v['user_id']);
abort_unless($subject->hasVerifiedEmail() && $subject->two_factor_secret!==null && $subject->two_factor_confirmed_at!==null,422,'Confirmar contacto e o próprio MFA antes da atribuição interna.');
$organization=$this->organization($v['operator_organization_id']);
abort_unless($organization!==null,422,'Selecione a organização operadora cadastrada; não exige comprovativos de Promotor externo.');
if($v['role']==='promoter')abort_unless(($v['organization_id']??null)===$v['operator_organization_id'],422,'O vínculo interno é à organização operadora, não uma representação de gestão empresarial.');
return DB::transaction(function()use($actor,$v){
DB::select('SELECT pg_advisory_xact_lock(101026,40002)');
$subject=User::whereKey($v['user_id'])->lockForUpdate()->firstOrFail();
abort_unless($subject->hasVerifiedEmail() && $subject->two_factor_secret!==null && $subject->two_factor_confirmed_at!==null && $this->organization($v['operator_organization_id'])!==null,422,'Conta ou organização já não reúne as condições da atribuição.');
$e=DB::table('audit_events')->where('source_system','portal-profiles-v1')->where('action','role_granted')->where('after_data->operation_key',$v['operation_key'])->first();
$payload=array_intersect_key($v,array_flip(['user_id','role','operator_organization_id','organization_id','opportunity_types','reason','expires_at']));
if($e){$d=json_decode($e->after_data,true);abort_unless($d['designation']==$payload,409,'Chave usada numa atribuição diferente.');abort_unless(DB::table('portal_role_assignments')->where('id',$d['assignment_id'])->whereNull('revoked_at')->exists(),409,'A atribuição foi revogada.');return $d['assignment_id'];}
$duplicate=DB::table('portal_role_assignments')->where('user_id',$v['user_id'])->where('role',$v['role'])->where('source','internal-portal-designation')->whereNull('revoked_at')->where('starts_at','<=',now())->where(fn($q)=>$q->whereNull('expires_at')->orWhere('expires_at','>',now()))->exists();
abort_if($duplicate,409,'Já existe atribuição interna ativa: recupere-a antes de repetir ou alterar.');
$id=(string)Str::uuid();
app(PortalProfileAdministration::class)->insertGrant($id,$actor,[...$v,'source'=>'internal-portal-designation']);
app(PortalProfileAccess::class)->audit($actor,'role_granted',['assignment_id'=>$id,'subject_user_id'=>$v['user_id'],'role'=>$v['role'],
'operation_key'=>$v['operation_key'],'designation'=>$payload,'operator_organization_id'=>$v['operator_organization_id'],
'reason'=>$v['reason'],'authority'=>'portal-owner-internal-designation','external_promoter_documents_required'=>false,'no_corporate_membership_created'=>true]);
return $id;
});
}
}
+128 -24
View File
@@ -16,19 +16,20 @@ class PortalProfileAccess
/** @return list<string> */
public static function fingerprintFiles(): array
{
return [__FILE__, app_path('Models/User.php'), app_path('Models/Opportunity.php'), config_path('portal.php'), base_path('routes/web.php'),
return [__FILE__, app_path('Services/OpportunityContacts.php'), resource_path('js/components/opportunity-contact-form.tsx'), app_path('Services/PortalInternalDesignation.php'), app_path('Models/User.php'), app_path('Models/Opportunity.php'), config_path('portal.php'), base_path('routes/web.php'),
app_path('Http/Middleware/HandleInertiaRequests.php'), app_path('Services/OpportunityManagement.php'),
app_path('Services/OpportunityResources.php'), app_path('Services/OpportunityImageProcessor.php'),
app_path('Services/OpportunityResources.php'), app_path('Services/OpportunityImageProcessor.php'), app_path('Services/VerifiedDocumentBinary.php'),
app_path('Services/PortalProfileAdministration.php'), app_path('Services/PortalSuperusers.php'),
app_path('Services/OpportunityProfileWorkflow.php'), app_path('Http/Controllers/PortalProfileController.php'), app_path('Http/Controllers/DashboardController.php'),
app_path('Http/Controllers/OpportunityManagementController.php'),
app_path('Services/OpportunityCanonicalContract.php'), app_path('Services/OpportunityCanonicalResponse.php'), app_path('Services/OpportunityCategoryFields.php'), app_path('Services/OpportunityModularProfiles.php'), app_path('Services/OpportunityWorkflowTasks.php'), base_path('composer.json'), base_path('composer.lock'),
app_path('Services/OpportunityReviewMateriality.php'), app_path('Services/OpportunityReviewConditions.php'), app_path('Services/OpportunityCanonicalMetadata.php'), app_path('Services/OpportunityCompleteness.php'), app_path('Services/OpportunityCanonicalValue.php'),
resource_path('data/investmoz-opportunity-modular.schema.json'), resource_path('js/components/opportunity-canonical-fields.tsx'), resource_path('js/components/opportunity-parcel-geometry.tsx'),
app_path('Http/Controllers/OpportunityResourceController.php'),
app_path('Http/Controllers/InvestmentTerritoryController.php'),
app_path('Http/Middleware/PortalProfileSession.php'), app_path('Http/Middleware/ProtectProfileOpportunity.php'),
app_path('Http/Middleware/ProtectPrivilegedIdentity.php'), app_path('Http/Middleware/EnsurePortalProfiles.php'),
app_path('Http/Middleware/AuditProfileDecision.php'), app_path('Providers/AppServiceProvider.php'),
app_path('Http/Middleware/AuditProfileDecision.php'), app_path('Http/Middleware/EnsurePortalProfileAdministration.php'), app_path('Providers/AppServiceProvider.php'),
database_path('migrations/2026_10_10_040000_create_portal_profile_authorization.php'), base_path('bootstrap/app.php'),
resource_path('js/pages/profiles/request.tsx'), resource_path('js/pages/profiles/administration.tsx'), resource_path('js/pages/profiles/audit.tsx'),
resource_path('js/components/profile-navigation.tsx'), resource_path('js/components/opportunity-profile-actions.tsx'),
@@ -45,7 +46,17 @@ class PortalProfileAccess
public function available(): bool
{
return config('portal.profile_access_enabled') && Schema::hasTable('portal_role_assignments')
return config('portal.profile_access_enabled') && $this->installed();
}
public function governanceAvailable(): bool
{
return (config('portal.profile_administration_enabled') || config('portal.profile_access_enabled')) && $this->installed();
}
public function installed(): bool
{
return Schema::hasTable('portal_role_assignments')
&& Schema::hasTable('portal_superuser_pair') && Schema::hasTable('portal_profile_requests')
&& Schema::hasTable('portal_security_approvals') && Schema::hasColumn('users', 'portal_access_revision')
&& Schema::hasColumn('opportunities', 'workflow_context') && Schema::hasColumn('opportunities', 'owner_user_id')
@@ -55,7 +66,7 @@ class PortalProfileAccess
/** @return list<\stdClass> */
public function grants(User $actor, ?string $role = null): array
{
if (! $this->available() || ! $actor->hasVerifiedEmail()) {
if (! $this->governanceAvailable() || ! $actor->hasVerifiedEmail()) {
return [];
}
@@ -70,7 +81,7 @@ class PortalProfileAccess
public function superuser(User $actor): bool
{
return $this->available() && $actor->hasVerifiedEmail() && DB::table('portal_superuser_pair')->where('id', 1)
return $this->governanceAvailable() && $actor->hasVerifiedEmail() && DB::table('portal_superuser_pair')->where('id', 1)
->where(fn ($q) => $q->where('first_user_id', $actor->id)->orWhere('second_user_id', $actor->id))->exists();
}
@@ -89,8 +100,46 @@ class PortalProfileAccess
&& (int) session('portal.mfa_at', 0) >= time() - 900;
}
public function internalAssignment(User $actor, string $type): ?\stdClass
{
foreach ($this->grants($actor, 'promoter') as $grant) {
if ($grant->source === 'internal-portal-designation'
&& in_array($type, json_decode($grant->opportunity_types, true), true)
&& app(PortalInternalDesignation::class)->organization($grant->organization_id) !== null) {
return $grant;
}
}
return null;
}
public function promoterRecordScope(User $actor, Opportunity $record): bool
{
foreach ($this->grants($actor, 'promoter') as $grant) {
if (! in_array($record->opportunity_category, json_decode($grant->opportunity_types, true), true)) {
continue;
}
if ($grant->source === 'internal-portal-designation') {
if (app(PortalInternalDesignation::class)->organization($grant->organization_id) !== null
&& ($record->workflow_context['operator_organization_id'] ?? null) === $grant->organization_id
&& ((int) $record->owner_user_id === $actor->id || in_array($actor->id, $record->workflow_context['contributors'] ?? [], true))) {
return true;
}
} elseif ($grant->organization_id === $record->organization_id && $this->represents($actor, $record->organization_id)
&& ($record->organization_id !== null || (int) $record->owner_user_id === $actor->id)) {
return true;
}
}
return false;
}
public function scoped(User $actor, string $role, ?string $organization, string $type): bool
{
if ($role === 'promoter' && $organization !== null && $this->internalAssignment($actor, $type) !== null
&& DB::table('organizations')->where('id', $organization)->whereNull('deleted_at')->exists()) {
return true;
}
foreach ($this->grants($actor, $role) as $grant) {
if (($grant->organization_id === $organization || ($role !== 'promoter' && $grant->organization_id === null))
&& in_array($type, json_decode($grant->opportunity_types, true, 512, JSON_THROW_ON_ERROR), true)) {
@@ -103,6 +152,9 @@ class PortalProfileAccess
public function operational(User $actor, string $action, ?int $recordId = null): bool
{
if (! $this->available()) {
return false;
}
if ($this->has($actor, 'auditor')) {
return false;
}
@@ -110,8 +162,13 @@ class PortalProfileAccess
return true;
}
if (! $this->mfa($actor)) {
return false;
}
return DB::table('portal_security_approvals')->where('kind', 'elevation')->where('subject_user_id', $actor->id)
->whereNotNull('approved_by')->whereNull('consumed_at')->where('expires_at', '>', now())
->whereNotNull('approved_by')->whereColumn('approved_by', '!=', 'subject_user_id')
->whereColumn('approved_by', '!=', 'requested_by')->whereNull('consumed_at')->where('expires_at', '>', now())
->whereExists(fn ($q) => $q->selectRaw('1')->from('portal_superuser_pair')
->where(fn ($holders) => $holders->whereColumn('first_user_id', 'portal_security_approvals.approved_by')->orWhereColumn('second_user_id', 'portal_security_approvals.approved_by')))
->where('scope->action', $action)->where('scope->record_id', $recordId)->exists();
@@ -119,7 +176,9 @@ class PortalProfileAccess
public function canCreate(User $actor, ?string $organization, string $type): bool
{
return $this->available() && $this->scoped($actor, 'promoter', $organization, $type) && $this->operational($actor, 'create');
$included = in_array($type, OpportunityCanonicalContract::BASE_CATEGORIES, true) || app(OpportunityModularProfiles::class)->enabled();
return $included && $this->available() && $this->scoped($actor, 'promoter', $organization, $type) && $this->operational($actor, 'create');
}
public function legacyWriteAllowed(User $actor): bool
@@ -138,22 +197,33 @@ class PortalProfileAccess
&& ! DB::table('portal_security_approvals')->where('kind', 'replacement')->whereNotNull('consumed_at')->where('scope->old_user_id', $actor->id)->exists();
}
/** Administration never grants operational access to a dossier or its attachments. */
public function hasOperationalReadScope(User $actor, Opportunity $record): bool
{
$personal = $record->organization_id !== null || (int) $record->owner_user_id === $actor->id;
return $this->promoterRecordScope($actor, $record)
|| $this->scoped($actor, 'validator', $record->organization_id, $record->opportunity_category)
|| $this->scoped($actor, 'publisher', $record->organization_id, $record->opportunity_category);
}
public function canView(User $actor, Opportunity $record): bool
{
if ($record->owner_user_id !== null && ! $this->available()) {
return false;
}
if ($this->superuser($actor)) {
return ! $this->has($actor, 'auditor') && $this->hasOperationalReadScope($actor, $record)
&& $this->operational($actor, 'view', $record->id);
}
if ($record->owner_user_id === null) {
return $actor->can('manage-portal');
}
if (! $this->available() || ! $actor->hasVerifiedEmail()) {
return false;
}
if ($this->has($actor, 'auditor') || $this->superuser($actor)) {
return true;
}
$personal = $record->organization_id !== null || (int) $record->owner_user_id === $actor->id;
return ($personal && $this->scoped($actor, 'promoter', $record->organization_id, $record->opportunity_category))
|| $this->scoped($actor, 'validator', $record->organization_id, $record->opportunity_category)
|| $this->scoped($actor, 'publisher', $record->organization_id, $record->opportunity_category);
return $this->has($actor, 'auditor') || $this->hasOperationalReadScope($actor, $record);
}
public function canEdit(User $actor, Opportunity $record, ?string $newType = null): bool
@@ -162,7 +232,7 @@ class PortalProfileAccess
return $this->legacyWriteAllowed($actor);
}
return $this->canView($actor, $record) && ! $record->trashed()
return $this->canView($actor, $record) && $this->promoterRecordScope($actor, $record) && ! $record->trashed()
&& in_array($this->state($record), ['draft', 'needs_information'], true)
&& $this->scoped($actor, 'promoter', $record->organization_id, $newType ?? $record->opportunity_category)
&& $this->operational($actor, 'edit', $record->id);
@@ -197,22 +267,38 @@ class PortalProfileAccess
*/
public function scope(Builder $query, User $actor): Builder
{
if ($this->has($actor, 'auditor') || $this->superuser($actor)) {
if ($this->has($actor, 'auditor') && ! $this->superuser($actor)) {
return $query;
}
if ($this->superuser($actor)) {
$ids = DB::table('portal_security_approvals')->where('kind', 'elevation')->where('subject_user_id', $actor->id)
->where('scope->action', 'view')->whereNotNull('approved_by')->whereNull('consumed_at')->where('expires_at', '>', now())
->get()->filter(fn ($row) => $this->operational($actor, 'view', json_decode($row->scope, true)['record_id'] ?? null))
->map(fn ($row) => json_decode($row->scope, true)['record_id'])->all();
$query->whereIn('id', $ids);
}
return $query->where(function ($scope) use ($actor) {
$scope->whereRaw('1=0');
if ($actor->can('manage-portal')) {
if ($actor->can('manage-portal') && ! $this->superuser($actor)) {
$scope->orWhereNull('owner_user_id');
}
foreach ($this->grants($actor) as $grant) {
if ($grant->role === 'promoter' && ! $this->represents($actor, $grant->organization_id)) {
if (! in_array($grant->role, ['promoter', 'validator', 'publisher'], true)) {
continue;
}
if ($grant->role === 'promoter' && $grant->source !== 'internal-portal-designation' && ! $this->represents($actor, $grant->organization_id)) {
continue;
}
if ($grant->role === 'promoter' && $grant->source === 'internal-portal-designation' && app(PortalInternalDesignation::class)->organization($grant->organization_id) === null) {
continue;
}
$scope->orWhere(function ($allowed) use ($actor, $grant) {
$allowed->whereNotNull('owner_user_id')->whereIn('opportunity_category', json_decode($grant->opportunity_types, true, 512, JSON_THROW_ON_ERROR));
if ($grant->organization_id !== null) {
if ($grant->role === 'promoter' && $grant->source === 'internal-portal-designation') {
$allowed->where(fn ($q) => $q->where('owner_user_id', $actor->id)->orWhereJsonContains('workflow_context->contributors', $actor->id))
->where('workflow_context->operator_organization_id', $grant->organization_id);
} elseif ($grant->organization_id !== null) {
$allowed->where('organization_id', $grant->organization_id);
} elseif ($grant->role === 'promoter') {
$allowed->whereNull('organization_id')->where('owner_user_id', $actor->id);
@@ -225,23 +311,41 @@ class PortalProfileAccess
/** @return array<string,mixed>|null */
public function navigation(?User $actor): ?array
{
if (! $actor || ! $this->available() || ! $actor->hasVerifiedEmail()) {
if (! $actor || ! $this->governanceAvailable() || ! $actor->hasVerifiedEmail()) {
return null;
}
$contexts = [];
$seen = [];
$internalPromoter = false;
foreach ($this->grants($actor, 'promoter') as $grant) {
if ($grant->source === 'internal-portal-designation' && app(PortalInternalDesignation::class)->organization($grant->organization_id) !== null) {
$internalPromoter = true;
foreach (DB::table('organizations')->whereNull('deleted_at')->get(['id', 'name']) as $realPromoter) {
foreach (json_decode($grant->opportunity_types, true) as $type) {
$key = $realPromoter->id.'|'.$type;
if (! isset($seen[$key]) && $this->canCreate($actor, $realPromoter->id, $type)) {
$contexts[] = ['organization_id' => $realPromoter->id, 'organization_name' => $realPromoter->name, 'type' => $type];
$seen[$key] = true;
}
}
}
continue;
}
if (! $this->represents($actor, $grant->organization_id)) {
continue;
}
foreach (json_decode($grant->opportunity_types, true, 512, JSON_THROW_ON_ERROR) as $type) {
if ($this->canCreate($actor, $grant->organization_id, $type)) {
$key = ($grant->organization_id ?? 'individual').'|'.$type;
if (! isset($seen[$key]) && $this->canCreate($actor, $grant->organization_id, $type)) {
$contexts[] = ['organization_id' => $grant->organization_id, 'type' => $type];
$seen[$key] = true;
}
}
}
return ['contexts' => $contexts, 'mine' => $contexts ? '/minhas-oportunidades' : null, 'create' => $contexts ? '/minhas-oportunidades/create' : null,
'request' => '/perfil/promotor', 'review' => $this->has($actor, 'validator') || $this->has($actor, 'publisher') || $this->has($actor, 'auditor') || $this->superuser($actor) ? '/minhas-oportunidades' : null,
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,
'audit' => $this->has($actor, 'auditor') || $this->superuser($actor) ? '/perfis/auditoria' : null, 'administration' => $this->superuser($actor) ? '/perfis/gestao' : null];
}
+4 -1
View File
@@ -22,6 +22,9 @@ class PortalProfileAdministration
public function grant(User $actor, array $input): string
{
$this->administrative($actor);
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'])],
'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'])],
@@ -77,7 +80,7 @@ class PortalProfileAdministration
/** @param array<string,mixed> $input */
public function request(User $actor, array $input): string
{
abort_unless($this->access->available() && $actor->hasVerifiedEmail(), 403);
abort_unless($this->access->governanceAvailable() && $actor->hasVerifiedEmail(), 403);
$data = Validator::make($input, ['creation_key' => 'required|uuid', 'representation_type' => 'required|in:individual,company,public_entity,association,partner',
'organization_id' => 'nullable|uuid|exists:organizations,id', 'opportunity_types' => 'required|array|min:1', 'opportunity_types.*' => ['required', Rule::in(OpportunityManagement::CATEGORIES)],
'document_ids' => 'required|array|min:1', 'document_ids.*' => 'required|uuid|exists:documents,id', 'reason' => 'required|string|min:20|max:1000'])->validate();
+62 -8
View File
@@ -20,7 +20,7 @@ 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')];
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));
}
@@ -78,7 +78,10 @@ class PortalProfileInstallation
$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,
'rule' => 'Escolher explicitamente duas contas confirmadas com MFA; um terceiro gestor com MFA aprova. Sem escolha automática, sem alteração de papéis legados.'];
'rule' => 'O primeiro titular apresenta o pedido com MFA e autorização de instalação; o segundo confirma numa operação separada com MFA. Sem autoaprovação, terceira pessoa obrigatória ou escolha automática.'];
$pending = $installed && ! $pair ? DB::table('portal_security_approvals')->where('kind', 'bootstrap')->whereNull('consumed_at')->where('expires_at', '>', now())
->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,
'path_190000_installed' => DB::table('migrations')->where('migration', '2026_10_09_190000_prepare_investor_path')->exists(),
@@ -120,24 +123,75 @@ class PortalProfileInstallation
/** @param array<string,mixed> $input
* @return array<string,mixed> */
public function bootstrap(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',
'first_user_id' => 'required|integer|exists:users,id', 'second_user_id' => 'required|integer|different:first_user_id|exists:users,id', 'reason' => 'required|string|min:20|max:1000'])->validate();
return $this->receipt($actor, 'bootstrap', $data, function () use ($actor, $data) {
abort_unless((int) $data['first_user_id'] === $actor->id, 403, 'O primeiro titular deve apresentar o seu próprio pedido; não é permitido inicializar terceiros.');
return $this->receipt($actor, 'bootstrap-request', $data, function () use ($actor, $data) {
$p = $this->preview($actor);
abort_unless(hash_equals($p['hash'], $data['hash']), 409, 'Plano alterado.');
abort_unless($p['installed'] && ! $p['bootstrap']['initialized'], 409, 'Inicialização exige schema instalado e dupla ainda não designada. Use substituição para uma dupla existente.');
abort_unless($p['installed'] && $p['consistent'] && ! in_array(false, $p['dependencies'], true) && ! $p['bootstrap']['initialized'], 409, 'Schema consistente instalado e dupla não inicializada necessários.');
$second = User::findOrFail($data['second_user_id']);
foreach ([$actor, $second] as $user) app(PortalSuperusers::class)->validateBootstrapHolder($user);
abort_if(DB::table('portal_security_approvals')->where('kind', 'bootstrap')->whereNull('consumed_at')->where('expires_at', '>', now())->exists(), 409, 'Já existe pedido pendente. Recupere-o; não duplique a cerimónia.');
$id = (string) \Illuminate\Support\Str::uuid();
DB::table('portal_security_approvals')->insert(['id' => $id, 'kind' => 'bootstrap', 'requested_by' => $actor->id, 'subject_user_id' => $second->id,
'scope' => json_encode(['first_user_id' => $actor->id, 'second_user_id' => $second->id, 'code_hash' => $this->fingerprint(),
'target' => $p['target'], 'preview_hash' => $p['hash']], JSON_THROW_ON_ERROR), 'reason' => $data['reason'],
'expires_at' => now()->addMinutes(15), 'created_at' => now(), 'updated_at' => now()]);
return ['initialized' => false, 'pending' => true, 'approval_id' => $id, 'confirmation_url' => '/management/profile-install/bootstrap/'.$id,
'holders' => [$actor->id, $second->id], 'expires_in_seconds' => 900, 'flags_changed' => false, 'privileges_granted' => false];
});
}
/** Purpose-specific view; designation grants no general management access. */
public function bootstrapPreview(User $actor, string $id): array
{
abort_unless($actor->hasVerifiedEmail(), 403);
$row = DB::table('portal_security_approvals')->where('id', $id)->where('kind', 'bootstrap')->first();
abort_unless($row, 404);
abort_unless(in_array($actor->id, [(int) $row->requested_by, (int) $row->subject_user_id], true), 403, 'Apenas os dois titulares designados consultam este pedido.');
app(PortalSuperusers::class)->validateBootstrapHolder($actor);
$scope = json_decode($row->scope, true, 512, JSON_THROW_ON_ERROR);
$identity = DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port');
$current = $scope['code_hash'] === $this->fingerprint() && $scope['target']['database'] === $identity->database && (int) $scope['target']['port'] === (int) $identity->port;
$view = ['approval_id' => $id, 'requested_by' => (int) $row->requested_by, 'second_user_id' => (int) $row->subject_user_id,
'reason' => $row->reason, 'expires_at' => $row->expires_at, 'consumed' => $row->consumed_at !== null, 'code_current' => $current,
'expired' => strtotime($row->expires_at) <= time(), 'target' => $identity,
'can_confirm' => $actor->id === (int) $row->subject_user_id && $row->consumed_at === null && strtotime($row->expires_at) > time() && $current,
'mfa_confirmed_in_session' => $this->access->mfa($actor)];
$view['hash'] = hash('sha256', json_encode([$id, $row->requested_by, $row->subject_user_id, $row->scope, $row->reason, $row->expires_at], JSON_THROW_ON_ERROR));
return $view;
}
public function confirmBootstrap(User $actor, string $id, array $input): array
{
$view = $this->bootstrapPreview($actor, $id);
abort_unless($actor->id === $view['second_user_id'] && $actor->id !== $view['requested_by'], 403, 'O pedido não pode ser autoaprovado.');
abort_unless($this->access->mfa($actor), 403, 'Conclua MFA nesta sessão.');
$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['approval_id'] = $id;
return $this->receipt($actor, 'bootstrap-confirm', $data, function () use ($actor, $id, $data) {
$row = DB::table('portal_security_approvals')->where('id', $id)->lockForUpdate()->first();
$view = $this->bootstrapPreview($actor, $id);
abort_unless(hash_equals($view['hash'], $data['hash']), 409, 'Pedido alterado; consulte novamente.');
abort_unless($view['can_confirm'], 409, 'Pedido expirado, já consumido ou revisão/destino alterados.');
$first = User::findOrFail($row->requested_by);
$this->authorize($first);
$p = $this->preview($first);
abort_unless($p['installed'] && $p['consistent'] && ! in_array(false, $p['dependencies'], true) && ! $p['bootstrap']['initialized'], 409, 'Dependências ou dupla alteradas.');
app(PortalSuperusers::class)->validateBootstrapHolder($first);
DB::table('portal_security_approvals')->where('id', $id)->update(['approved_by' => $actor->id, 'updated_at' => now()]);
config(['portal_profiles.bootstrap_authorized' => true]);
try {
app(PortalSuperusers::class)->initialize(User::query()->whereKey($data['first_user_id'])->firstOrFail(), User::query()->whereKey($data['second_user_id'])->firstOrFail(), $actor);
app(PortalSuperusers::class)->initialize($first, $actor, $actor, $id);
} finally {
config(['portal_profiles.bootstrap_authorized' => false]);
}
return ['initialized' => true, 'holders' => [$data['first_user_id'], $data['second_user_id']], 'version' => 1, 'flags_changed' => false];
return ['initialized' => true, 'approval_id' => $id, 'holders' => [$first->id, $actor->id], 'version' => 1, 'flags_changed' => false];
});
}
+48 -26
View File
@@ -4,41 +4,58 @@ namespace App\Services;
use App\Models\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;
class PortalSuperusers
{
public function __construct(private PortalProfileAccess $access, private PortalProfileAdministration $administration) {}
public function initialize(User $first, User $second, User $approver): void
private function mfaSecret(User $user): string
{
// Bootstrap requires a separately authorized ceremony; never infer real holders.
abort_unless(config('portal_profiles.bootstrap_authorized') === true, 403);
abort_unless(count(array_unique([$first->id, $second->id, $approver->id])) === 3, 422);
foreach ([$first, $second, $approver] as $user) {
abort_unless($user->hasVerifiedEmail() && $user->two_factor_secret && $user->two_factor_confirmed_at, 422, 'Contas confirmadas com MFA necessário.');
try {
$secret = Crypt::decryptString($user->two_factor_secret);
} catch (DecryptException) {
abort(422, 'Configuração MFA incompatível com este ambiente. Recuperar a conta pelo procedimento existente antes da inicialização.');
}
abort_unless(strlen($secret) >= 16 && preg_match('/^[A-Z2-7]+=*$/', $secret), 422, 'Configuração MFA inválida.');
abort_if(DB::table('portal_role_assignments')->where('user_id', $user->id)->where('role', 'auditor')->whereNull('revoked_at')
->where('starts_at', '<=', now())->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))->exists(), 422, 'A restrição do Auditor impede a designação de titular nesta cerimónia.');
// Normal Fortify enrollment serializes the string; older QA fixtures used encryptString.
// Read either existing envelope without re-encryption, unserializing objects or changing keys.
$plain = Fortify::currentEncrypter()->decrypt($user->two_factor_secret, false);
abort_unless(is_string($plain), 422, 'Configuração MFA inválida.');
if (preg_match('/^s:[0-9]+:"([A-Z2-7]+=*)";$/D', $plain, $matches)
&& serialize($matches[1]) === $plain) {
return $matches[1];
}
abort_unless($this->access->mfa($approver), 403);
DB::transaction(function () use ($first, $second, $approver) {
DB::select('SELECT pg_advisory_xact_lock(101026, 40001)');
$existing = DB::table('portal_superuser_pair')->where('id', 1)->first();
if ($existing) {
abort_unless((int) $existing->first_user_id === $first->id && (int) $existing->second_user_id === $second->id, 409, 'Inicialização já realizada. Use substituição atómica.');
return;
}
DB::table('portal_superuser_pair')->insert(['id' => 1, 'first_user_id' => $first->id, 'second_user_id' => $second->id, 'approved_by' => $approver->id, 'created_at' => now(), 'updated_at' => now()]);
$this->access->audit($approver, 'superuser_pair_initialized', ['holders' => [$first->id, $second->id], 'version' => 1]);
return $plain;
}
public function validateBootstrapHolder(User $user): void
{
abort_unless($user->hasVerifiedEmail() && $user->two_factor_secret && $user->two_factor_confirmed_at, 422, 'Conta confirmada com MFA necessário.');
try {
$secret = $this->mfaSecret($user);
} catch (DecryptException) {
abort(422, 'Configuração MFA incompatível com este ambiente. Recuperar pelo procedimento existente.');
}
abort_unless(strlen($secret) >= 16 && preg_match('/^[A-Z2-7]+=*$/', $secret), 422, 'Configuração MFA inválida.');
abort_if(DB::table('portal_role_assignments')->where('user_id', $user->id)->where('role', 'auditor')->whereNull('revoked_at')
->where('starts_at', '<=', now())->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))->exists(), 422, 'A restrição do Auditor impede a designação nesta cerimónia.');
}
public function initialize(User $first, User $second, User $confirmer, string $approvalId): void
{
abort_unless(config('portal_profiles.bootstrap_authorized') === true, 403);
abort_unless($first->id !== $second->id && $confirmer->id === $second->id, 403, 'Confirmação pelo segundo titular, distinta do pedido.');
foreach ([$first, $second] as $user) $this->validateBootstrapHolder($user);
abort_unless($this->access->mfa($confirmer), 403);
DB::transaction(function () use ($first, $second, $confirmer, $approvalId) {
DB::select('SELECT pg_advisory_xact_lock(101026, 40001)');
$approval = DB::table('portal_security_approvals')->where('id', $approvalId)->lockForUpdate()->first();
abort_unless($approval && $approval->kind === 'bootstrap' && (int) $approval->requested_by === $first->id
&& (int) $approval->subject_user_id === $second->id && (int) $approval->approved_by === $confirmer->id
&& $approval->consumed_at === null && strtotime($approval->expires_at) > time(), 409, 'Pedido cruzado inválido, expirado ou já consumido.');
abort_if(DB::table('portal_superuser_pair')->where('id', 1)->exists(), 409, 'Dupla existente; use substituição atómica.');
DB::table('portal_superuser_pair')->insert(['id' => 1, 'first_user_id' => $first->id, 'second_user_id' => $second->id, 'approved_by' => $confirmer->id, 'created_at' => now(), 'updated_at' => now()]);
DB::table('portal_security_approvals')->where('id', $approvalId)->update(['consumed_at' => now(), 'updated_at' => now()]);
$this->access->audit($confirmer, 'superuser_pair_initialized', ['approval_id' => $approvalId, 'requested_by' => $first->id, 'holders' => [$first->id, $second->id], 'version' => 1]);
});
}
@@ -69,6 +86,7 @@ class PortalSuperusers
DB::transaction(function () use ($actor, $id) {
$row = DB::table('portal_security_approvals')->where('id', $id)->lockForUpdate()->first();
abort_unless($row !== null, 404);
abort_unless(in_array($row->kind, ['replacement', 'elevation'], true), 403, 'Use a confirmação específica da inicialização cruzada.');
abort_if((int) $row->requested_by === $actor->id || (int) $row->subject_user_id === $actor->id, 403, 'Aprovação independente necessária.');
abort_unless($row->consumed_at === null && strtotime($row->expires_at) > time() && $row->approved_by === null, 409);
DB::table('portal_security_approvals')->where('id', $id)->update(['approved_by' => $actor->id, 'updated_at' => now()]);
@@ -103,7 +121,11 @@ class PortalSuperusers
public function requestElevation(User $actor, string $action, ?int $recordId, string $reason): string
{
$this->administration->administrative($actor);
abort_unless(in_array($action, ['create', 'edit', 'validate', 'publish', 'archive'], true) && mb_strlen($reason) >= 20 && mb_strlen($reason) <= 1000, 422);
abort_unless(in_array($action, ['view', 'create', 'edit', 'validate', 'publish', 'archive'], true) && mb_strlen($reason) >= 20 && mb_strlen($reason) <= 1000, 422);
if ($action === 'view') {
$record = $recordId === null ? null : \App\Models\Opportunity::find($recordId);
abort_unless($record && $this->access->hasOperationalReadScope($actor, $record) && ! $this->access->has($actor, 'auditor'), 403, 'A consulta exige perfil operacional com âmbito válido; a elevação não o substitui.');
}
$id = (string) Str::uuid();
DB::table('portal_security_approvals')->insert(['id' => $id, 'kind' => 'elevation', 'requested_by' => $actor->id, 'subject_user_id' => $actor->id,
'scope' => json_encode(['action' => $action, 'record_id' => $recordId], JSON_THROW_ON_ERROR), 'reason' => $reason,
+163
View File
@@ -0,0 +1,163 @@
<?php
namespace App\Services;
use Generator;
/** Read the accepted original one feature at a time, without changing its bytes. */
final class RetainedGeoJsonCollection
{
public function __construct(private readonly string $path) {}
/** @return array{type:mixed,feature_count:int,first_properties:array<string,mixed>,exceededTransferLimit:mixed} */
public function manifest(): array
{
$features = $this->features();
$count = 0;
$first = [];
foreach ($features as $feature) {
if ($count === 0) {
$first = $feature['properties'] ?? [];
}
$count++;
}
$metadata = $features->getReturn();
return ['type' => $metadata['type'] ?? null, 'feature_count' => $count, 'first_properties' => $first,
'exceededTransferLimit' => $metadata['exceededTransferLimit'] ?? false];
}
/** @return Generator<int,array<string,mixed>,mixed,array<string,mixed>> */
public function features(): Generator
{
$stream = fopen($this->path, 'rb');
abort_unless(is_resource($stream), 422, 'Exemplar privado indisponível.');
$buffer = '';
$position = 0;
$peek = static function () use ($stream, &$buffer, &$position): ?string {
if ($position === strlen($buffer)) {
$buffer = fread($stream, 65536);
$position = 0;
}
return $buffer !== '' ? $buffer[$position] : null;
};
$take = static function () use ($peek, &$position): ?string {
$char = $peek();
if ($char !== null) {
$position++;
}
return $char;
};
$white = static function () use ($peek, $take): void {
while (($c = $peek()) !== null && str_contains(" \t\r\n", $c)) {
$take();
}
};
$expect = static function (string $expected) use ($white, $take): void {
$white();
abort_unless($take() === $expected, 422, 'Estrutura JSON do exemplar inválida.');
};
$value = static function () use ($white, $peek, $take, &$buffer, &$position): string {
$white();
$first = $peek();
abort_unless($first !== null, 422, 'Exemplar JSON truncado.');
$structured = in_array($first, ['{', '[', '"'], true);
$result = $structured ? $take() : '';
$depth = $first === '"' ? 0 : 1;
$quoted = $first === '"';
$delimiters = $first === '{' ? '{}"' : ($first === '[' ? '[]"' : '"');
while (true) {
abort_unless($peek() !== null, 422, 'Exemplar JSON truncado.');
// Search whole numeric/coordinate spans in C; never loop through every byte in PHP.
$span = strcspn($buffer, $structured ? ($quoted ? '"\\' : $delimiters) : ",]} \t\r\n", $position);
$result .= substr($buffer, $position, $span);
$position += $span;
abort_if(strlen($result) > 4 * 1024 * 1024, 422, 'Elemento JSON excede o limite seguro de leitura.');
if ($position === strlen($buffer)) {
continue;
}
if (! $structured) {
break;
}
$c = $take();
$result .= $c;
if ($quoted) {
if ($c === '\\') {
$escaped = $take();
abort_unless($escaped !== null, 422, 'Exemplar JSON truncado.');
$result .= $escaped;
} elseif ($c === '"') {
$quoted = false;
}
} elseif ($c === '"') {
$quoted = true;
} elseif ($c === $first) {
$depth++;
} else {
$depth--;
}
if (! $quoted && $depth === 0) {
break;
}
}
abort_unless($result !== '', 422, 'Valor JSON ausente.');
return $result;
};
$decode = static function (string $bytes): mixed {
try {
return json_decode($bytes, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException) {
abort(422, 'JSON do exemplar inválido.');
}
};
try {
$expect('{');
$metadata = [];
$keys = [];
$index = 0;
$hadFeatures = false;
$white();
abort_if($peek() === '}', 422, 'Exemplar sem coleção de elementos.');
while (true) {
$key = $decode($value());
abort_unless(is_string($key) && ! isset($keys[$key]), 422, 'Chave JSON inválida ou repetida.');
$keys[$key] = true;
$expect(':');
if ($key === 'features') {
$hadFeatures = true;
$expect('[');
$white();
if ($peek() !== ']') {
while (true) {
$feature = $decode($value());
abort_unless(is_array($feature) && ($feature['type'] ?? null) === 'Feature', 422, 'Elemento geográfico inválido.');
yield $index++ => $feature;
unset($feature);
$white();
if ($peek() === ']') {
break;
}$expect(',');
}
}
$expect(']');
} else {
$metadata[$key] = $decode($value());
}
$white();
if ($peek() === '}') {
break;
}$expect(',');
}
$expect('}');
$white();
abort_unless($peek() === null && $hadFeatures,422,'Exemplar incompleto ou com conteúdo adicional.');
return $metadata;
} finally {
fclose($stream);
}
}
}
+11 -10
View File
@@ -13,7 +13,7 @@ class TerritoryGeometryImport
{
public function fingerprint(): string
{
return hash('sha256', implode('', array_map(fn ($f) => hash_file('sha256', $f), [__FILE__, config_path('geometry-import.php'), config_path('geometry-correspondences.php'), app_path('Http/Controllers/TerritoryGeometryImportController.php'), base_path('routes/web.php'), resource_path('js/pages/management/territory-geometry-import.tsx'),
return hash('sha256', implode('', array_map(fn ($f) => hash_file('sha256', $f), [__FILE__, app_path('Services/RetainedGeoJsonCollection.php'), config_path('geometry-import.php'), config_path('geometry-correspondences.php'), app_path('Http/Controllers/TerritoryGeometryImportController.php'), base_path('routes/web.php'), resource_path('js/pages/management/territory-geometry-import.tsx'),
base_path('bootstrap/app.php'), app_path('Providers/FortifyServiceProvider.php'), config_path('fortify.php'),
resource_path('js/pages/auth/login.tsx'), resource_path('js/pages/auth/two-factor-challenge.tsx')])));
}
@@ -52,19 +52,20 @@ class TerritoryGeometryImport
$text = $this->readFile($metadata);
abort_unless(str_contains($text, 'Mozambique INE - Instituto Nacional de Estatistica') && str_contains($text, '2019-06-07'), 422, 'Metadados do exemplar divergentes.');
$sourceHash = hash_file('sha256', $file);
$source = json_decode($this->readFile($file), true, 512, JSON_THROW_ON_ERROR);
abort_unless(($source['type'] ?? '') === 'FeatureCollection' && count($source['features'] ?? []) === [1 => 11, 2 => 159, 3 => 411][$level] && ! ($source['exceededTransferLimit'] ?? false), 422, 'Exemplar incompleto.');
$collection = new RetainedGeoJsonCollection($file);
$source = $collection->manifest();
abort_unless(($source['type'] ?? '') === 'FeatureCollection' && $source['feature_count'] === [1 => 11, 2 => 159, 3 => 411][$level] && ! ($source['exceededTransferLimit'] ?? false), 422, 'Exemplar incompleto.');
$locations = DB::table('geo_locations')->where('location_type', [1 => 'province', 2 => 'district', 3 => 'admin_post'][$level])->whereNull('deleted_at')->get(['id', 'name', 'parent_id', 'source_system', 'source_code', 'external_id']);
$crosswalk = config('geometry-correspondences');
$correspondences = $crosswalk['rows'][$level] ?? [];
abort_if($correspondences && (($crosswalk['edition'] ?? null) !== '2019-06-07' || ($crosswalk['source_sha256'][$level] ?? null) !== $sourceHash), 422, 'Correspondências não pertencem a este exemplar; nenhuma aproximação aplicada.');
$normalize = fn ($n) => strtolower(trim(Str::ascii($n)));
$countryNames = array_map($normalize, [$source['features'][0]['properties']['ADM0_PT'], $source['features'][0]['properties']['ADM0_EN']]);
$countryNames = array_map($normalize, [$source['first_properties']['ADM0_PT'], $source['first_properties']['ADM0_EN']]);
$countries = DB::table('geo_locations')->where('location_type', 'country')->whereNull('deleted_at')->get(['id', 'name'])->filter(fn ($c) => in_array($normalize($c->name), $countryNames, true))->values();
$countryId = count($countries) === 1 ? $countries[0]->id : null;
$parentSourceHash = $level > 1 ? hash_file('sha256', $directory.'/moz-adm'.($level - 1).'-ine-20190607.geojson') : null;
$rows = [];
foreach ($source['features'] as $feature) {
foreach ($collection->features() as $feature) {
$p = $feature['properties'];
abort_unless(($p['ADM0_PCODE'] ?? '') === 'MZ', 422, 'Âmbito territorial do exemplar divergente.');
$external = '2019-06-07:adm'.$level.':'.$p['ADM'.$level.'_PCODE'];
@@ -136,9 +137,9 @@ class TerritoryGeometryImport
abort_unless(hash_equals($plan['hash'], $data['hash']), 409, 'Correspondências, fonte ou estado alterados; repita a pré-visualização.');
abort_unless($plan['scan_ready'], 423, 'Scan limpo atual ligado ao original necessário.');
abort_if(count(array_filter($plan['rows'], fn ($r) => str_contains($r['status'], 'conflict') || $r['status'] === 'invalid_geometry')) > 0, 409, 'Conflito de identidade/geometria: nenhuma escrita aplicada.');
$bytes = $this->readFile(config('geometry-import.directory').'/moz-adm'.$data['level'].'-ine-20190607.geojson');
abort_unless(hash('sha256', $bytes) === $plan['source_sha256'], 409);
$source = json_decode($bytes, true, 512, JSON_THROW_ON_ERROR);
$sourcePath = config('geometry-import.directory').'/moz-adm'.$data['level'].'-ine-20190607.geojson';
abort_unless(hash_file('sha256', $sourcePath) === $plan['source_sha256'], 409);
$collection = new RetainedGeoJsonCollection($sourcePath);
$metadata = config('geometry-import.directory').'/moz-adm'.$data['level'].'-ine-metadata.html';
$metadataSize = filesize($metadata);
abort_unless(is_int($metadataSize), 422, 'Metadados indisponíveis durante a aplicação.');
@@ -149,14 +150,14 @@ class TerritoryGeometryImport
$batch = (string) Str::uuid();
$created = [];
$reused = [];
foreach ($plan['rows'] as $i => $row) {
foreach ($collection->features() as $i => $feature) {
$row = $plan['rows'][$i];
if ($row['status'] === 'reuse') {
$reused[] = $row['geometry_id'];
}
if ($row['status'] !== 'insert') {
continue;
}
$feature = $source['features'][$i];
$id = (string) Str::uuid();
$trace = ['authority' => 'Mozambique INE - Instituto Nacional de Estatistica', 'provider' => 'UNOCHA; exemplar hosted by World Bank', 'source_version' => $plan['edition'], 'source_sha256' => $plan['source_sha256'], 'metadata_sha256' => $plan['metadata_sha256'], 'source_url' => 'https://services.arcgis.com/iQ1dY19aHwbSDYIF/arcgis/rest/services/Mozambique/FeatureServer/'.($data['level'] + 2), 'source_properties' => $feature['properties'], 'source_scan' => $plan['scan'], 'batch_id' => $batch, 'purpose' => 'administrative_boundary', 'investment_site' => false, 'legal_currentness' => 'not_determined', 'match_basis' => $row['match_basis'], 'correspondence' => $row['correspondence'], 'correspondence_version' => $row['correspondence_version'], 'correspondence_sha256' => $plan['correspondence_sha256']];
DB::insert('INSERT INTO geo_geometries(id,source_system,external_id,geo_location_id,geometry_type,geom,properties,data_classification) VALUES (?,?,?,?,?,ST_SetSRID(ST_GeomFromGeoJSON(?),4326),?::jsonb,?)', [$id, 'ine-cod-ab', $row['external_id'], $row['location_id'], strtolower($feature['geometry']['type']), json_encode($feature['geometry'], JSON_THROW_ON_ERROR), json_encode($trace, JSON_THROW_ON_ERROR), 'internal']);
+34 -1
View File
@@ -5,6 +5,8 @@ namespace App\Services;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\HeaderUtils;
@@ -12,8 +14,9 @@ use Symfony\Component\HttpFoundation\HeaderUtils;
/** Authorization/publication stays with the consumer; originals share integrity and cipher handling. */
class VerifiedDocumentBinary
{
public function respond(object $document, bool $inline = false): Response|BinaryFileResponse
public function respond(\stdClass $document, bool $inline = false): Response|BinaryFileResponse
{
$this->authorizeOpportunityAttachment($document);
abort_unless($document->status === 'active' && $document->malware_scan_status === 'clean'
&& ($document->deleted_at ?? null) === null && hash_equals(trim($document->sha256), trim((string) $document->malware_scanned_sha256)), 404);
$disk = Storage::disk('local');
@@ -43,4 +46,34 @@ class VerifiedDocumentBinary
return $inline ? response()->file($path, $headers)->setContentDisposition('inline', basename($document->file_name)) : response()->download($path, basename($document->file_name), $headers);
}
/** The general document route must not bypass the opportunity's current authorization. */
private function authorizeOpportunityAttachment(\stdClass $document): void
{
$links = collect();
foreach (['opportunity_documents', 'opportunity_images'] as $table) {
if (! Schema::hasTable($table)) {
continue;
}
$query = DB::table($table)->where('document_id', $document->id);
if ($table === 'opportunity_images') {
$query->orWhereRaw("payload->'derivatives' @> ?::jsonb", [json_encode([['document_id' => $document->id]], JSON_THROW_ON_ERROR)]);
}
$links = $links->concat($query->get(['opportunity_id', 'deleted_at']));
}
$privateOrigin = in_array($document->source_system ?? null, ['opportunity-resources', 'opportunity-image-derivatives'], true);
if ($links->isEmpty() && ! $privateOrigin) {
return; // Other consumers retain their own publication/authorization rules.
}
$actor = request()->user();
abort_unless($actor instanceof \App\Models\User, 403, 'Anexo privado: é necessário acesso autorizado à oportunidade.');
foreach ($links as $link) {
$opportunity = \App\Models\Opportunity::find($link->opportunity_id);
if ($link->deleted_at === null && $opportunity && $opportunity->status !== 'archived'
&& app(PortalProfileAccess::class)->canView($actor, $opportunity)) {
return;
}
}
abort(403, 'O perfil atual não autoriza consultar este anexo da oportunidade.');
}
}
+7 -4
View File
@@ -204,10 +204,10 @@ class VirtualDesk
});
}
/** @return array<string,mixed> */
public function requestToolPrefill(User $actor, \stdClass $request): ?array
/** @return array<string,mixed>|null */
public function requestToolPrefill(User $actor, \stdClass $request, bool $lock = false): ?array
{
$case = $this->case($actor, $request->case_id);
$case = $this->case($actor, $request->case_id, false, $lock);
$payload = $this->decode($request->payload);
if (! config('investor-path.enabled') || (int) $case->user_id !== $actor->id || ! $case->simulation_id || $case->closed_at
|| ! in_array($request->status, ['draft', 'returned'], true) || trim((string) ($payload['description'] ?? '')) !== ''
@@ -218,6 +218,9 @@ class VirtualDesk
$draftRequest = Request::create('/');
$draftRequest->setUserResolver(fn () => $actor);
$draft = app(SimulationFormDrafts::class)->find($case->simulation_id, $draftRequest);
if ($lock) {
$draft = SimulationFormDraft::query()->whereKey($draft->id)->lockForUpdate()->firstOrFail();
}
$economic = SimulationFormDraft::decryptSnapshot($draft->economic_snapshot);
$description = (string) ($economic['project_summary'] ?? '');
if (trim($description) === '') {
@@ -313,7 +316,7 @@ class VirtualDesk
abort_unless(in_array($request->status, ['draft', 'returned'], true) && $request->version === (int) $data['version'], 409, 'Pedido alterado ou já submetido.');
$prefill = null;
if (! empty($data['tool_prefill'])) {
$prefill = $this->requestToolPrefill($actor, $request);
$prefill = $this->requestToolPrefill($actor, $request, true);
$source = $data['tool_prefill'];
if ($submit || ! $prefill || $source['draft_id'] !== $prefill['draft_id'] || (int) $source['draft_version'] !== $prefill['draft_version']
|| ! hash_equals($prefill['snapshot_sha256'], $source['snapshot_sha256'])
+1
View File
@@ -37,6 +37,7 @@ class VirtualDeskInstallation
sort($files);
$files = [...$files, ...PortalProfileAccess::fingerprintFiles()];
return hash('sha256', json_encode(array_map(fn ($file) => hash_file('sha256', $file), $files), JSON_THROW_ON_ERROR));
}
+4 -2
View File
@@ -1,10 +1,12 @@
<?php
use App\Http\Middleware\AuditProfileDecision;
use App\Http\Middleware\EnsureSimulationRecoveryCookie;
use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use App\Http\Middleware\PortalProfileSession;
use App\Http\Middleware\PreserveFormFeedback;
use App\Http\Middleware\ProtectPrivilegedIdentity;
use App\Http\Middleware\ProtectProfileOpportunity;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\QueryException;
@@ -29,8 +31,8 @@ return Application::configure(basePath: dirname(__DIR__))
$middleware->web(append: [
PortalProfileSession::class,
\App\Http\Middleware\ProtectPrivilegedIdentity::class,
\App\Http\Middleware\AuditProfileDecision::class,
ProtectPrivilegedIdentity::class,
AuditProfileDecision::class,
ProtectProfileOpportunity::class,
HandleAppearance::class,
HandleInertiaRequests::class,
+3
View File
@@ -2,6 +2,9 @@
return [
// Runtime diagnostics must not expose portal requests or private props.
'devtools' => ['enabled' => false],
/*
|--------------------------------------------------------------------------
| Server Side Rendering
+4 -1
View File
@@ -1,12 +1,15 @@
<?php
return [
'organization_country_enabled' => env('PORTAL_ORGANIZATION_COUNTRY_ENABLED', false),
'legacy_content_qa_enabled' => env('PORTAL_LEGACY_CONTENT_QA_ENABLED', false),
'profile_access_enabled' => (bool) env('PORTAL_PROFILE_ACCESS_ENABLED', false),
// Prepare and audit assignments without opening operational opportunity routes.
'profile_administration_enabled' => (bool) env('PORTAL_PROFILE_ADMINISTRATION_ENABLED', false),
// Prepared increment; enable only in QA until the authenticated rollout is approved.
'opportunity_dashboard_access_enabled' => env('PORTAL_OPPORTUNITY_DASHBOARD_ACCESS_ENABLED', false),
'opportunity_specialized_drafts_enabled' => env('PORTAL_OPPORTUNITY_SPECIALIZED_DRAFTS_ENABLED', false),
// Accepted first QA version, additionally guarded by the actual isolated database identity.
// Experimental proposal only; functional approval and operational SLA remain pending.
'opportunity_modular_profiles_qa_enabled' => env('PORTAL_OPPORTUNITY_MODULAR_PROFILES_QA_ENABLED', false),
'opportunity_other_qa_subtypes' => [],
'operator_name' => env('PORTAL_OPERATOR_NAME'),
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (app()->environment('testing')) {
$target = DB::selectOne('SELECT current_database() AS database, inet_server_port() AS port');
throw_unless(str_ends_with($target->database, '_test') && (int) $target->port === 55441, RuntimeException::class, 'Isolated QA required');
} else {
throw_unless(config('organization_country.authenticated_installation') === true, RuntimeException::class, 'Authenticated organization country installation required');
}
Schema::table('organizations', function (Blueprint $table): void {
$table->string('incorporation_country_code', 2)->nullable();
$table->jsonb('incorporation_country_provenance')->nullable();
});
}
public function down(): void
{
throw new RuntimeException('Country data and provenance must be preserved; disable the consumer or restore the verified candidate clone instead of dropping populated columns.');
}
};
@@ -0,0 +1,93 @@
# C132 — contenção aplicada, incidente ainda aberto
Autorização específica do responsável nesta conversa: desativar o diagnóstico anónimo ativo usando a correção QA, preservar os registos restritamente e tratar as credenciais efetivamente afetadas. **Só C132 foi aplicado.** C131, outras funcionalidades, migrations, flags, serviços, COUNTRY02, papéis e as provas A/B/C37 não foram incluídos nesta intervenção.
## Contenção e verificações
- Em **12/10/2026 às 18:57:15 UTC (20:57:15 de Moçambique)**, `config/inertia.php` passou a definir `devtools.enabled=false`. Hash anterior `45994a9035e8e10d2fbb82f9fc18756cfb1ba403c9597d334122181b6b29839b`; novo `80c68e12bf6cb64e39931e2467b43909893cea3eb6d04c3c1e68bdcb1236dfb7`. É a mesma fonte validada em QA. A DACL foi conservada; a troca atómica foi recusada pelo Windows e a aplicação utilizou escrita exclusiva do ficheiro existente, já usada na configuração anterior do portal. Staging removido após conferir o hash.
- HTTP em `https://portal-investidor.test`, TLS reconhecido, sem autenticação/cookies: listagem **404**, detalhe real retido **404**, detalhe arbitrário **404**. Login **200**, cookies Secure/HttpOnly/SameSite=Lax para a sessão e sem conteúdo misto local. Pedidos anónimos ao desafio MFA/dashboard redirecionam para login; isso não foi contado como autenticação bem-sucedida.
- O responsável confirmou em janela privada: **«login, MFA e dashboard funcionam»**, com uma das contas existentes 2/13 e o seu autenticador. O ID exato não foi indicado na resposta; não inventar qual foi usado. Não repetiu A/B ou C37.
- 279 ficheiros preservados com hashes, incluindo 276 diagnósticos, fora da raiz web. Originais e cópia de incidente com ACL restrita ao operador Windows atual e SYSTEM. Logs Apache preservados separadamente. Não foram copiados corpos, cookies, passwords, códigos ou segredos para relatórios/ZIP.
## Alcance conhecido e período
A listagem anónima ativa tinha **445 metadados** às 18:40:45 UTC. O detalhe examinado então expunha dados de utilizador, cabeçalhos, corpos e caminhos internos. Presença de uma chave não significa valor utilizável: a análise local posterior distinguiu valores mascarados de segredos efetivos.
Os 276 diagnósticos preservados abrangem **11/10/2026 18:41:14 UTC a 12/10/2026 13:12:01 UTC**. A recolha e as rotas usam o mesmo gate DevTools; infere-se que o diagnóstico estava habilitado pelo menos na geração do primeiro registo retido. **O início exato da exposição é indeterminado**: a retenção/pruning de 24 horas não constitui um histórico de instalação/habilitação. A diferença entre os 445 metadados anteriormente observados e os 276 ficheiros de entrada preservados não pode ser tratada como inventário integral recuperado; a retenção automática existia antes da contenção.
Os logs disponíveis de acesso (04/10–12/10) foram examinados e preservados; contêm dois pedidos DevTools 200 correspondentes à conferência autorizada e pedidos posteriores 404. O formato é partilhado por vhosts e não prova todos os acessos históricos. **Não foi provada descarga não autorizada; também não foi provada a sua ausência.** O acesso demonstrado foi pelo hostname HTTPS local; alcance externo não foi ensaiado nesta contenção.
## Dados de autenticação efetivamente guardados
| Tipo | Evidência nos registos retidos | Tratamento |
|---|---|---|
| Passwords | 28 ocorrências mascaradas | Sem rotação indiscriminada de passwords. |
| Cookies / XSRF / tokens genéricos | Cookie 267, XSRF 203 e tokens 21 ocorrências mascaradas; Set-Cookie também mascarado | Não se alegou que estes campos presentes continham cookies/tokens utilizáveis. |
| Códigos MFA pontuais | Quatro valores não mascarados, de 11/10 20:12 a 12/10 09:02 UTC | Já expirados; não foram guardados nos recibos públicos. |
| Sementes TOTP / QR otpauth | Quatro sementes e quatro URI, ainda correspondentes às contas ativas antes da resposta | Rotação seletiva das contas 14, 15, 16 e 17. |
| Códigos de recuperação MFA | 32 valores nas quatro respostas JSON em array, sem chave sensível para a máscara genérica; correspondência confirmada no snapshot anterior à resposta | Os oito códigos por conta foram renovados na mesma rotação seletiva. Nenhum dos valores retidos corresponde agora às credenciais atuais. |
| Segredos da configuração ativa | Nenhuma correspondência literal encontrada com os valores secretos da configuração examinada | `APP_KEY`, cifra, HTTPS e histórico preservados; não executar `key:generate`. Isto não prova todo o período anterior à retenção. |
Contas afetadas:
| ID | Titular / conta existente | Resultado |
|---|---|---|
| 14 | Aurora Chachuaio | MFA/recovery renovados; password e papel intactos. |
| 15 | Palmira Uamusse | MFA/recovery renovados; password e papel intactos. |
| 16 | Mario Melembe | MFA/recovery renovados; password e papel intactos. |
| 17 | Tempo Lda — info@tempo.co.mz | MFA/recovery renovados; entrega ao responsável legítimo desta conta. |
Reutilizada a ação Fortify de renovação e `PortalProfileAccess::revokeSessions`: revisão de acesso incrementada, “lembrar-me” invalidado e verificação de sessões/tokens por estas quatro contas. Havia zero sessões autenticadas e zero tokens API dessas contas a eliminar; não se afirma ter eliminado sessões inexistentes. As sementes e os códigos antigos já não coincidem com os atuais; o mecanismo aceita código do novo segredo e recusa o do antigo. **MFA permanece obrigatório durante a entrega das novas entradas**, sem desativação para contorno. Os restantes utilizadores, as atribuições e a dupla 2/13 ficaram intactos. Na renovação inicial não houve envio externo; as entregas individuais posteriores estão registadas no seguimento abaixo.
## Backup, ensaio e auditoria
Antes da mudança do ficheiro, conferidos os hashes dos arquivos e o restauro válido anterior do destino, e realizado round trip da configuração em armazenamento privado. Antes de alterar credenciais, renovado o dump do destino e restaurado no clone isolado `c132_incident_20261012_190248_test:55441`: **295 tabelas e 31 sequências**, linhas/hashes integralmente iguais. O backup de resposta mantém DevTools OFF e a chave estável; originais/documentos de negócio não foram alterados.
A renovação/revogação foi ensaiada primeiro nesse clone e só depois aplicada às quatro contas ativas, por transação. Passwords, obrigatoriedade MFA, papéis, dupla e utilizadores não afetados verificados. Incidente auditado no mecanismo existente, como resposta administrativa autorizada, ator humano NULL (sem personificação): correlação `ead504de-19c1-4d84-9eca-d5649b8a456a`; evento de contenção `f3d7d79b-e6d0-47fe-aff1-b089ac02dd35`. A auditoria não contém novos segredos.
## Medidas ainda necessárias
1. O responsável entrega **individualmente** ao titular os ficheiros MFA locais protegidos `conta-14-2fas-local.html` até `conta-17-2fas-local.html`, no diretório privado de incidente indicado ao Codex local. Estes ficheiros contêm segredos: não anexar à conversa, não publicar URLs, não distribuir o conjunto aos funcionários. Usar 2FAS Auth continua válido: nova entrada TOTP dessa mesma conta, sem reutilizar a anterior. Cada pessoa entra com a sua password e novo autenticador, abre o dashboard e confirma ao responsável. Os códigos de recuperação novos podem ser consultados pelo fluxo autenticado existente.
2. Completar a delimitação histórica quando existirem snapshots/logs adicionais: procurar apenas dados com correspondência concreta, sem rotações gerais por hipótese. Preservar os registos e hashes; não expurgar automaticamente.
3. Verificar que DevTools continua OFF em futuras disponibilizações e que os registos retidos não se tornam anexos públicos. Uma eventual política futura de diagnóstico/retention é decisão separada; a correção mínima presente não ativa outro pacote.
**C132 está contido, não encerrado.** O fecho exige entrega/confirmação dos novos autenticadores, tratamento de outras credenciais que venham a ser efetivamente identificadas e aceitação dos limites históricos documentados. Reversão não deve reabilitar diagnóstico anónimo nem repor segredos comprometidos. Restauro integral de base ou código continua dependente de decisão separada.
Provas sanitizadas no pacote de revisão: `C132-containment.json`, `C132-http-contained.json`, `C132-local-analysis.json`, `C132-usability-before-snapshot.json`, `C132-usability-after-rotation.json`, `C132-rotation-QA.json`, `C132-rotation-active.json`, `C132-backup-restoration.json`, `C132-manual-auth-confirmation.json`, `C132-audit-record.json`, `C132-ACL-verification.json` e `C132-exposure-period.json`. A matriz existente mantém AUD-PROFILE-26 parcial pelos restantes critérios, sem novos IDs ou fecho global.
## Seguimento de 12 outubro e recuperação individual
O cadastro ativo confirma sem inferir a ordem dos nomes: **14 Aurora Chachuaio** (`aurora.chachuaio@tempo.co.mz`), **15 Palmira Uamusse** (`palmira.matsinhe@tempo.co.mz`), **16 Mario Melembe** (`mario.melembe@tempo.co.mz`) e **17 Tempo Lda** (`info@tempo.co.mz`). Para a conta corporativa 17, o responsável determinou entrega ao email, com resposta do gestor; não foi inventado um titular pessoal.
As quatro novas entradas foram conferidas contra as sementes atuais e enviadas em **quatro emails individuais**, um único destinatário por mensagem, sem CC/BCC, TLS 1.3 obrigatório e certificado verificado. A flag geral de notificações permaneceu inalterada; não houve consumo da fila. Os anexos/QR/segredos ficam fora da conversa e dos pacotes de revisão. A tentativa inicial da conta 17 parou antes do envio por uma verificação adicional que confundia TLS implícito com STARTTLS; a negociação TLS real foi conferida antes do único envio aceite. Não houve repetição de email após aceitação.
| Conta | Entrega SMTP | Confirmação do titular |
|---|---|---|
| 14 Aurora | Aceite individualmente com TLS | Responsável confirmou em13/10: recebido,MFA configurado,dashboard acessível. |
| 15 Palmira | Aceite individualmente com TLS | Responsável confirmou em 13/10: recebido, MFA configurado e dashboard acessível. Prova manual; não repetir. |
| 16 Mario | Aceite individualmente com TLS | Responsável confirmou em 13/10: recebido, MFA configurado e dashboard acessível. Prova manual; não repetir. |
| 17 Tempo Lda | Aceite individualmente com TLS | Responsável confirmou: recebido, MFA configurado e dashboard acessível. Prova manual; não repetir. |
A leitura adicional examinou todos os payloads de sessão pela serialização JSON efetiva: **nenhuma sessão autenticada nem `login.id` pendente para 14–17**, no ativo ou no clone restaurado. A revisão de acesso está em 1 e lembrar-me está anulado. A ausência de sessões não é apresentada como eliminação de sessões inexistentes. Num ensaio isolado e transacional de QA, uma sessão autenticada existente foi eliminada pela rotina reutilizada; uma sessão de outra conta permaneceu; o middleware existente devolveu **401**, fez logout e invalidou a sessão antiga com revisão divergente. Os fixtures foram integralmente revertidos. Esta prova QA não substitui as confirmações manuais de recuperação.
Examinados **1.443 pedidos legíveis** e **130 eventos de auditoria** dos registos disponíveis. Os dois únicos pedidos de diagnóstico com 200 coincidem com a conferência autorizada de 18:40:45 UTC, com origem loopback; os posteriores devolvem 404. Não foi identificado outro acesso bem-sucedido ao diagnóstico nesses registos. Rejeições de autorização em perfis foram separadas de prova de ataque. O log é partilhado entre vhosts sem Host/conta autenticada; 21 linhas não correspondem ao formato HTTP analisado. Retenção de 24h, lacunas históricas e ausência de auditoria integral de login/descarga impedem concluir que nunca existiram outros acessos. **Não se declara ausência de exfiltração nem início exato da exposição.**
O diagnóstico mantém-se **OFF constante**, independente de APP_ENV. Acrescentado um gate técnico C132 que verifica a fonte da candidata e a configuração efetiva/cache, antes e depois da disponibilização nos quatro helpers existentes, e uma verificação de CI. Foram ensaiados localmente o estado seguro e a rejeição de configuração ausente, habilitada, condicionada por ambiente e cache habilitadora. CI remoto não foi executado. A verificação HTTP anónima de listagem e detalhe real continua obrigatória após implantação. Não se afirma que um gate possa impedir contorno manual deliberado. Nenhum desses ensaios repetiu disponibilizações históricas, migrations ou alterações de serviço; C131 não foi integrado.
**Situação atual após as confirmações de 13/10:** contas 14–17 recuperadas, entrega/MFA/dashboard confirmados individualmente. O critério de recuperação está concluído; permanecem a avaliação de eventual evidência histórica adicional e os limites indeterminados de exposição. Incidente mantido aberto. As pendências gerais de privacidade, C131, A/B e C37 mantêm os âmbitos e estados anteriores.
## Confirmação manual da conta 16 em 13 outubro
O responsável informou: “conta 16 — recebido, MFA configurado e dashboard acessível”. A confirmação foi registada sem credenciais ou códigos em `C132-account16-manual-recovery.json`, distinta da entrega SMTP e das provas anteriores de sessões. Não se repetiram login, rotação ou envio. Conta 17 mantém a aceitação válida; faltam 14 e 15. O alcance histórico continua indeterminado e C132 não fica encerrado por esta recuperação individual.
## Confirmação manual da conta 14 em 13 outubro
Recebido, MFA configurado e dashboard acessível, conforme mensagem do responsável. `C132-account14-manual-recovery.json`, sem credenciais/códigos.14/16/17 confirmadas; resta 15 e os limites históricos. Não houve novo envio, rotação ou teste de sessões; incidente aberto.
## Confirmação manual da conta 15 e recuperação individual concluída
O responsável confirmou em 13/10/2026: “conta 15 — recebido, MFA configurado e dashboard acessível”. Registo `C132-account15-manual-recovery.json`. As quatro contas 14–17 têm entrega, configuração MFA e acesso confirmados. O critério de recuperação individual fica encerrado; sem reenvio, rotação ou novo teste/alteração de sessões. As provas anteriores de tratamento de sessões permanecem válidas e distintas desta confirmação. Os limites históricos/exfiltração indeterminada mantêm C132 aberto, separado de B. Nenhum segredo/código foi registado.
@@ -0,0 +1,22 @@
# C135: pedido de suporte do transporte de interface
**Preparado em 13/10/2026; não submetido.** Não há canal de suporte ligado às ferramentas desta sessão. Este texto contém apenas o diagnóstico sanitizado; não anexar a conversa completa, credenciais, QR, MFA, cookies, bases ou diagnósticos do incidente C132.
## Texto para o suporte
No Windows, os conectores suportados de interface deixaram de disponibilizar o transporte, embora as provas anteriores tenham usado Chromium local. O primeiro ponto de falha é a ligação IPC, antes da seleção de janela ou de qualquer ação no portal.
- Cliente nativo via `@oai/sky`: `sky.list_apps` falha com pipe nativo indisponível, `os error 2` / ficheiro não encontrado.
- Cliente `cua`: inventário de aplicações e browsers vazio; criação de tab IAB responde `Browser is not available: iab`.
- Recuperação já ensaiada em 12/10/2026 às 21:18 UTC: reset do kernel node_repl, nova importação de sky, consulta de inventário, reescrita da documentação/inventário cua, reset de cua_repl e nova consulta. Resets/importação passaram; transporte continuou indisponível. Não repetir esse ciclo como solução.
- Skill usada: `computer-use:computer-use`, versão de pacote `26.1007.21434`. Versão exata do aplicativo hospedeiro não confirmada; não inventada.
- Não foram iniciados helpers, implementados protocolos privados, usado CDP/Playwright como contorno ou alterados o portal, Apache, base, scanner ou configurações para corrigir o conector.
- Impacto: novas verificações visuais ficam pendentes; HTTP/SQL e desenvolvimento independente continuam possíveis. Provas visuais anteriores preservadas. Não há evidência de que o erro seja da aplicação testada.
Solicitação: verificar o transporte/helper/provider suportado do host e repor um inventário de browsers/janelas utilizável. Indicar o diagnóstico/reparação suportados se houver uma restrição de versão ou de ambiente. A causa específica além da ausência do IPC não está determinada.
Evidência sanitizada disponível: `connector-C135-reset-diagnosis.json`, timestamp `2026-10-12T21:18:20.809642+00:00`. O ticket deve receber número/recibo real após a submissão; até lá o estado é preparado, não enviado.
## Canal e limite de intervenção
O feedback no compositor através de `/` é o canal documentado. [OpenAI Docs — Feedback and logs](https://learn.chatgpt.com/docs/reference/troubleshooting#feedback-and-logs), consultado em 13/10/2026. A ferramenta não expõe envio de feedback e não permite automatizar o seu próprio aplicativo para o submeter. Uma pessoa com acesso ao canal pode encaminhar este texto uma vez; isso não exige repetir testes do portal.
@@ -0,0 +1,61 @@
# Âmbito B aprovado: núcleo e percurso integrado, exclusivamente em QA
**Decisão da Tempo, 13/10/2026: opção B, 40–72 horas de trabalho técnico restante.** Esta delimitação e os critérios abaixo precedem a execução. Mantém a matriz/backlog existentes; não acrescenta funcionalidades, regras de negócio ou requisitos por causa da organização desta entrega.
## Incluído
- Gestão das seis categorias base: projeto de investimento; imobiliário, nos ramos de venda e arrendamento; direitos sobre terra; venda de negócio; parceria de negócio; franquia. Contratos/editor/validações já solicitados, rascunho incompleto, gravação/recuperação, submissão, correção, revisão independente, aprovação, publicação no âmbito autorizado e acompanhamento.
- Materialidade das alterações dos campos já existentes, revisão apenas dos pareceres afetados, condições e evidências recuperáveis; contactos C131 e projeção financeira C136. Preserve-se o promotor real e a autorização de divulgação. Não substituir decisão externa por aprovação interna.
- País mestre da organização, residência e origem separados; recuperação, filtros/estatísticas e repetição sem duplicações dos consumidores incluídos. O formulário existente de interesse em negócio, C133/C134, está incluído; a sua fixture não comprova publicação pelo workflow.
- Recursos e seletores/mapas das oportunidades e dos consumidores usados no percurso integrado, inclusive dossier/Balcão/fundiário. Usar apenas cadastro/correspondências inequívocas existentes, mantendo explicitamente geometria ausente ou ambígua. Sem novas camadas ou importações no ativo.
- Originais, scans, imagens/derivadas e documentos aplicáveis aos fluxos incluídos, com recuperação autorizada. Não disponibilizar uma operação que comprometa confidencialidade; ACL individual de oportunidades continua desligada.
- Percurso do investidor existente: cinco fases e 19 etapas, sem renumerar roteiros; vários investimentos independentes, aplicabilidade, preparação paralela, contexto ao abrir ferramentas, resultado no dossier correto, apoio no Balcão e acompanhamento interno. A/B e C37 não são repetidos; verificar apenas variantes/compatibilidade ainda sem cobertura ou afetadas por correção.
- Teclado, foco, rótulos, erros, leitura dos estados e apresentação móvel dos consumidores incluídos, reutilizando os critérios 320/390 px já provados. Dispositivos reais permanecem uma prova separada.
## Variantes e critério por categoria
| Categoria e provas a reutilizar | Critério ainda a demonstrar/completar no âmbito | Limite preservado |
| --- | --- | --- |
| Projeto — 30/52, WF6/MAT6 | Dados/pressupostos e licença/evidência aplicáveis no contrato existente: alteração → recuperação → reabertura da revisão afetada → decisão independente. | Sem certificação automática de viabilidade ou decisão externa inventada. |
| Imobiliário — venda 31 e arrendamento 54, LEASE54 | Compatibilidade de estados/documentos e recuperação dos valores; provas de renda/periodicidade e workflow de54 reutilizadas. | Construção/ocupação/limites urbanísticos sem percurso completo não são apresentados como variantes concluídas. |
| Direitos sobre terra — 32 | Área/unidade, comunidades/encargos e documentos aplicáveis; valores/IDs/contexto territorial recuperados. | Ato positivo sintético identificado como simulação; limite administrativo não é parcela nem direito. |
| Venda de negócio — 33 e C133 | Mandato/entidade/histórico do ramo existente, promotor real, teaser e divulgação autorizados; interesse com país/origem/estatísticas correto e sem duplicação. | Não aprovar automaticamente a proposta de entidade sem histórico; não confundir o anúncio existente com oportunidade canónica. |
| Parceria — 34 | Contribuições monetárias/não monetárias e obrigações: guardar → recuperar → alteração material → pareceres afetados → aprovação/publicação. | Sala adicional de negociação e C137 ficam no complemento posterior; não são pré-condição deste contrato. |
| Franquia — 35/56, C136 e ramos HTTP de royalties/licença | Taxa/royalties/licença, território e exclusividade nos campos existentes; reabrir apenas revisões afetadas, preservar as demais assinaturas, recuperar a versão e mostrar visibilidade correta. | Não presumir titularidade de marca/licença ou divulgação pública; variantes sem evidência própria não recebem fecho. |
## Aceitação transversal e reutilização das provas
| Percurso/critério | Rotas/consumidores | Evidência válida e falta exata |
| --- | --- | --- |
| Navegação e rascunho | `/dashboard` → `/minhas-oportunidades` → `/minhas-oportunidades/create`; Promotor no âmbito | Navegação/coedição/rascunhos base já provados. Novos campos/erros corrigidos precisam de demonstração própria, sem repetir toda a coedição. |
| Revisão e publicação | `/minhas-oportunidades/{id}/edit`, `/workflow`, `/view`, `/response`; Promotor → Validador → Publicador independentes | WF6/MAT6/LEASE54 preservados. Demonstrar só variantes afetadas e distinguir publicação interna/restrita de catálogo público. Preservar autor/versão/condições/justificação e impedir autoaprovação com múltiplos papéis. |
| Dados pessoais e país/origem | Formulários incluídos de organização, oportunidade, interesse em negócio e Balcão/fundiário | Reutilizar ISO/COUNTRY02/C133. Campo → API → gravação → recuperação → filtro/estatística correspondente; um resultado por repetição, origem não inferida de residência. País real da Tempo não é inventado. |
| Territórios/mapas | `/minhas-oportunidades/{id}/resources`; consumidores territoriais utilizados no dossier/Balcão/fundiário | COEDIT-GEO/QA56/API anteriores preservados. Seleção/alteração do pai/limpeza dos filhos/guardar/recuperar e legenda/ausência de geometria na interface ainda onde falta. Não esperar173 correspondências para validar estes consumidores. |
| Documentos | Recursos privados da oportunidade e documentos dos consumidores incluídos do Balcão/fundiário | Originais/scan/worker/limites/replay anteriores reutilizados. Original preservado, scan e derivadas próprias quando aplicável, download autorizado e negado, nova sessão, sem duplicações. PDF enviado, impressão do browser e reciboTXT distinguidos. |
| Percurso/contexto | `/investimentos`, `/investimentos/{id}` e ferramenta/Balcão abertos com esse contexto | A/B completo preservado. Verificar variantes ainda sem cobertura dos estados/dependências/resultados existentes, recuperação noutra sessão e ausência de mistura/acesso indevido, sem criar fases ou dependências novas. |
| Preparação paralela e decisões | Estados/ações das cinco fases e19etapas | Preparação independente avança quando outra ação aguarda dados. Preenchimento, validação interna, submissão e decisão externa são estados distintos. Aplicabilidade não elimina o histórico nem renumera etapas. |
| Acessibilidade dos critérios novos | Rotas e componentes acima | Reutilizar teclado/axe/móvel prévios; demonstrar apenas rótulos/foco/erros/estados/controles alterados ou sem prova. C135 mantém a prova visual nova aberta. |
Critério de saída: a pessoa conclui a atividade incluída no ambiente QA previsto, vê o resultado e recupera-o noutra sessão, com permissões corretas. Testes/API/SQL/hash não substituem o que falta observar na interface. Uma prova cobre vários requisitos somente quando há correspondência explícita de campo, consumidor, perfil, transição e resultado.
## Fora desta entrega, preservado no mesmo backlog
Outros consumidores de mapas/estatísticas, salas e C137, Balcão/CRM além dos percursos acima, expansão do legado; módulos experimentais/ofertas/competências/SLA; educação nova; simulador fiscal/contributivo; fundos; comparador/modelos; capitalização/Bolsa; negócios similares/importação; editor de checklists; indicadores de utilização. Restauração e migração normativa integral Response/§27 permanecem decisões separadas. O adaptador de compatibilidade conserva IDs/história e `normative_response_complete=false`.
A seleção B adia20–38h do complemento existente e76–152h dos incrementos distintos. Não elimina pedidos nem autoriza desabilitar capacidades atuais por conveniência. Limitações de fonte/dados não são preenchidas por invenção; não se reabre a aceitação das fontes oficiais.
## Condições técnicas antes da execução
- QA prevista: **https://portal-investidor.test:18445**; base **stability_consumers_20261011_084534_test:55441**. Confirmar configuração efetiva/BD real/guarda antes de qualquer escrita e o cabeçalho `X-Investmoz-QA-Target` nos ensaios HTTP.
- Preservar chave/cifra, originais, contratos/hashes antigos de pareceres, IDs, relações, dados e histórico. Notificações/CRM externos desabilitados; tratar apenas trabalhos próprios de teste.
- Conferir030000/040000/050000 e190000 no clone. 190000 é dependência do percurso integrado, não do workflow isolado; não executar uma instalação já existente.
- C135: sem novos resets ou contorno. Pedido sanitizado de suporte preparado, sem canal ligado para submissão; visual novo aberto até alternativa realmente disponível e permitida. Não transferir sucessivamente para o proprietário a descoberta de falhas de infraestrutura.
- C132 permanece incidente separado; não reenviar segredos, rodar MFA ou encerrar as confirmações pendentes nesta entrega.
## Execução, revisão e reversão
Executar por lacuna do conjunto acima, com prova antes/depois quando houver falha concreta. Atualizar as linhas existentes da matriz; conservar fechos e referências. O saldo40–72h é estimativa, não prazo prometido. Não ampliar o âmbito por um erro de harness ou por uma variante nova; registar a lacuna restante.
Entrega final: demonstração integrada dos critérios novos combinada com as provas anteriores; compilação de produção naQA; manifesto/hash fixos; pacote único para revisão, com rotas, perfis, critérios e limitações; backup/restauro correspondente à revisão/acervo incluídos. Enquanto faltar aceitação visual necessária, identificar o pacote como preparado, não integralmente demonstrado.
Reversão QA: conservar fontes/bundle/configuração anteriores e recuperar apenas o delta técnico necessário; não apagar dados, reautorizar partilhas retiradas ou revalidar assinaturas por algoritmo errado. Preparação do destino/ativação mantém procedimento e autorização próprios. **Zero alterações no ativo nesta execução; COUNTRY02 ativo e fechos A/B/C37 preservados.**
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,173 @@
<!-- C132-contained-20261012 -->
## C132 contido no ativo — incidente ainda aberto
Autorização específica do responsável executada: apenas `config/inertia.php`, DevTools OFF desde 12/10 18:57:15 UTC. HTTP anónimo index/detalhe real/detalhe arbitrário **404**. Login **200** e confirmação manual de **login, MFA e dashboard**. C131 não aplicado; COUNTRY02, papéis, bundle, chave/cifra, A/B e C37 preservados.
276 diagnósticos em 279 ficheiros preservados restritamente. Cookies/passwords/tokens mascarados nos exemplares retidos, mas quatro sementes TOTP e 32 códigos de recuperação correspondentes às contas 14–17 foram expostos: renovados seletivamente, obrigatoriedade MFA preservada. Zero correspondências entre os valores retidos e as credenciais atuais. Backup/restauro do destino renovado antes da resposta às credenciais, 295 tabelas/31 sequências, clone isolado 55441. Restam entrega individual das novas entradas e delimitação histórica; **não declarar fecho do incidente**.
[Relatório de contenção, alcance, período, provas e medidas restantes](C132-incidente-contido.md). Os retratos anteriores de C132 exposto abaixo são histórico anterior à contenção, não o estado atual. A matriz existente mantém os IDs; AUD-PROFILE-26 passa a parcial, sem fecho da privacidade integral.
<!-- /C132-contained-20261012 -->
### C125 — contextos de criação repetidos por concessões sobrepostas — P2
QA21 → dashboard → Minhas oportunidades → Nova oportunidade: 32 opções para 10 pares organização/tipo. Esperado: cada par aparece uma vez. Causa: navegação acrescenta um par por concessão, sem deduplicação. Correção apenas na cópia QA de PortalProfileAccess::navigation, depois de verificar representação/permissão; concessões e regras intactas. Chromium confirmou 10 opções únicas, criou arrendamento54 e recuperou; SQL confirmou QA22 ainda com1contexto e venda31 sem alteração. Evidências: functional-lease-editor-chromium-20261011.json e functional-lease-persistence-qa-20261011.json. A correção não ativa módulos experimentais. Ativo inalterado; delta posterior à candidata3d9.
<!-- workflow-functional-cases-20261011:begin -->
## C119–C124 — lote de workflow de11/10/2026
### C119 — campos/referências materiais não abrangidos pelo parecer pertinente — P1
Reprodução de código e snapshotsQA30–35:alterar titular/registo societário ou documento aninhado usado no contrato; algoritmo anterior omitira esses caminhos em alguns gates. Esperado:só pareceres afetados reabertos, restantes com assinatura/ator/data originais; editorial conserva todos. Observado na inspeção:campos ausentes da projeção de materialidade; a lacuna não é atribuída à interface por inferência. Correção QA:materialidadev3 e verificação do algoritmo v2 original, hashing de referências aninhadas. Provas:seis ciclos visuais, ensaio de assinatura v2/alteração editorial e substituição documental em memória. Variantes visuais adicionais continuam por campo; não alterar silenciosamente assinaturas históricas.
### C120 — condições não tinham percurso de responsável/resolução/bloqueio — P1
Inspeção do workflow anterior:parecer condicionado sem estrutura recuperável de responsável,evidência,resolução e bloqueio pertinente. Esperado:responsável existente autorizado, prazo só quando explicitamente definido, resolver com evidência própria e impedir ação bloqueada. CorreçãoQA:contexto/auditoria existentes, sem tabela nova; responsável fora do âmbito recusado, gate diferente recusado, alteração de evidência reabre condição/história. UI30–35:aprovação422 com erro/foco, resolução e aprovação24/publicação25 independentes, dados recuperados. Prova exata:`functional-conditions-semantic-qa-20261011.json` e`functional-workflow-chromium-20261011.json`; SLA externo não inventado.
### C121 — cartões omitiam estados do conjunto autorizado — P1
Passos:listar oportunidades comestado de correção/em análise/espera de informação/rejeição. Esperado:indicadores com rótulos e estados usados no workflow. Inspeção:lista fixa de cartões não incluía esses estados, mesmo havendo contagens da API. CorreçãoQA:cartões novos; filtros por estado e somas coincidem com conjunto filtrado/SQL. Evidência:UIlista/6 consultas. Não confundir cartãozero com cadastro vazio/funcionalidade concluída.
### C122 — Pesquisar enviava booleano textual recusado — P1
Passos:QA21→Minhas oportunidades→Categoria venda de negócio→Pesquisar. Esperado:GET200 com categoria selecionada e lista/indicadores correspondentes. Observado:formulário codificava`deleted=false`; regra Laravel`boolean`rejeita a string, redirecionando ao formulário e perdendo o resultado pretendido. Causa:serialização dobooleano noformulárioGET. CorreçãoQA:enviar0/1. Prova:clique real eURL`category=business_sale&deleted=0`,4 registos; publicados2; texto inexistente0; filas recuperadas;6 consultas iguais aSQL independente. Nenhuma validação do servidor relaxada.
### C123 — títulos e landmarks dos mapas fundiários ambíguos — P1
Passos:abrir caso32 com parcelas/localizações; executar axe em32e15/30–35/lista, teclado/atalho e320/390px. Observado:heading-order no rótulo do anel e landmark-unique entre mapas. Esperado:hierarquia de títulos coerente e nomes de região distintos. CorreçãoQA:rótulo do anel como parágrafo e label contextual por parcela/localização. Repetidas somente32/lista afetadas, demais7 provas reutilizadas;0violações no conjuntoaxe ensaiado, foco e semoverflow. Não encerra leitorreal,dispositivosfísicos ou PDFs acessíveis.
### C124 — dependência ClamD no destino com assinaturas vencidas — P0 para novos scans
Reprodução por leitura do serviço 3310 em12:01:25UTC:engine1.5.4 responde; assinaturas09/10às08:25:40UTC,51,59h; limite configurado48h. Esperado:serviço e assinaturas válidos para novo original/derivada. Observado:`signatures_stale`,healthfalse. Essa é uma prova de saúde do serviço; não se executou upload ativo para fabricar uma falhaHTTP. Operações afetadas:novos scans/importações/anexos/derivadas que exigem análise; não invalida automaticamente scans históricos nem COUNTRY02. Correção necessária:manutenção/atualização de assinaturas no destino e ensaio real de original+derivada com worker supervisionado, no âmbito de futura disponibilização autorizada. QA13310 fresca processou originais normalmente. Destino não alterado neste lote.
Falhas de preparação do ensaio (bundle recompilado durante navegação, TLS do clienteNode e leitura históricaMFA) foram resolvidas no harness e distinguidas de falhas do portal. Conta19 é controlo negativo intencional; não reabre C37/QA18. C110–C118 e fechos anteriores conservam os relatórios correspondentes; este lote não volta a instalá-los.
<!-- workflow-functional-cases-20261011:end -->
## C111 e C112 — HTTPS QA 11/10/2026
**C111 fechado somente na origem HTTPS QA**: certificado SAN country02-qa.test reconhecido pelo Chromium/Windows após confirmação do utilizador, TLS1.3 e contexto seguro. Mantidos Inertia::encryptHistory e private,no-store. Percurso COUNTRY02 completo e 47 recursos conferidos. HTTP histórico continua incapaz de usar WebCrypto; ativação requer HTTPS correspondente e autorização própria. C110 e A/B/C37 preservados.
**C112 — histórico privado depois de logout.** Rota/perfil: /investidor/profile, gestor sintético representado no clone country_candidate_20261011_074430_test:55441. Reprodução anterior à correção: login/MFA→perfil privado→voltar/avançar→logout→Back. Esperado: servidor recusa dados privados e histórico não os restaura, pedindo autenticação. Observado: API401 mas Back recuperava a organização privada no histórico. Causa: Fortify invalidava a sessão no servidor, mas o cliente mantinha a chave do histórico cifrado. Correção na cópia QA: binding da LogoutResponse em AppServiceProvider chama Inertia::clearHistory depois da invalidação/regeneração, preservando a resposta Fortify e a cifragem. Teste: Back mostra login sem master, API401, sessão regenerada e nova sessão/MFA recupera dados após autorização. C112 fechado neste âmbito QA; não se considera instalado no ativo. [Provas/reversão](../../../../outputs/investmoz-country02-https-20261011/REVER-CANDIDATA.md).
Falhas do ensaio separadas: APIRequestContext sem DNSdoChromium e ficheirofavicon ausente na cópiaQA. Corrigidos mecanismo de pedido/sanitização de diagnóstico e cópia dofaviconoriginal. Nenhum cookie, senha, secretMFA oucódigo consta das evidências finais. Sessões temporáriasQA invalidadas ao terminar. Não declarados como falhas da API/instalador; históricos preservados.
## Atualização C110 e novo caso C111 — QA HTTP 11/10/2026
**C110 fechado no instalador QA:** chave gerada pelo servidor vinculada à operação, estável após 409/F5/repetição. Prévia/confirmar/instalar/recuperar demonstrados em hostname HTTP não-loopback. Uma migration/auditoria e duas colunas, sem duplicações. Versão anterior da reprodução preservada abaixo como histórico.
**C111 — histórico privado em HTTP.** Rota/perfil: `/investidor/profile`, gestor sintético autorizado com MFA normal no clone QA. Passos: abrir o instalador pelo hostname HTTP `country02-qa.test:18103`, confirmar que a origem não é marcada segura, concluir o ensaio de instalação e abrir o perfil privado. Esperado: página privada com histórico cifrado e sem erro JS. Observado: estado vazio controlado é apresentado, mas o cliente lança `Unable to encrypt history`; `typeof crypto.subtle=undefined`. Causa: `PrivateInvestmentResponse` pede `Inertia::encryptHistory()` e o cliente necessita WebCrypto disponível num contexto seguro. Esta falha preexistente foi exposta pela equivalência de origem, não foi introduzida pela chave UUID e não reabre A/B ou C37 demonstrados em loopback.
Correção/decisão concreta: manter cifragem e preparar HTTPS com certificado confiável e origem privada definida, verificando navegação/voltar/logout; qualquer disponibilização ativa é separada. Se HTTP for obrigatório, definir e provar um comportamento equivalente sem dados privados no histórico. Não desabilitar proteção nem sinalizar inseguro como seguro. C111 continua pendente, sem mudança de middleware/configuração ativa. [Provas e pacote](../../../../outputs/investmoz-country02-c110-20261011/REVER-CANDIDATA.md); [documentação oficial](https://inertiajs.com/docs/v2/security/history-encryption).
## C110 — formulário do instalador COUNTRY02 em hostname HTTP
**Operação afetada:** inicialização da interface da prévia em `http://portal-investidor.test/management/opportunity-resources-install/organization-country`. Revisão `c68ceef9d4a3` / código `36f7722ce5a5`.
**Reprodução:** depois de conferir os hashes, carregar o bundle no endereço ativo como visitante. GET do instalador redireciona para login, conforme a política de acesso. Na mesma origem, conferir a disponibilidade de `crypto.randomUUID` e carregar o módulo compilado do instalador. Inicializar o componente isoladamente com propriedades de ensaio, sem fazer login ou chamar a API de aplicação.
**Esperado:** inicialização do componente e chave UUID de repetição válida, permitindo a posterior prévia autenticada.
**Observado:** `isSecureContext=false`, `crypto.randomUUID=undefined`, `getRandomValues=function`. O módulo real, com hash conferido, lança `TypeError: crypto.randomUUID is not a function` antes de `useForm` ou do layout. A prévia autenticada não foi obtida. Esta prova não simula autorização ou autenticação.
**Causa:** chamada incondicional de `crypto.randomUUID()` na inicialização de `idempotency_key` em `resources/js/pages/management/opportunity-install.tsx:31`. A QA em HTTP loopback não reproduzia o contexto do hostname HTTP ativo.
**Correção e aceitação restantes:** UUIDv4 criptográfico com alternativa `getRandomValues` ou UUID do servidor. Ensaio em QA equivalente ao hostname HTTP ativo, preservando CSRF, MFA recente, confirmação, motivo, hash e repetição. Recompilar e fixar nova revisão antes de retomar uma prévia e aplicação autorizadas correspondentes. Não alterar chave, perfis ou origem para contornar a falha.
**Resultado seguro:** interrompido antes do POST, manifesto anterior restaurado atomicamente, 050000 e duas colunas ausentes, flag desabilitada. Zero alterações de negócio e zero eventos de instalação; duas sessões públicas de visita. [Relatório e recibos](../../../../outputs/investmoz-country02-activation-20261011/resultado.md). A/B e C37 preservados.
<!-- country-production-final-20261011:begin -->
## C109 — MFA do instalador sem040000 — 2026-10-11T06:21:38.798206+00:00
**Requisito:**COUNTRY02/OPS01. **Causa:**AppServiceProvider condicionava a escrita de`portal.mfa_actor`/`portal.mfa_at`ao módulo de perfis disponível;PortalProfileInstallation exigeMFArecente mesmo no ramo manage-portal anterior a040000. PreserveFormFeedback não é a causa;C37QA18 permanece encerrado.
**Reproduzir no clone:** fonte288tabelas,030000/040000/190000ausentes, emailverificado/gestor sintético comMFA normalmente configurado; login→challengeválido→préviaCOUNTRY02→POSTconfirmado comCSRF/hash/UUID/reason. **Esperado:**2colunas opcionais/ledger/auditoria. **Antes:**403"Conclua MFA nesta sessão"apesar dochallengeválido. **Correção:**registo da prova unicamente no evento Fortify de código válido, sem depender de040000; fingerprint incorpora oprovider.
**Provas:**CountryCandidateMfaTest confirma código inválido/guest, código válido/autenticado/prova e logout/semprova;regressão6testes90assertions;Chromiumdo bundleprodução confirmaMFAsem040000, gravação/recuperação em nova sessão comdriverdatabase e idempotência. Primeira instalação visual a frio emcountry_candidate_20261011_060236_test;restauro finalcountry_candidate_20261011_060946_test com snapshot de origem idêntico. Recibos sanitizados omitem códigos/segredos/cookies e corpos de autenticação. A/B/C37 não foram repetidos.
**Observações do harness:**a primeira execução usouOPcache diferente doChromiumQAexistente e foi corrigida paraopcache.enable=0; essa alteração foi só no servidor temporárioQA18101. Um locator de"Instalado"foi tornado específico; uma fixture de compatibilidade alterou oMFA de um ator sintético partilhado, pelo que o ensaio passou a usar ator próprio e operações sequenciais. Tentativas anteriores foram preservadas; a tentativa final passou. Nenhum destes problemas reabreC37daQA18 ou altera oativo. ServidorQA18101 encerrado depois dos ensaios;QA18097 preservada.
<!-- country-production-final-20261011:end -->
<!-- qa-revision-20261011:begin -->
## Casos novos reproduzidos — 11/10/2026
| Caso / requisito | Reprodução | Esperado / observado / causa | Correção e prova |
| --- | --- | --- | --- |
| C104 P1 OP03/04 | Imóvel31publicado; Promotor21 prepara revisão, altera sótítuloeditorial ou preço,guarda/submete. | Esperado: só pareceres substantivamente afetados reabertos; nova assinaturafinal. Antes: save/submit apagava indiscriminadamente todos os pareceres; nenhuma comparação deescopo. | Escopos pergate +baseline +hashassinadooriginal preservado; título mantém3,preço reabrepropertye mantém2; Validador24/aprovaçãoindependente/Publicador25republicação no Chromium. Não generalizar ao restante workflow. |
| C105 P1 UI01/COUNTRY07 | QA21 rascunhofundiário incompleto; avançar àconfirmação e pedirapoio sem campos anteriores. | Esperado: voltar àetapacom campo,erro associado e foco. Observado: permanecia na confirmação,campos com erro ocultos e mensagensgenéricas. Causa: validação multietapa sem direcionamento/foco apóscommitReact. | Estado pendingErrorField/useEffects,IDs/aria e resumo nomeado; rascunho recuperável,erro support_kind focado,sem submissão/estatística indevida. revision-land-errors e novo rótulo/recovery emland-replay. |
| C106 P1 OP03/04 | MesmoGeoJSON: trocar ordem de pontos mas conservar os valores; comparar assinatura deescopo antiga/atual. | Esperado: ordem coordenada ématerial; chavesJSON porordem não. Antes: Arr::sortRecursive ordenava listas e podia tornar geometrias distintas iguais. | CanonicalValue ordena apenas objetos,preserva listas; regra review-scopes-v2,comparação anterior/audit de migração conservam hashes/regraoriginais. Teste semântico isolado provaREeDUAT; não foi novo ensaio visual de edição degeometria. |
| C107 P1 GEO03/UI01 | Público: fichaBalama,carregar mapa,viewport390px; medir scrollWidth e elementos. | Esperado: largura390,semrolagemhorizontal. Observado438; referência documental longa deponteaoexemplar excedia parágrafo/contentor. Tiles também eram extensosmas não demonstravam sozinhos a causa. | overflow-wrap:anywhere no componente de fontes territoriais e contenção explícita dos tiles; reteste público390semextravasamento/axe e ação de mapa por teclado. Geometria própria continua ausente,explicitamente apresentada. |
| C108 GEO03 — observação do ensaio esclarecida | Ficha pública Balama; consultar mapa dos investimentos no ensaio Chromium. | Primeira captura: mensagemcontrolada “Mapa base indisponível”, mapa cinzento; lista/estados disponíveis. Causa identificada: o próprio harness abortava todos os pedidos deorigem diferente daQA. Não foi falha do portal/TLS. | Ensaio separado permite sóGETde tile.openstreetmap.org:200/3tiles e fundo apresentado. revision-map-basemap-allowed-20261011.json. Sem alteração de geometrias,fontes,permissões ou TLS. Geometria própria continua ausente. Não conta como defeito corrigido do portal. |
Não são casos do portal: harness com ator/propriedade/rótulo incorreto,espera pelo endpoint do mapa público no editor privado,ou espera URL antes da navegação. QA14=403porMFA não confirmado é autorização exigida; QA17mantém acesso comMFA normal. A/B/C37 conservam fecho; não se repetiram os seus percursos.
<!-- qa-revision-20261011:end -->
<!-- qa-next-consumers-cases-20261010:begin -->
## C97–C103 — casos novos deste incremento QA — 2026-10-10T22:29:22.300559+00:00
**Ativo fora da escrita. A/B e C37 preservados.** Provas sanitizadas omitem cookies, X-XSRF-TOKEN, passwords, segredos e códigos MFA; contextos separados e alvo conferido antes de mutações. Tentativas do harness que falharam por navegação/seletor/compilação não são casos do portal.
| Caso / prioridade / requisito | Reprodução e operação afetada | Esperado / observado / causa | Correção e prova |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| C97 P1 COUNTRY02 | Abrir perfil como representante de uma organização existente; procurar país de constituição no cadastro mestre e reutilizar numa manifestação. | Esperado: ISO/fonte/versionamento no mestre e cópia identificada. Antes: organizations não tinha campos nem ação; declaração privada não era mestre. | Extensão050000:2colunas opcionais e serviço existente memberships/audit_events. QA21FR→cópia→ZA→nova sessão preservaMZ/FR e fontes; QA23PUT403; viewer/revogado/Auditor/múltiplos papéis unitários. `next-organization-chromium-20261010.json`; ativo ausente, não ativado. |
| C98 P1 UI01 | No editor do mestre submeter país/referência vazios; observar os erros e foco. | Esperado: erros associados e foco no primeiro campo inválido. Observado: erros renderizados depois do callback/RAF, foco não chega ao campo. Causa: atualização React ainda não comprometida. Label envolvendo textarea incluía o seu valor no nome acessível. | useEffect após atualização dos erros; htmlFor/id separado na referência; aria-invalid/describedby e alertas. Tentativas anteriores preservadas; `next-accessibility-chromium-20261010.json` valida erro/foco na revisão final. Pedido inválido não alterou o mestre. |
| C99 P0 OP03/CRM | QA21,31publicada: “Preparar alteração material”, fundamentação>80caracteres. | Esperado200, task concluída e razão completa rastreável. Observado503; stack SQLSTATE22001: tasks.outcomeVARCHAR80 recebeu a fundamentação integral. | Resumo CRM limitado80caracteres Unicode; motivo integral conserva-se no workflow/decisão/evento/auditoria. Cinco categorias completaram alteração/revisão/publicação aplicável no Chromium; teste preserva razão completa e resumo80. `next-workflow-categories-chromium-20261010.json`; SQLfinal. |
| C100 P1 UI01/COUNTRY | Abrir manifestação com três países, Balcão/negócio/fundiário e estados do workflow; consultar nomes acessíveis/erros. | Esperado: residência/constituição/origem distintas e erro associado; estado legível. Antes: vários selects tinham nome genérico“País”, erros sem referência no campo e códigos de estados sem leitura própria. | CountrySelecterror/aria-describedby, nomes distintos por consumidor e estados nomeados/traduzidos. RevisãoChromium/axe/teclado em cinco rotas delimitadas; não encerra todas as rotas/leitor de ecrã/dispositivos reais. |
| C101 P0 OP03/CRM | Suspender31; Promotor prepara revisão e resubmete **sem editar conteúdo**; Validador inicia revisão. | Esperado: tarefa aberta no novo ciclo. Observado409“Tarefa não pertence à versão aberta”; ensure reutilizou tarefa concluída porque chave só incluía conteúdo/tipo. | review_cycle separado de content_revision, chave nova por submissão; recupera vínculo concluído do caso legado só para a mesma oportunidade/tipo, guardando vínculo anterior e tarefa original. Navegador concluiu revisão→aprovação→republicação; teste before409/after25asserções preserva tarefas/conteúdo; SQLconfirma histórico. |
| C102 P0 OP04 | QA21/42: abrir editor após aprovação, alterar necessidade e guardar contrato com resumo canónico>500caracteres. | Esperado: texto integral válido e rascunho recuperável. Observado422“summary…500”; UI reenviou alias legado, validado antes de o contrato canónico ser usado. | Campos canónicos comuns são fonte única; aliases redundantes não impõem validação incompatível. Resumo legado limitado500, texto integral conserva-se no JSON canónico. Validação legada500 mantém-se quando não há contrato. Teste11asserções e quatro módulos no Chromium; SQL comprimentos/fontes/publicações. |
| C103 P1 UI01 | Abrir `/parcerias/salas/1` e executar auditoria axe de landmarks. | Esperado: um main principal único. Observado: landmark-main-is-top-level, landmark-no-duplicate-main e landmark-unique; Frame reutilizava o main do portfolio dentro do main do AppLayout. | Layout portfolio permite container sem novo main; Frame de parceria usa essa opção, preservando navegação e permissões. Reteste final: zero violações automáticas nas cinco rotas; captura/teclado/estados preservados. Não equivale a acessibilidade integral. |
Âmbito de fecho: falhas técnicas acima corrigidas e critérios QA ligados aos recibos; requisitos globais ainda parciais/instalação ativa ausente conforme [matriz-requisitos.csv](matriz-requisitos.csv) e [backlog.md](backlog.md). C37QA18 e A/B não foram reabertos.
<!-- qa-next-consumers-cases-20261010:end -->
<!-- qa-consumer-cases-20261010:begin -->
## C91–C96 — correções demonstradas em QA; ativo não alterado
**C91 (P1; AUD-DOC-01, AUD-COUNTRY-07, AUD-UI-01).** Reprodução: QA21 → pedido fundiário `01a12568-c330-73ec-a1ac-543ac0116a26` → “Imprimir / guardar cópia preenchida como PDF”. Esperado: caracteres legíveis e país/origem declarada separados, recuperados dos dados guardados. Observado: título e rótulos com caracteres mal codificados; país e origem não eram apresentados. Causa: texto corrompido no componente de impressão e ausência dessas propriedades no controlador da impressão. Correção: recuperar as duas descrições pelo catálogo existente, reparar a codificação do componente e preservar o texto legado sem inferir residência ou nacionalidade. A interface recuperou MZ/PT e acionou a impressão; outra conta e o gestor recebem404 na rota privada. Provas: `consumer-doc-before-chromium-20261010.json`, `consumer-documents-chromium-20261010.json` e regressão de LandAssistance. O PDF gerado e o seu scan são verificados separadamente; não se reutiliza o scan dos anexos como prova da derivada.
**C92 (P1; AUD-DOC-01, AUD-UI-01).** Reprodução: gerar o PDF preenchido pelo Chromium e inspecionar todas as páginas. Esperado: cópia do formulário, sem navegação da conta e com paginação utilizável. Observado no PDF anterior: menus, caminho de navegação e chamada de apoio incluídos; a regra que mantinha cada secção inteira produzia espaço vazio excessivo. Causa: o layout comum não distinguia a impressão e a regra de quebra era demasiado abrangente. Correção: esconder esses elementos somente na impressão deste componente e permitir quebra de secções, mantendo linhas e cabeçalhos agrupados. Ficheiro e scan anteriores preservados como `consumer-land-derived-before-c92-20261010.pdf` e `consumer-pdf-scan-before-c92-qa.json`. Reversão por código/build, sem alterar o pedido ou os originais.
**C93 (P1; AUD-OP-03/04, AUD-UI-01).** Reprodução: dashboard QA21 → oportunidade52 → editor `investment_project` → completar os dados ambientais necessários à submissão. Esperado: campos da definição canónica disponíveis e rascunho incompleto recuperável. Observado: o objeto ambiental aparecia sem campos, com indicação de definição contratual pendente; a submissão recusava a ausência desse objeto. Causa: a propriedade extraída de Create era um objeto opaco, embora `environmentalSocialCreate` já definisse os campos. Correção: o adaptador reutiliza essa definição para editor e validação, sem novo cadastro, tabela ou aprovação externa. QA21 preencheu avaliação/classificação explicitamente pendentes e completou o ciclo visual de correção, aprovação24 e publicação25. A regressão verifica os campos e a preservação do rascunho incompleto. Fixture antiga sem marcos, imagens ou dados ambientais completos foi conservada; a nova oportunidade recebeu os dados sintéticos pela interface, sem relaxar regras.
**C94 (P1; AUD-OP-02/03, AUD-DOC-01, AUD-UI-01).** Reprodução: oportunidade52 submetida/publicada → Promotor autorizado abre Recursos → tenta “Documentos” ou “Imagens”. Esperado: poder consultar anexos e miniaturas, sem poder editar a versão fechada. Observado: os separadores estavam desativados por `readOnly`, embora as rotas de consulta autorizassem a leitura. Causa: o mesmo bloqueio de edição era aplicado à navegação de consulta. Correção: separadores apenas bloqueados durante uma operação; seleção de recurso em leitura identificada como “Ver recurso”; ações de gravação/exclusão/restauração permanecem bloqueadas e o servidor conserva a política. Chromium após correção: download do PDF com hash exato, miniatura WebP interna renderizada, QA23 recebe403 no original e na URL assinada; anónimo recebe401. Catálogo público apresenta a ficha sem metadados privados. Prova: `consumer-workflow-files-chromium-20261010.json`; tentativa anterior com botão desativado preservada.
**Diagnósticos que não são falhas do portal:** a autorização de download/preview não está apenas no controlador; `ProtectProfileOpportunity` aplica a política por organização e estado. QA23 e o teste de URL assinada válida foram recusados antes de qualquer correção, com403; não foi criado um caso de fuga de ficheiros. Erros de seletores do harness e requisitos novos em fixtures antigas estão preservados nas tentativas, separados de C93/C94. Um callback de rede do harness expôs cookies na saída de erro: foram invalidadas três sessões sintéticas QA21 do lote, sem mudar MFA; recolha sanitizada e encerramento dos callbacks corrigidos. Prova: `consumer-browser-session-revocation-qa.json`. C37 e as credenciais não foram reabertos.
Todas as escritas funcionais deste lote usam exclusivamente QA18097/`desk_restore_20261009_174726_test:55441`. A demonstração de C93 cobre `investment_project`; não encerra os outros contratos ou Response/§27. A impressão corrigida não encerra acessibilidade documental integral nem todos os consumidores.
**C95 (P1; AUD-COUNTRY-06, AUD-UI-01).** Reprodução: negócio QA18 `4f927885-4e30-42d6-a9ed-7c983f5af149` → etapa3 → consultar o nome acessível do seletor de sector. Esperado: pesquisa e seleção com nomes distintos. Observado: o rótulo envolvia pesquisa e select, mas apenas a pesquisa tinha nome próprio; o select não era encontrado pelo respetivo nome acessível. Correção: nome explícito no select, preservando a pesquisa, as opções e os dados. Chromium após correção: preencher os oito passos do negócio existente → submeter200 → nova sessão → recuperar PT/FR e estado submitted → estatística FR0→1; repetição409 sem duplicação. Prova: `consumer-business-chromium-20261010.json`. Não encerra a acessibilidade integral do wizard.
**C96 (P2; AUD-GEO-01/03, AUD-UI-01).** Reprodução: gestor QA → corredor `b46a0eba-13fa-4917-8730-be0e2e86db6f` → editor. Esperado: rótulo “Descrição” legível. Observado na inspeção visual do mapa/seletores: “Descrição”. Causa: literal corrompido no ramo de corredores do editor comum. Correção: reparar somente o literal, preservando dados/IDs/associações. Prova anterior: captura corridors-deep-selectors de `consumer-structures-deep-chromium-20261010.json`; prova após compilação QA: `consumer-corridor-label-chromium-20261010.json`, nome acessível correto e localidade recuperada, sem regravar. Não altera regras territoriais.
Complemento C92: PDF final com três páginas renderizadas e inspecionadas, sem menus, caracteres legíveis, MZ/PT separados. Scan ClamAV real da própria derivada clean e três originais preservados: `consumer-pdf-presentation-qa.json`, `consumer-pdf-scan-qa.json`. O PDF não está etiquetado; acessibilidade documental integral continua pendente. Complemento C94: Validador24 consulta PDF e WebP, com “Guardar recurso” desativado; `consumer-reviewer-files-chromium-20261010.json`. Isso não concede edição nem encerra todos os perfis.
<!-- qa-consumer-cases-20261010:end -->
<!-- qa-ab-countries-cases-20261010:begin -->
## C88–C90 — corrigidos em QA, ativos não alterados
**C88 (P1; DESK02, GUIDE01, UI01):** abrir dossierA existente→Apoio no Balcão→pedido8e6511a8-c15d-46b7-8eb5-c34b6e31eb15. Esperado: reutilizar resumo guardado da ferramenta do mesmo projeto para preparar apoio, conservando o pedido. Observado: descrição vazia embora o rascunho financeiro atual tenha54bytes de resumo; B tinha54bytes recuperados. Causa identificada: preparação copiava uma vez; rascunho anterior não recuperava alterações posteriores e não havia ação explícita de reutilização. Não foi inferida a causa histórica da cópia vazia. Correção: prévia do resumo atual, botão explícito “Reutilizar descrição guardada e guardar rascunho”, só para descrição vazia, conta proprietária, request/version/source do mesmo dossier; servidor recusa fonte/versão divergente, sobrescrita e submissão conjunta; locks e histórico preservados. PUT pela interface guardou A,v3 da ferramenta, criou revisão do texto vazio e evento request_prefill_reused, sem novo pedido/conta/dossier. API/SQL e UI390/320 recuperam resumo/PT/ZA; gestor não recebe prévia financeira privada. Provas: investor-ab-remaining-* e regressão antes/depois. A tentativa de harness após guardar comparava versão textual com inteiro; a gravação não foi repetida, e a recuperação/revisão foram confirmadas depois. Reversão não apaga o histórico.
**C89 (P1; COUNTRY03/04, UI01):** nos quatro formulários públicos, consultar nomes acessíveis dos dois seletores. Esperado: país do requerente e origem declarada distinguíveis. Observado: ambos aria-label=País, apesar dos textos visuais diferentes. Causa: CountrySelect usava o label padrão para ambos. Correção: nomes explícitos “País do requerente” e “País de origem declarado desta solicitação” no formulário comum e na manifestação pública. Chromium comprovou seleção PT/ZA, gravação e recuperação/filtros; quatro exames390px sem violações automáticas/overflow. Leitor de ecrã real continua independente. Não foi alterado catálogo, significado ou dado histórico.
**C90 (P1; COUNTRY03/04; rastreabilidade de entrada, independente da origem-país):** enviar formulário público Investidor ou Empresa e recuperar registo na gestão/SQL. Esperado: guardar a página de entrada e apresentar país/origem como campos distintos. Observado: source_page=/apoio para ambos, porque o POST é partilhado. Causa: literal fixo no construtor InterestRequest. Correção: registar path de formulário conhecido somente com esquema/host/porta da mesma origem; fallback/endpoint=/apoio para referente externo, administrativo, inexistente ou outra porta. Queries pessoais não são guardadas. Replay conserva a origem da primeira receção. Interface da gestão mostra “Página de entrada registada”. Um envio novoC90→POST302→protocolo→gestão→/formularios/investidor/PT/ZA→SQLúnico, sem reatribuir os anteriores. Regressão antes falhava (/apoio); depois passa, incluindo replay e referentes não autorizados. Provas: form-entry-source-*qa.json e ab-country-final-regression-qa.json.
**Ensaios, sem falha técnica do portal:** rejeições422 dos emails sintéticos .invalid/example.com em manifestação pública são a validação DNS prevista; erroemail aparece e não grava pedido. Usado identificador sintético de domínio DNS aceite com notificaçõesQA desativadas. Não relaxar regra ou usar endereço como identidade real. Erros anteriores de harness (duas versões financeiras legítimas, caixa do estado draft e versão de revisão serializada como texto) preservados nos recibos de tentativa; não são duplicações ou falhas de autorização.
A/B internos agora concluídos em QA por composição de provas. C37 continua encerrado só na autenticaçãoQA18; cenários não afirmam submissão/decisão externa, auditoria integral ou ativação.
<!-- qa-ab-countries-cases-20261010:end -->
<!-- qa-territory-resource-cases-20261010:begin -->
## Casos C86/C87 — recursos e cartografia
**C86 (P1, OP02/GEO02):** editar localização MZ com província e mudar payload para PT mantendo IDs MZ. Esperado422 no país e preservação do original; observadoantes200 e gravação contraditória. Causa: catálogo de países e seleção territorial validados separadamente; editor e conferência não aplicavam país. Correção: regra cruzada no servidor; UI retira a hierarquia somente no preenchimento após mudança explícita; rascunho estrangeiro incompleto aceite; conferência não pede campos MZ para estrangeiro. Provas: regressão antes/depois, browserQA21 e SQLREADONLY; tentativa rejeitada não muda payload/versão/auditoria. Dois recursos guardados/recuperados noutra sessão; QA23 consulta/escrita403. Nenhuma conversão de registos históricos.
@@ -10,6 +179,7 @@ C37 já encerrado por confirmação manual somente para autenticação QA18; nã
<!-- qa-territory-resource-cases-20261010:end -->
<!-- c37-manual-close-20261010:begin -->
## C37 encerrado — autenticação QA18 — 2026-10-10T20:26:29.902032+02:00
**Confirmação manual expressa do responsável registada. C37 está encerrado exclusivamente no âmbito da autenticação QA18.** Login → MFA → redirecionamento → sessão autenticada → atualização → logout → nova sessão/recuperação estão ligados às provas anteriores, sem repetir ensaios nem alterar conta, chave ou MFA. O logout manual de 20:17:15 foi confirmado pelo responsável e pelo rastreio: POST302→/, autenticação e estado persistido vazios.
@@ -21,6 +191,7 @@ O fecho **não encerra A/B, auditoria integral, móvel/acessibilidade integral,
<!-- c37-manual-close-20261010:end -->
<!-- qa-logout-c85-20261010:begin -->
## C85 — logout ausente no percurso do investidor
- **Reprodução:** autenticar QA18, abrir `/investimentos` ou um dossier; procurar logout no cabeçalho. Não havia botão; era preciso conhecer o menu do dashboard.
@@ -33,19 +204,20 @@ O fecho **não encerra A/B, auditoria integral, móvel/acessibilidade integral,
<!-- qa-logout-c85-20261010:end -->
<!-- qa-visual-cases-20261010:begin -->
## Casos adicionais C77–C84 e estado C37 — 10/10/2026
| Caso | Reprodução e observado | Esperado, causa e correção QA |
| --- | --- | --- |
| C37 | MFA manual aceite; destino pretendido era relatório administrativo, negado 403 com sessão autenticada. Nova tentativa 17:46:42 UTC chegou ao dashboard 200; responsável confirmou acesso. | Recusa administrativa correta. Página QA explica o acesso reservado e oferece retorno; pedido Inertia passa uma vez por 409 para renderizar a página completa, evitando modal na página MFA. QA21 provou 403 → painel → investimentos → F5. C37 habitual ainda pede F5/logout/novo login; ciclo anterior não demonstrado como falha persistente. |
| C77 / UI01, LEG02, DASH01 | axe: mains aninhados, conteúdo fora de landmarks e cabeçalho Sheet fora do Dialog. | Um main, navegação e apoio nomeados, SheetHeader dentro do SheetContent. Quinze verificações dirigidas posteriores sem violações automáticas. |
| C78 / GEO03 | Mapas com aria-label num div sem role. | Região nomeada. Cabo Delgado apresentou um polígono em quatro consumidores; seleção ainda não guardada e tiles externos não testados. |
| C79 / LEG02 | Turismo começava com h3 sob o título h1, omitindo h2. | Normalização apenas na apresentação para h2..h6 e saltos máximos de um nível, mantendo original, bytes, hash e texto. LegacyContentTest 5/84 e Chromium passaram. |
| C80 / SIM02, GUIDE01 | Preenchimento iniciado antes de terminar o GET podia ser sobrescrito pelo rascunho remoto; faltavam campos de A na recuperação. | Impedir edição e avanço até recuperar; cancelar efeito obsoleto; devolver resultado só após guardar snapshot completo. Chromium com GET deliberadamente atrasado e nova sessão A/B demonstraram recuperação. Histórico preservado. |
| C81 / SIM02 | Tabelas financeiras com scroll sem foco por teclado. | tabindex=0, região nomeada e foco visível. QA21 focou ambas e usou ArrowDown; axe passou. Leitor de ecrã real pendente. |
| C82 / GUIDE01 | Dossier a 390px alargava a página para 413px devido a labels/select/datetime da atribuição. | min-width:0, max-width:100% e quebra de linha, sem esconder ações. Dossier próprio QA21 corrigido sem overflow; repetir A/B móvel final. |
| C83 / UI01, LEG02 | HTML lang=en para interface em português. | Configuração pt-MZ somente no router QA e fallback anterior no template. Quinze verificações com pt-MZ; locale de validação preservado. |
| C84 / DOC01 | Mensagem global “ClamD real pendente” contrariava os scans reais. | Mostrar scan/motor por ficheiro/versão; retirar texto global. QA21 recursos51 confirmou apresentação; nenhuma derivada/PDF recebeu scan fictício. |
| Caso | Reprodução e observado | Esperado, causa e correção QA |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| C37 | MFA manual aceite; destino pretendido era relatório administrativo, negado 403 com sessão autenticada. Nova tentativa 17:46:42 UTC chegou ao dashboard 200; responsável confirmou acesso. | Recusa administrativa correta. Página QA explica o acesso reservado e oferece retorno; pedido Inertia passa uma vez por 409 para renderizar a página completa, evitando modal na página MFA. QA21 provou 403 → painel → investimentos → F5. C37 habitual ainda pede F5/logout/novo login; ciclo anterior não demonstrado como falha persistente. |
| C77 / UI01, LEG02, DASH01 | axe: mains aninhados, conteúdo fora de landmarks e cabeçalho Sheet fora do Dialog. | Um main, navegação e apoio nomeados, SheetHeader dentro do SheetContent. Quinze verificações dirigidas posteriores sem violações automáticas. |
| C78 / GEO03 | Mapas com aria-label num div sem role. | Região nomeada. Cabo Delgado apresentou um polígono em quatro consumidores; seleção ainda não guardada e tiles externos não testados. |
| C79 / LEG02 | Turismo começava com h3 sob o título h1, omitindo h2. | Normalização apenas na apresentação para h2..h6 e saltos máximos de um nível, mantendo original, bytes, hash e texto. LegacyContentTest 5/84 e Chromium passaram. |
| C80 / SIM02, GUIDE01 | Preenchimento iniciado antes de terminar o GET podia ser sobrescrito pelo rascunho remoto; faltavam campos de A na recuperação. | Impedir edição e avanço até recuperar; cancelar efeito obsoleto; devolver resultado só após guardar snapshot completo. Chromium com GET deliberadamente atrasado e nova sessão A/B demonstraram recuperação. Histórico preservado. |
| C81 / SIM02 | Tabelas financeiras com scroll sem foco por teclado. | tabindex=0, região nomeada e foco visível. QA21 focou ambas e usou ArrowDown; axe passou. Leitor de ecrã real pendente. |
| C82 / GUIDE01 | Dossier a 390px alargava a página para 413px devido a labels/select/datetime da atribuição. | min-width:0, max-width:100% e quebra de linha, sem esconder ações. Dossier próprio QA21 corrigido sem overflow; repetir A/B móvel final. |
| C83 / UI01, LEG02 | HTML lang=en para interface em português. | Configuração pt-MZ somente no router QA e fallback anterior no template. Quinze verificações com pt-MZ; locale de validação preservado. |
| C84 / DOC01 | Mensagem global “ClamD real pendente” contrariava os scans reais. | Mostrar scan/motor por ficheiro/versão; retirar texto global. QA21 recursos51 confirmou apresentação; nenhuma derivada/PDF recebeu scan fictício. |
**Mapa manual 51, 17:52:33 UTC:** conta autenticada QA18 recebeu 403; QA21 havia recebido 200. Sessão mantida. É recusa correta por perfil/autoria e não um mapa funcional demonstrado pelo responsável. Credenciais e entradas MFA são distintas; não ampliar autorização para permitir o ensaio na conta errada.
@@ -55,6 +227,7 @@ Provas: `visual-followup-chromium-20261010.json`, `qa-report-access-chromium-202
# Casos de reprodução e lacunas observáveis
<!-- qa-c71-sector-cases-20261010:begin -->
## Estado dos casos C71–C76 após o lote — 2026-10-10T16:23:25.695297+00:00
**C71 / AUD-OPS-01:** causa/operação/reprodução históricas preservadas abaixo. CorrigidoQA: recuperação emcluster novo, comparação295 tabelas/34.902 linhas/31 sequências e schema/permissões compatíveis; cópia física75575 ficheiros com hashes iguais. Prévia22 itens renovada antes de aplicação; backup/restauro final295/103verificado. Processo que removeu26catálogos continua não identificado; nenhum remendo de catálogo ou rotação de chave. Requisito inteiro parcial pelas demais dependências/ativação. A manutenção foi retirada; GET/login200no18097. Ver provas no relatório atual.
@@ -73,6 +246,7 @@ Falhas do harness conservadas separadamente: primeira leitura usou indevidamente
<!-- qa-c71-sector-cases-20261010:end -->
<!-- qa18-credential-diagnosis-20261010:begin -->
**Atualização manual15:41UTC:** os pedidos15:38:38,15:39:04 e15:39:43UTC têm `email_exact_matches_qa18=true` e `password_matches_qa18=false`; POST/login302 → GET/login200, sem `login.id` nem utilizador autenticado. Primeiro ponto de falha agora identificado: validação da palavra-passe recebida, antes do MFA; não é rejeição do código, desencriptação ou perda após autenticação. A razão pela qual o valor enviado diverge não está demonstrada. A palavra-passe privada foi novamente conferida por READ ONLY às15:41:06UTC; hash e MFA válidos, conta inalterada. Rastreio sanitizado arquivado em `investor-credential-manual-rejection-20261010.json`. Preparado um auxiliar privado local com apenas a palavra-passe (sem JSON/aspas), ignorado pelo Git, para cópia direta; nenhum segredo publicado. Conector do navegador manual indisponível; completar a tentativa nesse navegador e manter C37 aberto.
## C73 — rejeição de credenciais QA18 reportada; diagnóstico renovado
@@ -85,12 +259,14 @@ Falhas do harness conservadas separadamente: primeira leitura usou indevidamente
<!-- qa18-credential-diagnosis-20261010:end -->
<!-- legacy-sector-heading-20261010:begin -->
## C72 — título original removido na projeção de Infraestruturas
**Requisitos:** AUD-LEG-02/07; P1 na expansão. **Reprodução:** aplicar `LegacyContent::sanitize()` ao HTML original do post171992, através de `tools/legacy-sector-content-check.php before`. **Esperado:** título “2. Sectores Prioritários de Investimento” preservado sem introduzir segundo h1 de página. **Observado:** título ausente; os restantes16 exemplares do lote não apresentavam essa perda. **Causa:** lista de apresentação não admitia h1 e removia o elemento com todos os filhos. **Correção preparada:** normalizar h1 interno para h2 e manter limpeza de atributos/filhos. **Prova:** verificação after sobre17 originais, hashes preservados, título presente e markup ativo removido; nenhum acesso à base. **Pendente:** importar o exemplar privado depois de C71, divulgar separadamente e demonstrar a página real. Não atualizar outros critérios da matriz com esta prova de transformação, nem declarar o setor publicado. C37/QA18 continua independente.
<!-- legacy-sector-heading-20261010:end -->
<!-- qa-legacy-browser-20261010:begin -->
## C70 — identificação errada no título do navegador
**Requisito:** AUD-LEG-02; P2. **Reprodução:** abrir anónimamente `/explorar/agronegocio` na QA 18097 e consultar o título do separador. **Esperado:** identidade do portal e distinção QA. **Observado:** “Explorar agronegócio - Laravel”. **Causa:** `resources/js/app.tsx` usa o nome padrão da compilação; a QA herdava `VITE_APP_NAME` do ambiente local. **Correção:** `vite.config.ts` define “InvesteMoz QA” exclusivamente sob `INVESTMOZ_QA_BUILD=1`; não altera .env nem build ativo. **Evidência:** título verificado no Chromium, percurso renderizado após recompilação; manifesto ativo inalterado. Código preparado eQA demonstrada; não ativado.
@@ -105,6 +281,7 @@ Referência técnica: [PostgreSQL17 — pg_db_role_setting](https://www.postgres
<!-- qa-legacy-browser-20261010:end -->
<!-- qa-legacy-20261010:begin -->
## Casos adicionais preservados — fontes e consumidor novo
- **C67 / OP04:** publicar a chamada de concessãoQA42 após aprovação. Esperado: projeção restrita persistida e legível. Observado inicial:HTTP503; rótulo de modalidade adicionado à síntese excedia coluna `summary` de 500 carateres. Causa no novo adaptador, não no middleware. Correção limita projeção a 499 + reticência e preserva texto canónico completo. Tentativa falhada arquivada; depois QA42–48 divulgadas/recuperadas noutra sessão MFA. Visual pendente.
@@ -115,6 +292,7 @@ Superutilizador27 recebeu403 em gestão documental, conforme autorização exist
<!-- qa-legacy-20261010:end -->
<!-- qa-response-20261010:begin -->
- **C65 / QA40:** §27 exige unicidade de número cadastral por oportunidade. Rascunho incompleto/duplicado permanece recuperável; submissão devolve 422 junto a `canonical.land_rights.parcels.1.cadastral_number`. Após correção, submissão aceite. Números ausentes não são inventados.
- **C66 / QA41:** `succession` constava no contrato original mas era recusada pela lista semântica de venda. Lista reconciliada; criação/edição, submissão e nova sessão demonstradas. Não alterar silenciosamente outras modalidades.
@@ -122,44 +300,48 @@ C65 foi identificado por confronto código/§27; C66 por divergência da lista d
<!-- qa-response-20261010:end -->
<!-- qa-installation-cartography-20261010:begin -->
## Casos adicionais deste lote — sem reiniciar o inventário
| Caso / requisito | Reprodução e resultado esperado | Observado, causa e correção | Prova / estado |
| --- | --- | --- | --- |
| C59 — PROFILE-31 / OPS-01 | Gestor confirmado com MFA consulta e aplica apenas 040000, após030000; repetir o mesmo pedido. Esperado:prévia, dependências e provas, uma instalação e um recibo, sem contas/grants automáticos. | A migração já tinha guarda, mas faltava rota/serviço/interface autenticados. Reutilizados Fortify, audit_events e cerimónia da dupla. Plano obsoleto/chave alterada409; falta de provas/dependência422; Auditor/Promotor403. | Testes de feature em schema vazio, repetição e bootstrap separados; servidor18097 já instalado:noop, replay idêntico, novaMFA e negações. Visual pendente. |
| C60 — PROFILE-31 / recuperação | Em base isolada e schema vazio, down→instalar; depois impedir insert na auditoria e instalar. Esperado:reversão total deDDL/ledger se não houver recibo; retry possível; nenhum drop com uso/histórico. | No desenvolvimento do incremento foi introduzida remoção duplicada da colunausers; o ensaio encontrou Undefined column. Corrigida. Também reforçado down para contexto/organização sem autor e revisões de sessão; falha de auditoria devolve503 e não deixa schema/ledger parcial. | Testes específicos de reinstalação e falha de auditoria; históricos/contextos conservados. Não executado down no servidorQA utilizado, nem no ativo. |
| C61 — OP-03 / publicação | Recuperar #30,#33,#32 e comparar estado da preparação, âmbito efetivo e catálogo. Esperado:restrito,público,aprovado sem disponibilização respetivamente. | Rótulo genérico “Publicado”/estado published não explicava o âmbito. Novo label/projeção consulta política efetiva do catálogo; botões distinguem disponibilização restrita de publicação pública. | JSON/Inertia e política pública verificados; nenhuma fuga pública observada. Perceção/ação visual pendente. |
| C62 — PROFILE-31 / bootstrap | Propor duas contas distintas e terceiro gestor; candidato com MFA cifrado ilegível ou Auditor. Esperado:recusa controlada e nenhum titular criado. | A cerimónia conferia presença/confirmaçãoMFA, sem comprovar leitura do segredo no ambiente. Agora exige cifragem válida/estruturaMFA e recusa Auditor, mesmo com flags ainda desabilitadas. Sem key:generate/fallback ou remoção deMFA. | Teste422 e dupla permanece vazia; inicialização positiva com identidades sintéticas distintas. Não substitui C37/login visual. |
| C63 — ambiente de testes / documental | Executar IndependentDocumentOperationsTest com o PHPCLI padrão. Esperado:GD disponível para gerar as imagens do ensaio. | Dois testes falharam por imagecreatetruecolor inexistente noCLI; o servidorQA já tinhaGD. Runner passa a carregar explicitamente a mesma extensãoGD para o processo de testes. | Regressão posterior27/600 semskips, scans reais e testes finais separados. Não atribuir esta falha ao servidorweb ou declarar GD ativo verificado. |
| C64 — PROFILE-31 / recuperação e proteção | Em schema isolado com perfis habilitados, retirar a coluna de revisão e tentar desativar MFA/excluir conta. Esperado:sem alteração de identidade, recuperação e logout acessíveis. | Esquema parcial podia tornar o serviço de perfis indisponível e deixar middleware de proteção passar à frente. Agora recusa escritas com503, preserva MFA/conta e deixa o instalador apresentar a incoerência409; logout permanece permitido. | Teste específico, schema parcial não aplicado ao servidorQA nem ao ativo. Preserva leitura permitida e não cria bypass de recuperação. |
| Caso / requisito | Reprodução e resultado esperado | Observado, causa e correção | Prova / estado |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| C59 — PROFILE-31 / OPS-01 | Gestor confirmado com MFA consulta e aplica apenas 040000, após030000; repetir o mesmo pedido. Esperado:prévia, dependências e provas, uma instalação e um recibo, sem contas/grants automáticos. | A migração já tinha guarda, mas faltava rota/serviço/interface autenticados. Reutilizados Fortify, audit_events e cerimónia da dupla. Plano obsoleto/chave alterada409; falta de provas/dependência422; Auditor/Promotor403. | Testes de feature em schema vazio, repetição e bootstrap separados; servidor18097 já instalado:noop, replay idêntico, novaMFA e negações. Visual pendente. |
| C60 — PROFILE-31 / recuperação | Em base isolada e schema vazio, down→instalar; depois impedir insert na auditoria e instalar. Esperado:reversão total deDDL/ledger se não houver recibo; retry possível; nenhum drop com uso/histórico. | No desenvolvimento do incremento foi introduzida remoção duplicada da colunausers; o ensaio encontrou Undefined column. Corrigida. Também reforçado down para contexto/organização sem autor e revisões de sessão; falha de auditoria devolve503 e não deixa schema/ledger parcial. | Testes específicos de reinstalação e falha de auditoria; históricos/contextos conservados. Não executado down no servidorQA utilizado, nem no ativo. |
| C61 — OP-03 / publicação | Recuperar #30,#33,#32 e comparar estado da preparação, âmbito efetivo e catálogo. Esperado:restrito,público,aprovado sem disponibilização respetivamente. | Rótulo genérico “Publicado”/estado published não explicava o âmbito. Novo label/projeção consulta política efetiva do catálogo; botões distinguem disponibilização restrita de publicação pública. | JSON/Inertia e política pública verificados; nenhuma fuga pública observada. Perceção/ação visual pendente. |
| C62 — PROFILE-31 / bootstrap | Propor duas contas distintas e terceiro gestor; candidato com MFA cifrado ilegível ou Auditor. Esperado:recusa controlada e nenhum titular criado. | A cerimónia conferia presença/confirmaçãoMFA, sem comprovar leitura do segredo no ambiente. Agora exige cifragem válida/estruturaMFA e recusa Auditor, mesmo com flags ainda desabilitadas. Sem key:generate/fallback ou remoção deMFA. | Teste422 e dupla permanece vazia; inicialização positiva com identidades sintéticas distintas. Não substitui C37/login visual. |
| C63 — ambiente de testes / documental | Executar IndependentDocumentOperationsTest com o PHPCLI padrão. Esperado:GD disponível para gerar as imagens do ensaio. | Dois testes falharam por imagecreatetruecolor inexistente noCLI; o servidorQA já tinhaGD. Runner passa a carregar explicitamente a mesma extensãoGD para o processo de testes. | Regressão posterior27/600 semskips, scans reais e testes finais separados. Não atribuir esta falha ao servidorweb ou declarar GD ativo verificado. |
| C64 — PROFILE-31 / recuperação e proteção | Em schema isolado com perfis habilitados, retirar a coluna de revisão e tentar desativar MFA/excluir conta. Esperado:sem alteração de identidade, recuperação e logout acessíveis. | Esquema parcial podia tornar o serviço de perfis indisponível e deixar middleware de proteção passar à frente. Agora recusa escritas com503, preserva MFA/conta e deixa o instalador apresentar a incoerência409; logout permanece permitido. | Teste específico, schema parcial não aplicado ao servidorQA nem ao ativo. Preserva leitura permitida e não cria bypass de recuperação. |
C55 continua corrigida por operação:PDF eagoraDOCX/XLSX excluídos dão404, scanpendente continua423; restore preserva original. C37/C43/QA21/A-B permanecempendentes. Cada prova mantém API/persistência/interface separadas.
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Reprodução e evidências adicionais — mesmo inventário
| Caso / requisito | Passos e esperado | Observado / causa | Correção e estado |
| --- | --- | --- | --- |
| C55 — OP-02 | QA21→PDF limpo→exclusão lógica→GETdownload. Esperado: recurso indisponível, sem atribuir falha de scan. Restaurar e recuperar original. | HTTP423/quarentena porque download juntava row inexistente à condição de scan. | Separa ausência/exclusão404 de quarentena423; teste específico e ensaioPDFweb18097. Originais/hash preservados; visualpendente. Prova da falha `opportunity-semantic-documents-http-qa-attempt1.json`. |
| C56 — OP-04/PROFILE-25 | Promotor21 abre editor de categoria; campos de núcleo devem ter um único valor/controlo e erros associados. | Revisão do código: formulário legado e contrato canónico duplicavam título/território/campos, com valores independentes. | Contrato canónico único no modo perfil; formulário legado continua na gestão própria. BuildQA/TS e payloadAPI; observação visualpendente. |
| C57 — OP-04/PROFILE-28 | Guardar fim anterior ao início/ciclo/serviços incompletos/documento estrangeiro/comunidade sem consulta/financeiros incompletos; recuperar noutra sessão; submeter. | Regras anteriores aceitavam objetos opacos sem semântica suficiente. | 12negativas422 com caminho de campo; rascunhos recuperados; seis cenários completos submetidos/revistos. Não extrapolar a regras jurídicas ainda sem âmbito/gate. |
| C58 — OP-03/PROFILE-19/12 | Parecer com destinatário técnico/jurídico; responder outro ator; aprovar pendente. Depois atribuir publicação e tentar outro Publicador. | Fluxo anterior não tinha destinatário/resposta/fila completa nem atribuição editorial. | #30destinatário29/resposta/tarefa;outro403/aprovação422; #33filaeditorial29/outro25publica403/designado29publica. Sem gateautoaprovado/prazofictício; visualpendente. |
| 190000 — OPS-01/PROFILE-31 | Comparar ledger/duascolunas/definição QA eativo, distinguir migraçãoBalcão07 depercurso09. | Plano anterior omitia recurso ainda ausenteativo. | 09/190000confirmadaQA e ausenteativo, necessária/nãosubstituída; seqüência autenticada recolocada. Nenhuma execuçãoativa. |
| Caso / requisito | Passos e esperado | Observado / causa | Correção e estado |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| C55 — OP-02 | QA21→PDF limpo→exclusão lógica→GETdownload. Esperado: recurso indisponível, sem atribuir falha de scan. Restaurar e recuperar original. | HTTP423/quarentena porque download juntava row inexistente à condição de scan. | Separa ausência/exclusão404 de quarentena423; teste específico e ensaioPDFweb18097. Originais/hash preservados; visualpendente. Prova da falha `opportunity-semantic-documents-http-qa-attempt1.json`. |
| C56 — OP-04/PROFILE-25 | Promotor21 abre editor de categoria; campos de núcleo devem ter um único valor/controlo e erros associados. | Revisão do código: formulário legado e contrato canónico duplicavam título/território/campos, com valores independentes. | Contrato canónico único no modo perfil; formulário legado continua na gestão própria. BuildQA/TS e payloadAPI; observação visualpendente. |
| C57 — OP-04/PROFILE-28 | Guardar fim anterior ao início/ciclo/serviços incompletos/documento estrangeiro/comunidade sem consulta/financeiros incompletos; recuperar noutra sessão; submeter. | Regras anteriores aceitavam objetos opacos sem semântica suficiente. | 12negativas422 com caminho de campo; rascunhos recuperados; seis cenários completos submetidos/revistos. Não extrapolar a regras jurídicas ainda sem âmbito/gate. |
| C58 — OP-03/PROFILE-19/12 | Parecer com destinatário técnico/jurídico; responder outro ator; aprovar pendente. Depois atribuir publicação e tentar outro Publicador. | Fluxo anterior não tinha destinatário/resposta/fila completa nem atribuição editorial. | #30destinatário29/resposta/tarefa;outro403/aprovação422; #33filaeditorial29/outro25publica403/designado29publica. Sem gateautoaprovado/prazofictício; visualpendente. |
| 190000 — OPS-01/PROFILE-31 | Comparar ledger/duascolunas/definição QA eativo, distinguir migraçãoBalcão07 depercurso09. | Plano anterior omitia recurso ainda ausenteativo. | 09/190000confirmadaQA e ausenteativo, necessária/nãosubstituída; seqüência autenticada recolocada. Nenhuma execuçãoativa. |
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Reproduções adicionais do incremento — 10/10/2026
| Caso / requisito | Reprodução e esperado | Falha ou risco encontrado / causa | Correção e evidência separada |
| --- | --- | --- | --- |
| C44 (complemento) — OP-04/PROFILE-28 | Guardar rascunho especializado parcial → completar → submeter; condições da categoria devem ser verificadas. | Submit permanecia bloqueado pelo contrato não integrado; a extração dos Create não conservava as condições `allOf` do schema original. | Adapter recupera condições, usa validação Draft2020-12 e recursos existentes. Dez rascunhos recuperados; seis submissões aceites/ quatro recusadas por perfil. Semântica integral e visual pendentes. |
| C50 — OP-04 | Imobiliário `sale`, `price:null`: guardar rascunho permitido, submeter recusado. | Campo nullable e `required` não garantiam preço positivo para venda. | Regra explícita positive; oportunidade19: draft aceite, submit422, preço corrigido e submit200. |
| C51 — PROFILE-25 | Após submissão, continuar pela visualização; edição deve ficar fechada. | Código da ação recarregava `/edit`, que passa corretamente a403 após submissão; o primeiro acesso HTTP Validador a essa rota confirmou a restrição, não uma falha de autorização. | Ações navegam `/view`; edição privada tem link apenas autorizado. API/props/build verificados; transição visível ainda pendente. |
| C52 — PROFILE-08/12/25 | Publicada → pedido de alteração → pesquisar título privado/estado → recuperar; ficha pública não pode mudar antes de aprovação. | Consulta/contagens usavam só título e estado públicos, ocultando a posição da proposta privada. | Consulta já autorizada usa estado/título de trabalho, preservando publicação. Teste específico do filtro/contagem e HTTP público19 original até suspensão. Visual pendente. |
| C53 — GEO-03/PROFILE-12 | Duas localizações, principal em segundo lugar → aprovar/publicar; território apresentado deve ser o principal. | Revisão de código encontrou uso da primeira posição da lista, que não define a principal. | Filtra `is_primary`; HTTP oportunidade28 apresenta ID/distrito principal correto. Teste específico isolado; mapa visual pendente. |
| C54 — PROFILE-19 | Revisão → correção → resubmeter; ou revisão → rejeitar. Esperado: tarefa anterior concluída, nova tarefa sem atribuição presumida. | Código mantinha revisão antiga aberta e podia herdar atribuição numa nova versão. | Conclui tarefas com motivo/histórico; limpa atribuição na submissão. HTTP28: correção/resubmissão/publicação/suspensão, nenhuma tarefa aberta ao final; HTTP29: rejeição fecha revisão. |
| C37 / C43 | Login investidor18; dashboard Promotor21 e ciclo de ações. | Não houve demonstração visual atual no navegador. | Mantidos pendentes, roteiro e conta preparados; não fechar por HTTP, props ou total de testes. |
| Caso / requisito | Reprodução e esperado | Falha ou risco encontrado / causa | Correção e evidência separada |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| C44 (complemento) — OP-04/PROFILE-28 | Guardar rascunho especializado parcial → completar → submeter; condições da categoria devem ser verificadas. | Submit permanecia bloqueado pelo contrato não integrado; a extração dos Create não conservava as condições `allOf` do schema original. | Adapter recupera condições, usa validação Draft2020-12 e recursos existentes. Dez rascunhos recuperados; seis submissões aceites/ quatro recusadas por perfil. Semântica integral e visual pendentes. |
| C50 — OP-04 | Imobiliário `sale`, `price:null`: guardar rascunho permitido, submeter recusado. | Campo nullable e `required` não garantiam preço positivo para venda. | Regra explícita positive; oportunidade19: draft aceite, submit422, preço corrigido e submit200. |
| C51 — PROFILE-25 | Após submissão, continuar pela visualização; edição deve ficar fechada. | Código da ação recarregava `/edit`, que passa corretamente a403 após submissão; o primeiro acesso HTTP Validador a essa rota confirmou a restrição, não uma falha de autorização. | Ações navegam `/view`; edição privada tem link apenas autorizado. API/props/build verificados; transição visível ainda pendente. |
| C52 — PROFILE-08/12/25 | Publicada → pedido de alteração → pesquisar título privado/estado → recuperar; ficha pública não pode mudar antes de aprovação. | Consulta/contagens usavam só título e estado públicos, ocultando a posição da proposta privada. | Consulta já autorizada usa estado/título de trabalho, preservando publicação. Teste específico do filtro/contagem e HTTP público19 original até suspensão. Visual pendente. |
| C53 — GEO-03/PROFILE-12 | Duas localizações, principal em segundo lugar → aprovar/publicar; território apresentado deve ser o principal. | Revisão de código encontrou uso da primeira posição da lista, que não define a principal. | Filtra `is_primary`; HTTP oportunidade28 apresenta ID/distrito principal correto. Teste específico isolado; mapa visual pendente. |
| C54 — PROFILE-19 | Revisão → correção → resubmeter; ou revisão → rejeitar. Esperado: tarefa anterior concluída, nova tarefa sem atribuição presumida. | Código mantinha revisão antiga aberta e podia herdar atribuição numa nova versão. | Conclui tarefas com motivo/histórico; limpa atribuição na submissão. HTTP28: correção/resubmissão/publicação/suspensão, nenhuma tarefa aberta ao final; HTTP29: rejeição fecha revisão. |
| C37 / C43 | Login investidor18; dashboard Promotor21 e ciclo de ações. | Não houve demonstração visual atual no navegador. | Mantidos pendentes, roteiro e conta preparados; não fechar por HTTP, props ou total de testes. |
Rejeições esperadas adicionais: motivo curto422, confirmação de publicação falsa422, hash de prévia errado409, self/multirole403, recurso pelo rejeitor/organização403, publicação fundiária com autorização externa pendente422. Provas privadas específicas preservam sequência/estado, sem segredos.
@@ -167,17 +349,18 @@ Rejeições esperadas adicionais: motivo curto422, confirmação de publicação
<!-- qa-workflow-20261010:end -->
<!-- qa-profiles-v1-20261010:begin -->
## Reproduções adicionais de perfis — 10/10/2026
C37 permanece pendente; não houve nova tentativa da conta 18 nem fecho visual. C43/C44 preservados.
| Caso / requisito | Reprodução | Esperado | Observado e causa | Correção/prova | Pendente |
| --- | --- | --- | --- | --- | --- |
| C45 — PROFILE-05/06/25, AUD-GEO-03 | Promotor 21: dashboard → Nova → seletor/mapa; comparar chamadas territoriais. | Perfil autorizado consulta, grava e recupera território/geometria. | Consumidor chamava rotas management reservadas a manage-portal. Inspeção de código/rotas; nenhuma captura visual anterior. | Alias autorizados reutilizam serviços: 11 províncias, Cabo Delgado guardada/recuperada, uma área API. profiles-v1-current-version-qa.json. | Desenho/cliques por perfil e restantes consumidores. |
| C46 — PROFILE-06/07/10/29 | Gestor sem perfil: API administrativa de contexto da oportunidade privada; território, prévia de origem e subjects. | Allowlist legada não revela/edita o privado v1. | Rotas auxiliares tinham apenas can:manage-portal, sem política do registo. Lacuna identificada em código, sem realizar escrita indevida. | Middleware cobre aliases/payload; subjects/dashboard/catalog usam âmbito. Testes 403/lista vazia. | Outras relações/filas e âmbito provincial. |
| C47 — PROFILE-04 | Rejeitar pedido com approved_types=[] e conferências false. | Rejeição fundamentada sem inventar conferência. | Ensaio respondeu 422: approved_types required rejeitava array vazio. | present|array; não-vazio só na aprovação; accepted_if só approved. Teste rejeita sem conceder e preserva conferência false; decisão própria 403. | Decisão na interface. |
| C48 — PROFILE-15/16/24/26 | Titular 30: DELETE MFA, DELETE conta, PATCH email. | Manter MFA obrigatório, dupla e histórico. | Regra específica da identidade privilegiada v1 não existia. Lacuna identificada em código; nunca se desativou MFA para ensaio. | ProtectPrivilegedIdentity, 403 e auditoria; recovery Fortify noutra sessão/reuse negado; trigger DELETE testado. | Visual e recuperação institucional de emergência. |
| C49 — PROFILE-10/29 | Conta sintética com papéis v1 e allowlist legada: abrir Nova legada, POST draft legado; depois escrita administrativa com Auditor. | Não contornar organização/tipo nem a restrição do Auditor pela acumulação. | Exceção legada podia autorizar escrita mais ampla. Identificada em código, sem usar conta ativa ou criar dados fora do âmbito. | Decisão documentada antes da correção; legacyWriteAllowed usa histórico; 403 na criação e escrita, atalho legado ausente nas props. Gestor sem atribuição v1 preservado. | Interface, conciliação dos gestores reais e consumidores restantes. |
| Caso / requisito | Reprodução | Esperado | Observado e causa | Correção/prova | Pendente |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| C45 — PROFILE-05/06/25, AUD-GEO-03 | Promotor 21: dashboard → Nova → seletor/mapa; comparar chamadas territoriais. | Perfil autorizado consulta, grava e recupera território/geometria. | Consumidor chamava rotas management reservadas a manage-portal. Inspeção de código/rotas; nenhuma captura visual anterior. | Alias autorizados reutilizam serviços: 11 províncias, Cabo Delgado guardada/recuperada, uma área API. profiles-v1-current-version-qa.json. | Desenho/cliques por perfil e restantes consumidores. |
| C46 — PROFILE-06/07/10/29 | Gestor sem perfil: API administrativa de contexto da oportunidade privada; território, prévia de origem e subjects. | Allowlist legada não revela/edita o privado v1. | Rotas auxiliares tinham apenas can:manage-portal, sem política do registo. Lacuna identificada em código, sem realizar escrita indevida. | Middleware cobre aliases/payload; subjects/dashboard/catalog usam âmbito. Testes 403/lista vazia. | Outras relações/filas e âmbito provincial. |
| C47 — PROFILE-04 | Rejeitar pedido com approved_types=[] e conferências false. | Rejeição fundamentada sem inventar conferência. | Ensaio respondeu 422: approved_types required rejeitava array vazio. | present | array; não-vazio só na aprovação; accepted_if só approved. Teste rejeita sem conceder e preserva conferência false; decisão própria 403. | Decisão na interface. |
| C48 — PROFILE-15/16/24/26 | Titular 30: DELETE MFA, DELETE conta, PATCH email. | Manter MFA obrigatório, dupla e histórico. | Regra específica da identidade privilegiada v1 não existia. Lacuna identificada em código; nunca se desativou MFA para ensaio. | ProtectPrivilegedIdentity, 403 e auditoria; recovery Fortify noutra sessão/reuse negado; trigger DELETE testado. | Visual e recuperação institucional de emergência. |
| C49 — PROFILE-10/29 | Conta sintética com papéis v1 e allowlist legada: abrir Nova legada, POST draft legado; depois escrita administrativa com Auditor. | Não contornar organização/tipo nem a restrição do Auditor pela acumulação. | Exceção legada podia autorizar escrita mais ampla. Identificada em código, sem usar conta ativa ou criar dados fora do âmbito. | Decisão documentada antes da correção; legacyWriteAllowed usa histórico; 403 na criação e escrita, atalho legado ausente nas props. Gestor sem atribuição v1 preservado. | Interface, conciliação dos gestores reais e consumidores restantes. |
Submissão real do rascunho 15 → 422 por contrato Create ausente é lacuna funcional mantida, não falha de MFA/autenticação. A fixture de revisão não demonstra submissão integral. Evidências por critério em profiles-v1-final-qa.xml, http-qa, recovery-audit, current-version e preservation; JSON/HTML não substitui interface.
@@ -186,6 +369,7 @@ Submissão real do rascunho 15 → 422 por contrato Create ausente é lacuna fun
> Registos anteriores preservados como histórico. Os estados correntes são os da matriz e do bloco mais recente acima; uma entrega posterior não altera retroativamente a evidência anterior.
<!-- qa-dashboard-20261010:begin -->
## Casos adicionais C43/C44 —10/10/2026
**C43 — causas encontradas no código/compilação:**(1)AppSidebar mostrava só o primeiro filho de cada grupo, descartando oportunidades; (2)menu Painel apontava /investidor mesmo para gestor; (3)dashboard de gestão colocava criação no fim como Criar oportunidade, sem rótulo Nova oportunidade. A secção de gestão só é devolvida pelo backend a contas verificadas em portal.managers; o seu ocultamento para investidor é autorização esperada, não motivo para conceder perfil administrativo.
@@ -210,6 +394,7 @@ C44, reprodução anterior por inspeção: categoriareal_estate disponível, mas
<!-- qa-dashboard-20261010:end -->
<!-- qa-independent-20261010:begin -->
## Casos adicionais do lote independente — 10/10/2026
### C38 — correspondências provinciais impediam descendentes; ambiguidade nominal bloqueava lote independente — P1
@@ -247,14 +432,14 @@ Durante a leitura de um script legado apareceram passwordsQA fixas. Correção i
O pedido de reabertura referia a conta esperada18. A captura manual21:22–21:24UTC demonstra que foi selecionada a conta13 restaurada. O MFA foi alcançado, mas a autenticação nunca se completou. Causa concreta: credenciais MFA da conta13 cifradas pela chave de origem, incompatíveis com a chave estávelQA; a conta18 sintética não foi desafiada nessa tentativa. Nenhuma chave, MFA ou conta13 foi alterada para contornar o problema.
| UTC09/10 | Pedido | Resultado observado |
|---|---|---|
|21:22:10|GET/investimentos|302/login; sessão convidada guardada, destino pretendido /investimentos.|
|21:22:11|GET/login|200; mesmo cookie/sessão, sem autenticação.|
|21:22:44|POST/login|302/two-factor-challenge; login.id=13, não18.|
|21:22:44|GET/two-factor-challenge|200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador.|
|21:23:04|POST/two-factor-challenge|Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada.|
|21:23:04|GET/login|200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado.|
| UTC09/10 | Pedido | Resultado observado |
| -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| 21:22:10 | GET/investimentos | 302/login; sessão convidada guardada, destino pretendido /investimentos. |
| 21:22:11 | GET/login | 200; mesmo cookie/sessão, sem autenticação. |
| 21:22:44 | POST/login | 302/two-factor-challenge; login.id=13, não18. |
| 21:22:44 | GET/two-factor-challenge | 200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador. |
| 21:23:04 | POST/two-factor-challenge | Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada. |
| 21:23:04 | GET/login | 200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado. |
Primeiro desvio do ensaio: POST/login desafia13. Primeira falha técnica: POST/two-factor-challenge às21:23:04 (trace ec68d040a3291cb8, referência26e15b04-07b8-4211-a2a0-7f70509e03f6). Não se tratou de código MFA rejeitado pelo verificador nem de perda após autenticação. Os dois campos cifrados (secret/recovery) são incompatíveis; como nenhum corpo foi retido, não se afirma qual modalidade de entrada foi usada nesta tentativa. Não foram observados conflitos de cookies, mudança de chave/guard ou redirecionamento para outra origem.
@@ -485,3 +670,102 @@ AUD-LIB-01/SCAN-01. Reprodução: upload privado, depois POST /management/portal
## C36 — original canónico cifrado devolve404 em consumidores — P0
AUD-LIB-01/SCAN-01/DESK-02. Reprodução QA: documents com storage_encryption=laravel, bytes originais/hash, scan ClamD real clean; GET /management/documents/{id}/download. Esperado200 com original íntegro; observado404 (encrypted-consumer-before-qa.xml). Causa: gestão/biblioteca/Balcão comparavam hash do ficheiro cifrado ao hash original. Corrigido VerifiedDocumentBinary partilhado: mantém guardas do consumidor, scan/hash, path privado e cifra; decifra só em memória e verifica plaintext, sem copiar para disco público. Teste real verifica gestão, associação ao Balcão sem novo documents, download e view PDF após classificação/publicação explícitas, bloqueio antes de publicação, bytes/MIME/CSP e adulteração404 em todos os consumidores. document-consumers-real-qa.xml distingue os três ensaios ClamD de consumidores/worker das fixtures de outros testes. Sem observação visual nem escrita ativa.
## C126 — contorno da autorização de anexos pela rota geral da biblioteca
- **Prioridade/estado:** P0 de confidencialidade; corrigido e demonstrado apenas em QA. Impede disponibilizar a candidata8af63e2fe657 sem esta correção. Não existe030000/040000 no ativo; não se extrapola a exploração para documentos de outro consumidor.
- **Operação/perfil:** gestão geral17, sem perfil/âmbito da oportunidade54; descarregar um original, imagem ou derivada por UUID.
- **Reprodução:** autenticar17 emQAHTTPS18445; GET`/minhas-oportunidades/54/resources/documents/a61f9a47-82a7-49cc-958e-edd115729333/download` devolve403; GET`/management/documents/8dd5731f-80dc-48a1-a307-a51e27769d0b/download` devolvia200/PDF para os mesmos bytes.
- **Esperado/observado:** ambas as rotas devem exigir a autorização vigente da oportunidade; só a primeira a exigia. Causa: rota geral aceitava manage-portal e VerifiedDocumentBinary conferia apenas scan/integridade/cifra.
- **Correção:** serviço comum resolve a relação existente com oportunidade e exige perfil/âmbito atual, recurso ativo e oportunidade não arquivada; originais/derivadas órfãos dessa origem falham fechados. URLs assinados conservam autenticação e autorização. Sem tabelas ou cadastros paralelos; classificação não é ACL.
- **Provas:** functional-document-alias-before/after-20261011.json; functional-document-boundary-chromium-20261011.json; functional-document-images-chromium-20261011.json. Ambos os URLs403 para17; Promotor21/Validador24/Publicador25 recuperam os três PDFs54pelos hashes; derivadas33protegidas e biblioteca29preservada. Concessão sintética32 e revogação por Superutilizador27: URL anterior recusado na sessão e após novo login, com auditoria. A retirada global anterior não foi usada como substituto desta revogação.
- **Limite:** não implementa conceder/revogar acesso a um destinatário individual por anexo. Partilha externa seletiva e restrição entre membros autorizados continuam indisponíveis e anunciadas na interface.
## C127 — Superutilizador administrativo com acesso operacional global a anexos
- **P0, apenas QA; fonte/cobertura:** a leitura do código anterior encontrou `canView` a devolver true para todo Superutilizador. Essa constatação é de código; não se apresenta como exploração observada no destino, que ainda não tem030000/040000. Contraria v1§345: elevação não substitui perfil operacional; administração não concede consulta universal.
- **Reprodução/esperado:** titular sintético15, sem âmbito, GET `/minhas-oportunidades/7/resources` e download próprio/genérico do PDF. Deve receber403; com papel funcional, ainda403 até outro titular aprovar elevação de consulta para7. Autoaprovação e acesso ao dossier8 devem continuar403.
- **Correção/evidência:** PortalProfileAccess/PortalSuperusers existentes: scope+elevação independente `view`, objeto e validade15min/MFA recente. Mesmo Super com Auditor não contorna a negação. Chromium:403→elevação aprovada200(hash)→outro dossier403; revogação invalida sessão, URL antigo e novo login403. Expiração/escopo/conflitos confirmados no teste afetado. `workflow-upgrade-document-pipeline-chromium-20261011.json`, `workflow-upgrade-policy-validity-20261011.xml`, UI/bundle final.
- **Limite:** não implementa ACL individual nem autoriza operação/administração universal. Provas de gestão de papéis não substituem decisão sobre titulares legítimos.
## C128 — repetição de processamento de imagem gerava novas derivadas
- **P1, achado de código corrigido emQA:** versão anterior gerava novosUUIDs/streams em cada execução com versão/etag atualizados, mesmo sem mudar o original. Não foi apresentado um ensaio HTTP «antes»; a causa está no laço incondicional de geração.
- **Reprodução/esperado:** após gerar e analisar uma imagem, recuperar etag/versão e voltar a preparar o mesmo original. Deve manter documentos, hashes, versão e decisões, sem duplicar.
- **Correção/prova:** reutilizar derivações coerentes com hash/larguras/bytes existentes; reenfileirar só scans pendentes. ImagemQA800×600: trêsWebP320/640/800, scans próprios reais; repetiçãoHTTP200 mantém IDs, versão, hashes/cifra e fila vazia. Teste afetado conserva contagem/documentos/versões/auditoria. `workflow-upgrade-document-pipeline-chromium-20261011.json` e teste de imagens em `workflow-upgrade-affected-20261011.xml`.
## C129 — primeiro contacto obrigatório sem percurso de cadastro na oportunidade
- **P1; requisito existente:** `OP-FIELD-opportunity-internal_contact_id`. Código ativo exige um UUID de contacto na submissão e confere a relação com o promotor. O editor só oferece seleção; CRM cria contactos pela conversão de um interesse com consentimento e edita contactos existentes. Leitura ativa de 12/10 encontrou zero contactos. Não se relata uma tentativa de submissão real que não ocorreu.
- **Reprodução:** com Promotor autorizado, guardar um rascunho e abrir `/minhas-oportunidades/{id}/edit`; a lista Contacto interno está vazia e não existe ação de criação. Um rascunho incompleto pode ser guardado, mas a submissão não pode satisfazer esse campo. Criar um pedido/lead fictício para preencher o cadastro seria um contorno indevido.
- **Correção apenas QA:** ação de cadastro no editor de um rascunho recuperado; `POST /minhas-oportunidades/{id}/contacts`, com permissão vigente de edição, MFA e etag. Reutiliza `contacts`, `investors`, `investor_contacts` e auditoria existentes, sem tabelas, organização duplicada, pedidos ou consentimentos fictícios. Nome/email/telefone E.164 declarados; se faltar a ficha CRM do promotor, a classificação é fornecida explicitamente e a ficha liga a organização já existente. Identidades/conflitos de email não são fundidos nem sobrescritos silenciosamente. Guardar contacto não publica nem decide a oportunidade; a seleção é gravada no rascunho pela ação existente.
- **Provas:** `outputs/investmoz-staff-preparation-20261012/contact-policy-qa.json`: recuperação, repetição, permissões 403, versão 409, conflitos/telefone 422. `contact-http-qa.json`: Fortify login/MFA sintéticos, cadastro, repetição com mesmo ID, gravação no rascunho 7, logout/nova sessão/recuperação e Validador 403. Sem códigos, segredos ou notificações nas evidências. TypeScript e compilação de produção do delta passam.
- **Limites:** demonstração visual do novo formulário pendente, pois o conector não disponibiliza browsers; HTTP não a substitui. Cargo do contacto previsto na especificação não tem coluna no cadastro atual e não se declara coberto. Não encerra o contrato normativo integral. Ativo inalterado, workflow OFF.
## C130 — sessão perdida com administração ativa e workflow desligado
- **P0 técnico; cobertura:** reproduzido em fixture de evento/política QA, com revisão de autorização maior que zero após atribuição. Não é exploração observada numa sessão real dos funcionários no destino, nem reabertura de C37/QA18.
- **Causa:** o listener Fortify `Login` vinculava `portal.access_revision` apenas quando `available()` (workflow ON); o middleware verifica essa revisão quando `governanceAvailable()` (administração ou workflow ON). Administração ON/workflow OFF deixa a nova sessão sem revisão e o middleware redireciona-a para `/login`.
- **Esperado/observado:** após login legítimo a revisão atual deve ficar vinculada também quando só administração está disponível. Antes: sessão sem vínculo, próxima passagem 302. Depois: 200 tanto com workflow OFF como ON; vínculo obsoleto continua recusado com 302.
- **Correção apenas QA:** usar `governanceAvailable()` no listener; sem alterar MFA, chaves, cifragem, guards ou regras operacionais. `session-gate-before.json` / `session-gate-after.json` em `outputs/investmoz-staff-preparation-20261012`. A prova é de evento/middleware; aceitação visual da combinação afetada mantém-se distinta. Nenhuma alteração ativa.
### Provas posteriores de C129/C130 — 12/10/2026
- **C129:** confirmação manual do responsável «o processo foi concluido» após o roteiro Promotor45/QA18118. O percurso positivo do formulário/contacto/rascunho7/logout/nova sessão/recuperação fica demonstrado; leitura independente recupera contacto criado10:46:41UTC, versão4 guardada10:52:54UTC e auditoria ator45. `manual-acceptance-20261012.json`/`manual-contact-readonly.json`. Erros de campo/repetição conservam evidência API distinta; cargo/contrato normativo integral permanece parcial. As notas anteriores sobre interface pendente são históricas.
- **C130:** além da fixture de evento, FortifyHTTP em servidor QA temporário18119/adminON/workflowOFF/revisão>0 passou login/MFA/perfil/refresh200, workflow404, revisão antiga302, nova sessão recuperada e logout protegido. `c130-http-governance-only-qa.json`. O login/MFA com workflowON foi confirmado manualmente no roteiro45; não se alega observação visual da combinaçãoOFF. Servidor de controlo encerrado; zero sessões reais afetadas. Não corresponde a ensaio no ativo nem reabertura de C37.
## C131 — normalização posterior à validação do contacto — P1 — 12/10/2026
- Requisitos: AUD-CRM-01, AUD-OP-02, AUD-PROFILE-28; não criar outro requisito por esta falha.
- Alvo: QA HTTPS 18445, stability_consumers_20261011_084534_test:55441, Promotor 21, rascunho 16. Código ativo usado como baseline **apenas nessa QA**.
- Reproduzir: `POST /minhas-oportunidades/16/contacts` com `full_name`=`Contacto`+146 espaços+`QA auditoria`, outros campos válidos/etag;166 caracteres antes,21 depois de normalizar.
- Esperado: validar a identidade normalizada e guardar/reutilizar um único contacto; mínimo 2/máximo 150 sobre o valor armazenado.
- Observado antes:422 full_name. No serviço direto, ` A ` passava e ficava com 1 caractere; esse ensaio foi revertido por transação. **HTTP já rejeitava o nome curto por TrimStrings**; não atribuir-lhe um bypass que não ocorreu.
- Causa: OpportunityContacts validava antes de compactar os espaços; regras e valor gravado discordavam.
- Corrigido QA: compactar nome e normalizar email antes do Validator, preservando contrato/permissões/MFA/etag/dedup. Nome válido 200, replayreused=true/mesmo UUID, logout/nova MFA/GET recupera contacto; conteúdo do draft anterior intacto. Nome curto/blank 422 emfixture revertida.
- Provas: outputs/investmoz-audit-current-20261012/contact-normalization-http.json e contact-whitespace-{before, after}.json. Sem segredo/cookie/código no recibo. Nenhuma alteração ativa; interface atual pendente. Não exige recompilação JS.
## C132 — diagnóstico Inertia com autorização irrestrita em local — P0 — 12/10/2026
- Requisitos: AUD-PROFILE-26/24, AUD-OPS-01; consumidor `/_inertia/devtools/entries` e detalhe/{id}, recorder de páginas Inertia.
- Leitura ativa:446 rotas, duas DevTools ausentes da QA normal; configuração sem `devtools.enabled`, biblioteca ativa por ambiente local. 448 ficheiros em storage/inertia-devtools apenas contados. A primeira inspeção limitou-se à contagem. **Suplemento de 12/10 18:40:45 UTC:** GET sem autenticação/cookies, TLS reconhecido, index 200 com 445 metadados; detalhe de um pedido de gestão 200 com objeto de utilizador autenticado, Cookie/XSRF e corpos. Não exportados os valores. A diferença para 448 ficheiros não é perda de dados comprovada: ficheiros e entradas do índice são unidades distintas e o repositório tem retenção/pruning próprios. Não foram examinados todos os detalhes.
- Reprodução isolada: na QA 18445, alterar temporariamente apenas APP_ENV para local, sem tocar chave/schema/dados; GETanónimoàlistagem retorna 200(arrayvazio no ensaio). Isto demonstra a autorização da listagem, não exfiltração de dados ativos.
- Esperado: portal não disponibiliza diagnósticos internos a utilizadores anónimos/sem autorização.
- Causa: InertiaDevTools:: enabled usa local por omissão e middleware Authorize autoriza local antes de consultar Gate. Registo HTTP/props é partilhado pelo repositório da aplicação; propriedade/roles empresariais não delimitam esse acesso.
- Correção QA: config/inertia.php define `devtools.enabled=false` explicitamente; listagem/detalhe 404 mesmo APP_ENV=local. Login/MFA 21, dashboard, edit 16/view 30 continuam 200. Ambiente QA restaurado byte a byte; configuração ativa inalterada.
- Provas: outputs/investmoz-audit-current-20261012/devtools-isolation-http.json e C132-active-readonly.json. Correção permanece apenas QA, ativo exposto. Nenhum corpo/valor de cookie/código/segredo guardado. Provas HTTP/configuração; não declarar nova inspeção visual. Não remover diagnósticos históricos ativos automaticamente.
## Casos adicionais do lote independente 12 outubro
**C133 (P1; AUD-COUNTRY-03/04, AUD-STATS-01, AUD-FIELD-014).** Reproduzir na QA18445: manifesto de negócio com país anterior Moçambique e origem BR → guardar → gestão recupera o pedido → filtrar country=MZ/origin=BR. Esperado: recuperar o mesmo pedido, preservando os valores anteriores. Observado antes: zero resultados no filtro, embora leitura individual e origem funcionassem. Causa: PortalManagementController comparava country apenas com o código ISO. Correção exclusivamente QA: CountryCatalogue.filterValues fornece código e nomes PT/EN exatos do catálogo com correspondência única; query case-insensitive/trim, sem reescrita nem inferência de origem. Após: um resultado, recuperação noutra sessão, PT exclui, replay não aumenta contagem e SQL confirma um recibo/evento/consentimento. Anúncio sintético publicado para ensaio não comprova workflow de publicação. Provas business-country-before.json, business-country-after.json, business-country-variants.json, business-country-persistence.json, country-filter-QA-delta.json. Visual pendente; ativo não alterado.
**C134 (P1; AUD-FIELD-014, AUD-UI-01).** API de manifestação devolve422 com erros country/declared_origin_country_code; no componente existente, branch de erro apenas lançava data.message e ignorava data.errors. Esperado: erros adjacentes a cada campo e foco acessível, com dados/chave preservados para corrigir. Identificação por revisão de código e contrato API; reprodução visual ainda não realizada porque o conector está indisponível. Correção QA liga os erros, id/aria-invalid/aria-describedby e foco; reutiliza error/id do CountrySelect. TypeScript e build passaram, recursos servidos por HTTPS/hashes. Esta evidência demonstra preparação/compilação, não execução visual do foco. Provas business-feedback-QA-delta.json, business-feedback-build-QA.json, business-feedback-assets.json, business-country-variants.json. Ativo não alterado.
**C135 (impedimento de verificação, AUD-UI-01; separado de falhas do portal).** Reproduzir pelo inventário suportado: sky.list_apps falha antes de selecionar app/janela com pipe nativo ausente/os error2; cua.getState devolve apps/browsers vazios;12 processos do Chromium1243 continuam em execução. Esperado: inventário com janela/tab QA para inspeção. Observado: transporte IPC indisponível. Causa específica da ponte/processo além do IPC ausente não estabelecida; não afirmar falha do Chrome. Não se reiniciou infraestrutura ativa nem se contornou protocolo ou se transferiram ensaios repetidos ao utilizador. Próximo diagnóstico: repor conector no host e obter inventário QA. Evidência connector-diagnosis-C135.json; todos os critérios visuais novos permanecem abertos.
**C136 (P1; AUD-OP-03/04, AUD-PROFILE-28).** Em QA, aprovar franquia com taxa inicial1000, solicitar revisão, alterar para1250 e resubmeter. Esperado: parecer financeiro deixa de autorizar a versão alterada, revendo somente âmbitos afetados. Antes: financial_review conservado, porque projeção v3 não incluía initial_fee/royalties; só marca/licença/legal reabriam. Correção exclusiva QA: projeção v4 adiciona os dois campos existentes no gate financeiro; v2/v3 continuam com seus algoritmos/hashes. Após: HTTP da oportunidade sintética56 reabre brand_license_review/financial_review/franchise_legal_review, conserva confidentiality_clearance/hash/ator/data, nega autoaprovação403 e aprovação antes dos pareceres422;24 revê/reaprova e25 disponibiliza com visibilidade interna; recuperação noutra sessão mantém1250. Royalties aprovado apenas na regressão do serviço; UI e catálogo público não demonstrados por este lote. PHP-only, sem recompilação nem alteração ativa. Fonte anterior preservada. Evidências franchise-materiality-before/after.json, workflow-franchise-materiality/finish-HTTP.json, consumer-lot-final-SQL.json.
**C137 (P1; AUD-PART-01/AUD-UI-01).** Preparar salaQA com documento do autor explicitamente partilhado e scaneado; cancelar a sala. Esperado: autor conserva a ação de retirar a autorização e contraparte perde acesso após retirada; nova autorização continua proibida na sala encerrada. Contrato/API: retirada200, sessão antiga/nova404, autor200/hash, regrant409. Observado no componente: mutable=false em closed/cancelled e a mesma guarda envolve o botão de autorizar/retirar, ocultando retirada válida. Reprodução/aceitação visual pendentes porC135; não declaradas observadas. Causa: guarda de edição da sala aplicada à retirada da partilha. CorreçãoQA: dono pode retirar quando d.shared=true, mesmo semmutable; não pode autorizar quando encerrada. Mensagem explica ambos. Types/build159passaram e chunkHTTP/hashconferido. Fontes/manifesto anterior preservados; ativo intacto. Provas C137-QA-delta.json, C137-build-QA.json, next-lot-final-proof.json, partnership-revocation-closed-room-revocation-HTTP.json.
**C135 seguimento:** resetnode_repl/sky e resetcua_repl não recuperaram nativepipe/provider. Listagem continuaerro2 e inventário vazio. IABindisponível. Não foi encontrada/reparada causa específica nohost através das APIsexpostas. A recuperação suporta reset do cliente; a skill proíbe executar/procurarhelperexeou criar protocolo próprio. Não houve reinício/alteração do portal ou transferência de testes ao utilizador. Prova connector-C135-reset-diagnosis.json.
**C138 (P1; AUD-COUNTRY-03/04, AUD-STATS-01).** QA18445: criar rascunho fundiário, guardar paísPortugal/origemBR, enviar apoio202 e repetir a mesma versão/payload. Esperado: recuperar o mesmo recibo sem gravação repetida. Observado:409na guarda de estado support_requested, antes de InterestSubmission. CorreçãoQA reutiliza serviço/chave estáveis, valida equivalência/versão/titularidade e devolve o mesmo caso202sem revisão/evento novos. Payload alterado409, não titular404/anónimo401. SQL1caso/recibo/consentimento/outbox/evento; dados recuperados. Provas option-B-land-country-before/after-HTTP.json, option-B-land-statistics-HTTP.json, option-B-final-SQL.json. Visual pendenteC135, ativo não corrigido por este lote.
**C139 (P1; AUD-OP-01/03/04, AUD-UI-01).** QA18445: GET /api/v1/investment/search?maturity_level=7 e8 retornava422; filtro/labels ainda seis e publicação não projetava etapa canónica aprovada. Esperado: aceitar8etapas sem reinterpretar catálogo histórico, guardar/aprovar/publicar/recuperar nível/rótulo/versão corretos. CorreçãoQA em catálogo/publicação/modelo/interfaces usa constantes existentes, conserva valores públicos prévios no histórico e expõe só metadado da versão publicada.33passou7 e8por revisão/aprovação24/publicação pública25; busca/ficha/nova sessão coincidem, privados ocultos, limites0/9recusados. Provas option-B-C139-before-HTTP.json, option-B-public-maturity-workflow-HTTP.json, option-B-build-QA.json. Semântica dos dois catálogos preservada; filtro por posição explicitado. Visual pendenteC135, ativo não alterado.
## C140 — P1: unidade da parcela rejeitada no contrato QA
Reprodução: Promotor QA21, caso 32 emcorreção; guardar `canonical.land_rights.parcels[0].area_unit=ha`. Esperado: unidade do catálogo existente aceite, preservando área/geometry/UUID. Observado:422 schema sem essa propriedade. Causa: parcelCreate não tinha unidade. Correção QA: campo opcional do adaptador, enum compartilhado `sqm/ha/sqkm`, rótulo/ajuda; não atribui unidade a versões antigas nem converte valores. HTTP antes/depois, unidadeha→sqm, revisão cadastral exclusiva, 24/25/nova sessão/Response. UI pendente C135; §27 integral continuafalse. Provas `option-B2-area-unit-before/after-HTTP.json`, `option-B2-response-read-HTTP.json`.
## C141 — P1: submissão aceitava medição inconsistente da localização
Reprodução QA isolada: localização de 32 com área sem unidade ou unidade sem valor; validação da submissão aceitava ambos. Esperado: poder guardar e recuperar preparação incompleta, exigir o par ao submeter. Causa: validateSubmission não conferia area_value/area_unit do recurso ligado. Correção: conferência na submissão reutiliza catálogo existente; drafts continuam guardáveis. HTTP: guardar 200/recuperar→submeter 422 com campo→completarpar→replay 409 semduplicar→reverificargates/condição→24 aprova/25 publicarestrito→novasessão. Originais/IDs/história intactos; UIpendente. Provas `option-B2-submission-area-before/after.json`, `option-B2-area-draft-submission-HTTP.json`, `option-B2-final-QA.json`.
A validação inicialmente ensaiada no próprio save de recurso foi ajustada antes do lote final para respeitar rascunhos incompletos. Os 422 de resource_area_pair_HTTP no recibo intermediário C140 são históricos/supersedidos; C141 final guarda incompleto 200 e bloqueia apenas submissão. Não usar aquele trecho intermediário para descrever o estado atual.
@@ -1,24 +1,25 @@
# Cobertura por percurso e consumidor — continuação QA
<!-- qa-semantic-20261010:begin -->
## Resultado atual por categoria — semântica e atribuições em QA, 10/10/2026
Este bloco é a evidência mais recente desta matriz; as secções anteriores abaixo permanecem como histórico. Estados antigos sobre objetos opacos, coordenação editorial e ausência de 190000 ficam confrontados com os resultados concretos deste bloco. **Código preparado e HTTP/persistência em QA não encerram interface nem funcionalidade ativa.** Não houve escrita na base ativa. C37 e aceitação visual permanecem pendentes.
Servidor **http://127.0.0.1:18097**, base **desk_restore_20261009_174726_test:55441**, Fortify e MFA normais. **Promotor QA 21** continua a conta de ensaio do dashboard. Não usar Auditor ou Superutilizador em seu lugar.
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| --- | --- | --- | --- | --- | --- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| ------------------------- | -------------------------------- | ------------------------------- | ------------------------------- | ------------------------- | --------------------------------------------- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
As dez categorias recuperaram dados noutra sessão autenticada. As seis com contrato definido aceitaram os cenários semânticos documentados; as quatro restantes conservaram rascunhos, sem inventar um perfil modular para as submeter. Fundiário #32 separa aprovação interna da decisão externa. Venda #33 passou depois pelo percurso editorial público, sem divulgar resumo/dados privados.
@@ -36,40 +37,41 @@ As dez categorias recuperaram dados noutra sessão autenticada. As seis com cont
Mesma matriz: **3.386 requisitos / 3.386 linhas**, **6.838 ocorrências de origem**. IDs, fontes, critérios, versões divergentes e referências anteriores conservados.
| Estado canónico | Requisitos | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências de origem |
| ------------------------------- | ---------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31 e AUD-OPS-01**, em [matriz-requisitos.csv](matriz-requisitos.csv). Nenhum desses critérios visuais foi fechado por API.
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Incremento canónico e workflow em QA — 10/10/2026
Servidor **http://127.0.0.1:18097**; destino guardado **desk_restore_20261009_174726_test:55441**. Zero escritas na base ativa. **C37 e toda a aceitação visual deste incremento permanecem pendentes.** Props da interface, API e persistência foram verificadas; nenhum clique ou renderização no navegador foi observado.
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --- | --- | --- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
Os requisitos acima continuam **parciais**: nenhum passou a concluído pelo incremento. O detalhe está no [relatório do workflow](workflow-oportunidades-qa.md); fontes, versões, critérios e percursos permanecem na [mesma matriz](matriz-requisitos.csv).
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| ------------------------------ | ----------------------------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requisitos abertos**. As referências e versões anteriores foram preservadas.
@@ -77,6 +79,7 @@ Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requ
<!-- qa-workflow-20261010:end -->
<!-- qa-profiles-v1-20261010:begin -->
## Cobertura após perfis v1 — 10/10/2026
I0–I3 permanecem em QA. Cinco fases e 19 etapas preservadas, sem renumeração. C37, A/B e C43 visuais continuam pendentes. A autorização organizacional reutiliza OpportunityManagement, Resources, Fortify e entidades existentes; nenhuma jornada educativa nova foi iniciada.
@@ -94,6 +97,7 @@ Coordenadores, pareceristas, suporte e recurso estão explicitamente mapeados na
> Registos anteriores preservados como histórico. Os estados correntes são os da matriz e do bloco mais recente acima; uma entrega posterior não altera retroativamente a evidência anterior.
<!-- qa-dashboard-20261010:begin -->
## Cobertura adicional: dashboard e draft imobiliário —10/10/2026
- `dashboard-active-readonly.json`: configuração/contas elegíveis/instalação/manifesto ativo, sem boot HTTP/escrita de sessão no ativo.
@@ -110,6 +114,7 @@ Gestão desde/dashboard: API/destinos reais/gravação/novasessão/recuperação
<!-- qa-dashboard-20261010:end -->
<!-- qa-independent-20261010:begin -->
## Evidência independente por consumidor — 10/10/2026
QA web desk_restore_20261009_174726_test:55441 e ensaios separados investmoz_test:55441. C37/login investidor e A/B visuais continuam pendentes. Nenhuma sessão de navegador foi certificada; a nova autenticação HTTP deste lote foi do gestor cartográficoQA, distinta do investidor18.
@@ -118,17 +123,17 @@ QA web desk_restore_20261009_174726_test:55441 e ensaios separados investmoz_tes
**Cartografia — três estados:** cadastro 1920 referências/1990 geo_locations incluindo70países; geometria administrativa393/581da edição 2019; apresentação renderizada não verificada. geometry-crosswalk-consumers-http-qa.json recupera 32 novos limites por endpoint gestor e 0 públicos, nomes guardados de ambas as províncias Maputo correspondem a um IDúnico. geometry-consumers-path-qa.json recupera393por serviço. ProvinceSelect partilhado liga este IDao preview e conserva texto antigo desconhecido; isso prepara PortalInvestidor/portal-services/AI, sem alegar resultado visual individual. TerritoryFields/territory-preview/MapaBolsa/InvestmentMapPanel existentes reutilizados. Localidade pode ter contexto ancestral, nunca polígono próprio inferido. Correspondências0/31/157 pendentes; todas188nominais no relatório.
| Consumidor/tipo | Prova de operação/perfil/persistência | Limite da prova |
| --- | --- | --- |
| Fundiário PDF |Upload privado→quarentena404→ClamDreal/hash→owner200→original canónico cifrado recuperado por bytes; outro/manager404; GETestado; impressão props200; tamper404; leitura auditada.|IndependentDocumentOperationsTest, iterador próprioPDF; não PDFrenderizado/browser18097.|
| Fundiário PNG |Mesmo percurso, iteradorPNGreal; bytes/hash/scan próprios e size_bytes/uploaded_by.|Não prova renderização visual.|
| Fundiário JPEG |Mesmo percurso, iteradorJPEGreal; bytes/hash/scan próprios e permissões.|Não prova qualquer conversão/derivada não executada.|
| Sala parceria PDF |Autor200/candidato404→partilha autoria persistida→candidato200→novo contexto auth/GETlista→revogação404; candidato não partilha403; gestor/estranho403; scan originalreal/tamper404.|Método próprio com iteradorPDF; novo contexto de autenticação em teste, não sessão nova de navegador.|
| Sala parceria PNG |Mesmo percurso, iteradorPNGreal, partilha/revogação/eventos próprios, original cifrado preservado.|Interface da sala pendente.|
| Sala parceria JPEG |Mesmo percurso, iteradorJPEGreal, original/hash/scan próprios.|Não certifica acordo jurídico externo nem todos os anexos existentes.|
| Lote biblioteca PDF |ImportDocumentBatchTest::test_qa_batch_real_scan_preserves_original_replay_identity_conflict_and_profile_guards: actorQAsem permissão/ambiente ativo recusados; bytes duplicados→um original privado; ClamDreal; gestor200/público 404; replay 0 novos; conflito mesma identidade/bytes diferentes não substitui original.|CLIQA, não mecanismo autenticado de aplicação ativa. Dois testes antigos do ficheiro usam fixture/Busfake.|
| Oportunidades PDF/PNG/3WebP |resources-real-http-qa.json renovado: novo PDF válido→upload/scan/download/logout/nova sessão/403outra conta. resource-originals-preservation-http-qa.json preserva5binários anteriores e confirma uma página do novo PDF baixado; PNG/3WebP assinados recuperados.|Novo scan real somente do novo PDF; scans das derivadas anteriores conservados. Nenhum ensaio visual.|
| Biblioteca/Balcão |document-consumers-real-qa.xml e provas anteriores de bytes/MIME/CSP/scan/perfil conservadas; ensaio de loteQA deste lote separado.|PDFview bytes/CSP não é renderização, nem demonstra validade de todos os fixtures antigos.|
| Consumidor/tipo | Prova de operação/perfil/persistência | Limite da prova |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Fundiário PDF | Upload privado→quarentena404→ClamDreal/hash→owner200→original canónico cifrado recuperado por bytes; outro/manager404; GETestado; impressão props200; tamper404; leitura auditada. | IndependentDocumentOperationsTest, iterador próprioPDF; não PDFrenderizado/browser18097. |
| Fundiário PNG | Mesmo percurso, iteradorPNGreal; bytes/hash/scan próprios e size_bytes/uploaded_by. | Não prova renderização visual. |
| Fundiário JPEG | Mesmo percurso, iteradorJPEGreal; bytes/hash/scan próprios e permissões. | Não prova qualquer conversão/derivada não executada. |
| Sala parceria PDF | Autor200/candidato404→partilha autoria persistida→candidato200→novo contexto auth/GETlista→revogação404; candidato não partilha403; gestor/estranho403; scan originalreal/tamper404. | Método próprio com iteradorPDF; novo contexto de autenticação em teste, não sessão nova de navegador. |
| Sala parceria PNG | Mesmo percurso, iteradorPNGreal, partilha/revogação/eventos próprios, original cifrado preservado. | Interface da sala pendente. |
| Sala parceria JPEG | Mesmo percurso, iteradorJPEGreal, original/hash/scan próprios. | Não certifica acordo jurídico externo nem todos os anexos existentes. |
| Lote biblioteca PDF | ImportDocumentBatchTest::test_qa_batch_real_scan_preserves_original_replay_identity_conflict_and_profile_guards: actorQAsem permissão/ambiente ativo recusados; bytes duplicados→um original privado; ClamDreal; gestor200/público 404; replay 0 novos; conflito mesma identidade/bytes diferentes não substitui original. | CLIQA, não mecanismo autenticado de aplicação ativa. Dois testes antigos do ficheiro usam fixture/Busfake. |
| Oportunidades PDF/PNG/3WebP | resources-real-http-qa.json renovado: novo PDF válido→upload/scan/download/logout/nova sessão/403outra conta. resource-originals-preservation-http-qa.json preserva5binários anteriores e confirma uma página do novo PDF baixado; PNG/3WebP assinados recuperados. | Novo scan real somente do novo PDF; scans das derivadas anteriores conservados. Nenhum ensaio visual. |
| Biblioteca/Balcão | document-consumers-real-qa.xml e provas anteriores de bytes/MIME/CSP/scan/perfil conservadas; ensaio de loteQA deste lote separado. | PDFview bytes/CSP não é renderização, nem demonstra validade de todos os fixtures antigos. |
Fundiário e parceria agora reutilizam VerifiedDocumentBinary, sem relaxar permissões nem duplicar documents. Nenhum original foi convertido em cópia pública; novos uploads registam autor/tamanho. Document-independent-qa.xml e document-batch-independent-qa.xml distinguem scanner real de fixture. Arranque permanente ClamD/assinaturas/GDativo permanecem separados das operações demonstradas.
@@ -138,7 +143,6 @@ Fundiário e parceria agora reutilizam VerifiedDocumentBinary, sem relaxar permi
Workflow/contratos:110defs/9 contratos normativos preparados, runtime_validation_implemented=false/workflow_implemented=false/qa_activation=false; não existe percurso completo novo a certificar. Roteiros 19 etapas/5fases conservados. Provas e contagens da matriz em relatorio-executivo.md.
**Versões anteriores preservadas:** as secções abaixo documentam os instantes anteriores. 361 e2/39/179 são a baseline 09/10; o estado cartográfico corrente deste lote é393 e0/31/157. Ready/hashes/contagens antigas não certificam esta revisão. C37 mantém a sua confirmação visual pendente, sem bloquear as frentes independentes.
<!-- qa-independent-20261010:end -->
@@ -162,12 +166,12 @@ Evidências: mfa-key-diagnosis-qa.json, mfa-session-invalidation-qa.json, mfa-pe
**Mesma matriz:**3354 requisitos/linhas canónicas,5830 ocorrências preservadas; parcial: 3198 requisitos/5380 ocorrências; não implementado: 146 requisitos/440 ocorrências; dependente de decisão concreta: 4 requisitos/4 ocorrências; implementado mas não ativado: 1 requisitos/1 ocorrências; concluído e demonstrado: 5 requisitos/5 ocorrências. Nenhum requisito amplo fechado por este lote. `candidate_revision_fixed=false`, `integrated_ui_ab_passed=false`, `activation_ready=false`; não fixar candidata antes dos resultados manuais e correções.
| Requisito | Correção/prova concreta deste lote | Estado |
| --- | --- | --- |
| AUD-GEO-02/03, OPS-01 | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`. Fontes retidas/edição/hash/scan; nomes exatos+pai+país, conflitos, preview vinculado ao ator/estado, MFA, `geo_write_receipts`, `audit_events` append-only; nada publicado. HTTP real com login+TOTP, três níveis,361 reutilizadas/0 novas; replay e reversão de lote de reutilização mantêm361. QA de testes demonstra criação e reversão de lote novo, preservação de histórico e recusas de alteração/publicação/FK/scan expirado/MFA/alvo não QA. | Código preparado + API/persistência QA; interface e ativo pendentes |
| AUD-SCAN-01 | C31: nome da rota assinada corrigido para `management.opportunity-image-preview`, mantendo URL. Servidor web QA gera3WebP320/640/1280; PDF+PNG+3derivadas têm cinco scans reais ClamAV1.5.4, clean/hash próprios, cifragem Laravel e classificação restricted; downloads reais comparados, assinaturas ausentes403 e outra conta403. QA de testes prova quarentena423, scanner inconclusivo e retry real, substituição sem apagar original, versão409, exclusão/restauro e adulteração409. | Operações de oportunidades demonstradas por API/persistência; apresentação visual pendente |
| AUD-LIB-01/SCAN-01/DESK-02 | C35 corrigiu erro500 ao omitir data/emissor opcionais. C36 corrigiu recuperação404 de originais cifrados: os consumidores comparavam o hash do ciphertext com o original. VerifiedDocumentBinary reutiliza decifragem/integridade sem cópia pública nem alteração de permissões. PortalRealDocumentConsumersTest usa ClamD real: biblioteca privada→scan→classificação→publicação separada→download; versão409/dedup/404hash. Balcão testa upload/confidential→scan→download, dedup/403estranho. Original canónico cifrado é reutilizado sem duplicar documents; downloads na gestão/Balcão/biblioteca e view PDF devolvem os bytes originais; antes de publicação/adulteração404. | API/persistência QA; bytes de preview PDF verificados, renderização visual pendente; sem publicação ativa nem fecho global |
| AUD-UI-01/DASH-01/SIM-01/DESK-02/GUIDE-01/CRM-01 | A/B repetidos por HTTP no servidor recuperado; nova sessão real, IDs/drafts próprios, recuperação, aplicabilidade, resultado20/0 e20/70000, Balcão e tarefa concluída enquanto terra aguarda; outra conta/contexto recusados. | API/persistência QA; cenários completos na interface pendentes |
| Requisito | Correção/prova concreta deste lote | Estado |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| AUD-GEO-02/03, OPS-01 | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`. Fontes retidas/edição/hash/scan; nomes exatos+pai+país, conflitos, preview vinculado ao ator/estado, MFA, `geo_write_receipts`, `audit_events` append-only; nada publicado. HTTP real com login+TOTP, três níveis,361 reutilizadas/0 novas; replay e reversão de lote de reutilização mantêm361. QA de testes demonstra criação e reversão de lote novo, preservação de histórico e recusas de alteração/publicação/FK/scan expirado/MFA/alvo não QA. | Código preparado + API/persistência QA; interface e ativo pendentes |
| AUD-SCAN-01 | C31: nome da rota assinada corrigido para `management.opportunity-image-preview`, mantendo URL. Servidor web QA gera3WebP320/640/1280; PDF+PNG+3derivadas têm cinco scans reais ClamAV1.5.4, clean/hash próprios, cifragem Laravel e classificação restricted; downloads reais comparados, assinaturas ausentes403 e outra conta403. QA de testes prova quarentena423, scanner inconclusivo e retry real, substituição sem apagar original, versão409, exclusão/restauro e adulteração409. | Operações de oportunidades demonstradas por API/persistência; apresentação visual pendente |
| AUD-LIB-01/SCAN-01/DESK-02 | C35 corrigiu erro500 ao omitir data/emissor opcionais. C36 corrigiu recuperação404 de originais cifrados: os consumidores comparavam o hash do ciphertext com o original. VerifiedDocumentBinary reutiliza decifragem/integridade sem cópia pública nem alteração de permissões. PortalRealDocumentConsumersTest usa ClamD real: biblioteca privada→scan→classificação→publicação separada→download; versão409/dedup/404hash. Balcão testa upload/confidential→scan→download, dedup/403estranho. Original canónico cifrado é reutilizado sem duplicar documents; downloads na gestão/Balcão/biblioteca e view PDF devolvem os bytes originais; antes de publicação/adulteração404. | API/persistência QA; bytes de preview PDF verificados, renderização visual pendente; sem publicação ativa nem fecho global |
| AUD-UI-01/DASH-01/SIM-01/DESK-02/GUIDE-01/CRM-01 | A/B repetidos por HTTP no servidor recuperado; nova sessão real, IDs/drafts próprios, recuperação, aplicabilidade, resultado20/0 e20/70000, Balcão e tarefa concluída enquanto terra aguarda; outra conta/contexto recusados. | API/persistência QA; cenários completos na interface pendentes |
**Correspondências:** províncias11→9/2; distritos159→120/39; postos411→232/179. Esperado refere o exemplar2019, não um cadastro atual certificado. Maputo e Maputo City são as duas pendências provinciais. Distritos:9 por pai não resolvido/30 por nome; postos:86 por pai/93 por nome. [Todas220 lacunas por nome/código/pai/causa](correspondencias-cartograficas.md). Sem polígonos de localidades no exemplar; nenhum limite equivale a implantação/DUAT. Aceitação da fonte oficial preservada.
@@ -187,24 +191,24 @@ Os resultados apresentados no dossier são estimativas recalculadas pelas fórmu
## Países/origem/estatísticas, formulário a formulário
| Formulário/consumidor | Evidência específica em QA | Critério ainda pendente |
| --- | --- | --- |
| Manifestação pública `/` e `/manifestar-interesse` | `PortalAuditContinuationTest::test_public_country_and_origin_survive_api_storage_management_recovery_and_statistics`:249 países nos props, PT/ZA separados, 422 inválido sem escrita, replay único, metadata/GET gestor e agregado/filtro CRM ZA=1/PT=0 | Seleção, mensagem/recibo e filtros renderizados em ambas as páginas |
| Apoio support | `test_support_kinds_keep_iso_country_separate_and_legacy_text_unchanged`: POST próprio, recuperação detalhe PT/ZA, filtro PT/ZA e delta+1 interests, origem PT=0 | Formulário/recibo/tabela visíveis |
| Formulário investor | Mesmo ensaio, iteração própria investor; gravação/recuperação/filtro/delta+1 | Interface própria |
| Formulário company | Mesmo ensaio, iteração própria company; gravação/recuperação/filtro/delta+1 | Interface própria |
| Apoio partnership | Mesmo ensaio, iteração própria partnership; gravação/recuperação/filtro/delta+1 | Interface própria; não confundir com contrato da Bolsa |
| Perfil + empresa | `InvestmentWorkspaceTest::test_country_meanings_are_persisted_separately_without_inference_and_recovered_by_account`: residência PT/constituição MZ/histórico preservado e recuperação em manifestação; origem não inferida | Seletores/profile/empresa renderizados; não são estatística de solicitação por si só |
| Manifestação autenticada | Mesmo teste, origem ZA salva/recuperada/ZZ422/conta indevida404; `test_declared_origin_is_snapshotted_on_submission_and_statistics_do_not_infer_old_country`, `test_crm_origin_filter_separates_explicit_missing_and_empty_results_without_writing`: submissão/unknown/PT/ZA/filtros e stats | Caminho completo na interface, campos condicionais/anexos restantes |
| Jornada da carteira | `InvestmentPortfolioTest::test_personal_journey_is_isolated_and_retries_do_not_duplicate_interest_or_event`: país/origem metadata/GET jornada/replay/outra conta; CRM preserva investidor; agregado/filtro PT=1/MZ=0 apesar do país histórico Moçambique | Interface e estatística/filtro renderizados; não promover prova de outro formulário |
| Interesse em negócio público | `BusinessMarketplacePublicTest::test_interest_is_limited_to_published_business_and_deduplicated_idempotently`: GET do formulário249países/ID, POST PT/ZA, ZZ422 sem escrita, recibo/replay únicos, metadata/GET gestor, filtro PT/ZA e interests ZA=1/PT=0, conta indevida403 | Interface e variações condicionais por modalidade; não confundir com wizard privado |
| Wizard privado de negócios | `PortalAuditNextLotTest::test_business_country_origin_save_recover_filters_submission_statistics_and_actor_isolation`: PT/ZA cifra/revisões/GET/filtros; draft fora dos agregados; submissão businesses ZA=1/PT=0; inválido/conflito/conta indevida | Renderização por modalidade e permissões adicionais; não confundir com interesse público |
| Fundiário | `test_land_country_origin_and_four_territory_levels_recover_in_support_filters_statistics`: PT/ZA/parcela de4níveis/GET; apoio gera1interesse; filtro/PT/ZA/unknown/estatística; conta indevida404 | Formulário/mapa/recibo visíveis, anexos/transições restantes |
| Balcão preparação | `PortalAuditConsumerLotTest::test_all_three_desk_forms_save_recover_countries_and_support_authorized_corrections`, iteração project-preparation: cifra/GET PT/ZA/422; submetido/devolvido/correção MZ/PT/409/403; stats desk migra para PT, coleção interests/businesses vazia | Interface própria e restante ciclo/anexos |
| Balcão alteração | Mesmo ensaio, iteração project-change, referências/motivo e correção autorizada; recuperação/estatística própria | Interface própria/campos condicionais restantes |
| Balcão acompanhamento | Mesmo ensaio, iteração project-follow-up, referência/progresso e correção autorizada; recuperação/estatística própria | Interface própria/ciclo completo |
| Simulador/contexto | `test_simulator_recovers_iso_countries_in_private_draft_without_reinterpreting_legacy_values` + HTTP A/B: residência fiscal PT, fundos PT/ZA, cifra/GET/versão/ZZ422/estranho404; nenhuma execução fiscal por gravar | Seletores, autosave, nova sessão e retorno renderizados; estes campos não são origem de solicitação |
| Gestão/CRM | Ensaios acima: filtros origin/country/unknown, contagens separadas interests/desk/businesses e negativos403 | Aplicação do filtro, URL, tabela e estado vazio no navegador; desempenho das listas cifradas |
| Formulário/consumidor | Evidência específica em QA | Critério ainda pendente |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Manifestação pública `/` e `/manifestar-interesse` | `PortalAuditContinuationTest::test_public_country_and_origin_survive_api_storage_management_recovery_and_statistics`:249 países nos props, PT/ZA separados, 422 inválido sem escrita, replay único, metadata/GET gestor e agregado/filtro CRM ZA=1/PT=0 | Seleção, mensagem/recibo e filtros renderizados em ambas as páginas |
| Apoio support | `test_support_kinds_keep_iso_country_separate_and_legacy_text_unchanged`: POST próprio, recuperação detalhe PT/ZA, filtro PT/ZA e delta+1 interests, origem PT=0 | Formulário/recibo/tabela visíveis |
| Formulário investor | Mesmo ensaio, iteração própria investor; gravação/recuperação/filtro/delta+1 | Interface própria |
| Formulário company | Mesmo ensaio, iteração própria company; gravação/recuperação/filtro/delta+1 | Interface própria |
| Apoio partnership | Mesmo ensaio, iteração própria partnership; gravação/recuperação/filtro/delta+1 | Interface própria; não confundir com contrato da Bolsa |
| Perfil + empresa | `InvestmentWorkspaceTest::test_country_meanings_are_persisted_separately_without_inference_and_recovered_by_account`: residência PT/constituição MZ/histórico preservado e recuperação em manifestação; origem não inferida | Seletores/profile/empresa renderizados; não são estatística de solicitação por si só |
| Manifestação autenticada | Mesmo teste, origem ZA salva/recuperada/ZZ422/conta indevida404; `test_declared_origin_is_snapshotted_on_submission_and_statistics_do_not_infer_old_country`, `test_crm_origin_filter_separates_explicit_missing_and_empty_results_without_writing`: submissão/unknown/PT/ZA/filtros e stats | Caminho completo na interface, campos condicionais/anexos restantes |
| Jornada da carteira | `InvestmentPortfolioTest::test_personal_journey_is_isolated_and_retries_do_not_duplicate_interest_or_event`: país/origem metadata/GET jornada/replay/outra conta; CRM preserva investidor; agregado/filtro PT=1/MZ=0 apesar do país histórico Moçambique | Interface e estatística/filtro renderizados; não promover prova de outro formulário |
| Interesse em negócio público | `BusinessMarketplacePublicTest::test_interest_is_limited_to_published_business_and_deduplicated_idempotently`: GET do formulário249países/ID, POST PT/ZA, ZZ422 sem escrita, recibo/replay únicos, metadata/GET gestor, filtro PT/ZA e interests ZA=1/PT=0, conta indevida403 | Interface e variações condicionais por modalidade; não confundir com wizard privado |
| Wizard privado de negócios | `PortalAuditNextLotTest::test_business_country_origin_save_recover_filters_submission_statistics_and_actor_isolation`: PT/ZA cifra/revisões/GET/filtros; draft fora dos agregados; submissão businesses ZA=1/PT=0; inválido/conflito/conta indevida | Renderização por modalidade e permissões adicionais; não confundir com interesse público |
| Fundiário | `test_land_country_origin_and_four_territory_levels_recover_in_support_filters_statistics`: PT/ZA/parcela de4níveis/GET; apoio gera1interesse; filtro/PT/ZA/unknown/estatística; conta indevida404 | Formulário/mapa/recibo visíveis, anexos/transições restantes |
| Balcão preparação | `PortalAuditConsumerLotTest::test_all_three_desk_forms_save_recover_countries_and_support_authorized_corrections`, iteração project-preparation: cifra/GET PT/ZA/422; submetido/devolvido/correção MZ/PT/409/403; stats desk migra para PT, coleção interests/businesses vazia | Interface própria e restante ciclo/anexos |
| Balcão alteração | Mesmo ensaio, iteração project-change, referências/motivo e correção autorizada; recuperação/estatística própria | Interface própria/campos condicionais restantes |
| Balcão acompanhamento | Mesmo ensaio, iteração project-follow-up, referência/progresso e correção autorizada; recuperação/estatística própria | Interface própria/ciclo completo |
| Simulador/contexto | `test_simulator_recovers_iso_countries_in_private_draft_without_reinterpreting_legacy_values` + HTTP A/B: residência fiscal PT, fundos PT/ZA, cifra/GET/versão/ZZ422/estranho404; nenhuma execução fiscal por gravar | Seletores, autosave, nova sessão e retorno renderizados; estes campos não são origem de solicitação |
| Gestão/CRM | Ensaios acima: filtros origin/country/unknown, contagens separadas interests/desk/businesses e negativos403 | Aplicação do filtro, URL, tabela e estado vazio no navegador; desempenho das listas cifradas |
Provas atuais: `continuation-consumer-qa.xml` contém os métodos identificados, incluindo regressão territorial e carteira; `continuation-profile-qa.xml` contém perfil/manifestações, CRM, orientação, interesses e Bolsa; `continuation-business-journey-qa.xml` completa interesse em negócio público e agregado/filtro da jornada. As contagens globais destes ficheiros não substituem as asserções de cada linha. Texto legado mantido; país da residência/constituição/fiscal/fundos e origem declarada são significados diferentes. Ausência de origem permanece Não informado.
@@ -0,0 +1,162 @@
<!-- option-B3-exit-table-20261013 -->
## Opção B: tabela única dos critérios de saída
[Tabela atual: concluído/prova, trabalho executável, C135 e dependência concreta](saldo-opcao-B.md).22 grupos, sem novos IDs ou outro backlog; A/B/C37 preservados.25–43 h estimadas restantes (5–10 correções+5–10 implementação+15–23 verificação), não horas consumidas nem prazo garantido.
Projeto 30: PDF próprio/scan real/hash, licença aplicável sintética, revisão jurídica apenas, aprovação 24/publicação 25 restrita e outra sessão; visual ainda aberto. Scanner QA13310 tinha assinaturas >48 h; atualizado só emQA, limite intacto/fila alheia preservada. Sem delta de código do produto ou recompilação. Ativo intacto; candidata final não fixada.
C132 separado:14–17 confirmadas, recuperação individual concluída; investigação histórica/limites ainda abertos. Sem envio, rotação ou alteração ativa. As secções datadas abaixo preservam o histórico; para o estado atual usar esta tabela.
<!-- /option-B3-exit-table-20261013 -->
<!-- option-B2-saldo-20261013 -->
## Opção B: saldo atualizado, C140/C141 e critérios restantes
[Saldo por critério, consumidor, bloqueio e esforço](saldo-opcao-B.md). **Restam 25–43 h técnicas**, reestimativa da faixa 40–72, separadas em 5–10 correções, 5–10 implementação pedida e 15–23 verificação. Não é percentagem de conclusão nem tempo medido; espera C135/ativação/evolução fora. B continua sem candidata final.
C140: unidade explícita da parcela guardada/recuperada emQA, sem converter área 1100; apenas cadastral reabre. C141: preparação de área/unidade incompleta guardável; submissão 422→completar par→revisões/condição preexistente→aprovação 24/publicação 25 restrita→nova sessão.148 tarefas anteriores e originais/dossiers preservados; 6 tarefas novas próprias, sem prazos. Interface nova aberta por C135, separado das falhas do produto.
A/B e C37 preservados. C132 separado:14/16/17 confirmadas, apenas 15 pendente; nenhum segredo/envio/rotação/alteração ativa. Zero alterações do portal ativo.
<!-- /option-B2-saldo-20261013 -->
<!-- option-B-first-increment-20261013 -->
## Opção B em QA: âmbito fixado e critérios novos demonstrados
[Âmbito e aceitação fixados antes da execução](ambito-B-aceitacao-QA.md). [Resultados, acessos e critérios restantes](execucao-B-QA.md). A migração 190000 já existia neste clone; habilitou-se apenas a flag QA. C138 corrigiu a repetição fundiária, 409 → 202 com o mesmo recibo, país/origem e quatro IDs recuperáveis. C139 corrigiu maturidade 7/8 na publicação e pesquisa pública, sem converter os catálogos históricos.
Variantes de licença não aplicável (30), área/comunidade sintética (32), exercício financeiro (33), contribuições (34) e exclusividade (56) passaram por gravação, reabertura apenas dos pareceres afetados, revisão independente e recuperação noutra sessão. 33 foi publicado no catálogo público QA; os outros quatro têm visibilidade restrita. Consulta pendente continuou a impedir publicação apesar da aprovação interna. Originais e 132 tarefas anteriores preservados; 16 tarefas novas destes casos, sem prazos inventados.
TypeScript/produção passaram: 159 ficheiros preparados, 157 recursos referenciados servidos por HTTPS com hashes corretos. Mesma matriz: 3.401 requisitos/linhas, 7.739 ocorrências, 27 grupos de provas; 10 requisitos de B atualizados, sem fechos visuais ou agregados. A/B e C37 preservados. Critérios visuais novos continuam abertos por C135, assim como as variantes/consumidores delimitados. Este pacote consolida **um incremento B para revisão**, não a candidata final pronta para ativação. Código/configuração/bundle ativos intactos.
**C132, separado:** conta 16 confirmou recebimento, MFA e dashboard; conta 17 já confirmada. Restam 14/15 e os limites históricos do incidente, sem reenvio, rotação ou alterações ativas nesta confirmação.
<!-- /option-B-first-increment-20261013 -->
<!-- module-exit-synthesis-PDF-C137-20261012 -->
## Lote executado agora
| Item | Rota/perfil | Resultado e evidência | Critério que continua aberto |
| --- | --- | --- | --- |
| Exportações | `/api/v1/investment/export`; `/api/v2/investment/zones/export.csv`; público | CSV8/11colunas e8linhas de cada conjunto; UTF8/BOM; filtro positivo e replay idêntico; oportunidade interna56 excluída. `next-exports-HTTP.json`. | Botão/UI e demais combinações/limites grandes; não declara todas as exportações concluídas. |
| Royalties/licença | `/minhas-oportunidades/56/edit`, `/workflow`, `/view`, `/resources/documents/{id}/download`; QA21→24→25 | Royalties reabre3gates, licença2; restantes hash/ator/data conservados; aprovação422 antes das revisões; reaprovação24/publicação interna25/nova sessão. PDF próprio clean/hash/MIME e licençaUUIDpreservados. `franchise-variant-royalties/license-HTTP.json`, `next-lot-final-SQL.json`. | UI, exclusividade/titularidade e publicação pública; §27integral. |
| Revogação | `/parcerias/salas/2/documentos/4` e`/partilha`; autor21/participante23/não participante22 | PDF200 antes→sala cancelada→autor retira→sessão antiga/nova404; autor200/hash; regrant409, não autor403, anónimo401. Repetição mantém1original; sala1/anexos intactos. `partnership-revocation-closed-room-revocation-HTTP.json`. | C137UI e restantes variantes de sala; não é ACL individual da oportunidade. |
| C137 | Componente `partnerships/room`, autor do documento | GuardaUI `mutable` ocultava retirada após encerramento emboraAPIpermitisse. Ajustado apenasQA para permitir retirar partilha existente ao autor e manter novas partilhas indisponíveis. TypeScript/build passaram,159assets; novo chunk servido200/hash; manifestoQA87e77091835f… e anteriorcf78… preservados. | Clique/resultado visual com estado adequado; código compilado não encerra o critério. |
| PDF anterior | Impressão fundiária no browser, âmbitoQA anterior | Reutilizado PDF3páginas/hash0676c5f7… com prova visual/scan anteriores e bytes atuais conferidos. PDF sintético1977bytes deste lote é entrada de teste, **não um novo gerador do portal**. | Geradores/templates/PDFs etiquetados e consumidores restantes. ReciboBalcão continuaTXT; não foi convertido silenciosamente. |
Oito requisitos existentes atualizados; zero novosIDs;19grupos de provas com correspondências/limites explícitos. Nenhum fecho visual ou agregado novo. Fontes/configuração/bundle ativos conferidos por hash e intactos. Alteração deste lote é umaTSXna cópiaQA e159assets compilados, com originais/manifesto anterior privados e assets antigos preservados. Reversão técnicaQA deste delta: fonte anterior e manifestoQAanterior, mantendoPDFs,IDs,história e partilha revogada; nunca reautorizar destinatários como reversão. Algoritmov4da materialidade permanece, comv2/v3preservados. Não é pacote pronto para ativação.
Saldo por módulo, bloqueios e esforço na visao-consolidada-modulos.md; mesmas matrizes, sem novo backlog.
<!-- /module-exit-synthesis-PDF-C137-20261012 -->
<!-- consumer-QA-C135-C136-20261012 -->
## Lote QA de seletores, derivadas e variante financeira da franquia
**Nenhuma alteração no ativo.** A/B e C37 mantêm os fechos próprios. C133 conserva a prova API/SQL; C134 permanece compilado em QA, com interação visual pendente. C132 fica separado: conta17 recuperada, confirmações individuais14–16 ainda pendentes. Nenhum email ou segredo foi reenviado neste lote.
O lote atualiza nove requisitos existentes, sem novos IDs: AUD-FIELD-030, AUD-GEO-02/03, AUD-OP-02/03/04, AUD-SCAN-01, AUD-UI-01 e AUD-PROFILE-28. A matriz tem **3.401 requisitos/linhas e 7.739 ocorrências de origem**:3060 sem evidência suficiente,318 parciais,6 decisões Tempo,1 falha,7 demonstrados apenas em QA e9 não implementados. Nenhum requisito agregado ou critério visual foi encerrado por este lote.
### Evidência nova e critérios restantes
Base QA: **https://portal-investidor.test:18445**, PostgreSQL `stability_consumers_20261011_084534_test:55441`. O cabeçalho QA foi conferido em cada resposta; as leituras SQL finais ocorreram em transação READ ONLY. QA56 é uma oportunidade sintética, com documentação identificada como simulação sem validade jurídica.
| Item e requisito | Rota, perfil e ação | Demonstrado neste lote | Critério restante e evidência necessária |
| --- | --- | --- | --- |
| Hierarquia — AUD-FIELD-030/AUD-GEO-02 | `/minhas-oportunidades/56/resources`; Promotor21 guarda, nova sessão recupera. APIs `/minhas-oportunidades/territory-options` e `POST /minhas-oportunidades/56/resources/locations`. | Cabo Delgado→Ancuabe/distrito→Ancuabe/posto→Ancuabe-Sede/localidade: quatro IDs recuperados; pai de nível errado422 e país PT com território MZ422. | Mostrar seleção, troca de pai/país, limpeza dos filhos e erros adjacentes a1440/390px; captura e resultado após guardar. A API não demonstra os cliques nem a limpeza na interface. |
| Limites — AUD-GEO-03 | `/minhas-oportunidades/territory-geometries?territory_id={UUID}`; perfil autorizado. Consulta pública `/api/v1/investment/territory-geometries`. | Província/distrito/posto: geometria INE disponível, contextos1/2/3. Localidade cadastrada sem geometria própria, recebe só três limites ancestrais; `investment_site=false`. Camadas internas não expostas na consulta pública:0. | Mapa deve distinguir limite administrativo de local de investimento e ausência de limite da localidade. Captura/legenda/teclado/zoom em cada consumidor ainda aberto;173 correspondências e Mandie/Guro mantidos. Sem novas importações ou publicações. |
| Original/derivadas — AUD-OP-02/AUD-SCAN-01 | `POST /minhas-oportunidades/56/resources/images`; `POST /minhas-oportunidades/56/resources/images/{imagem}/prepare`; `GET .../download` e `GET .../preview/{documento}`. Autor21/coeditor22/Validador24/Publicador25; outra organização23/anónimo. | Upload→quarentena423→job do scan real ClamD1.5.4→original limpo→WebP320/640/1280→scan próprio→download200/hashes→nova sessão. Replay conserva IDs, versão2 e um evento derivatives_prepared. Outraorg403/anónimo401, incluindo URL assinada. Bytes cifrados e original preservados. | Apresentação visual da imagem/WebP e erros; outros formatos/PDFs/consumidores não cobertos. Os jobs tratados pertencem só a56: não foi um novo ensaio do worker nem consumo da fila alheia. Reutilizar os recibos prévios de interrupção/replay. |
| Response de recursos — AUD-OP-04 | `GET /minhas-oportunidades/56/response`; Promotor e perfis no âmbito. | IDs de localização/imagem, SHA original e autor21 recuperados no contrato ligado aos recursos. | §27 integral continua `normative_response_complete=false`: IDs bigint/referência histórica, metadata desconhecida e pareceres paralelos não são convertidos. Novas variantes exigem campos/IDs/metadata específicos; não se declara conformidade global. |
| C136, franquia — AUD-OP-03/04/AUD-PROFILE-28 | `/minhas-oportunidades/56/edit`, `PUT .../draft`, `POST .../workflow`, `GET .../view`; Promotor21→Validador24→Publicador25, MFA próprio em sessões normais. | Submissão/aprovação independente; taxa inicial1000→1250; nova submissão reabre marca/licença, legal da franquia e financeiro, conserva confidencialidade/hash/ator/data. Aprovação422 antes das revisões;24 reaprova e25 disponibiliza internamente. Nova sessão recupera taxa/estado. Autor não autoaprova403. | Interface da variante, royalties viaHTTP/UI e restantes variantes abaixo. Esta publicação usa o workflow real em QA, mas é **restrita**, não prova catálogo público. O anúncio do lote C133 continua fixture e não é substituído por esta franquia. |
| C135, conector — AUD-UI-01 | Inventários suportados de apps e navegador, antes de qualquer seleção/input. | Chromium1243 está em execução; pipe nativo ausente, os error2; inventário apps/browsers vazio. Primeiro ponto de falha é IPC. | Repor o transporte do conector no host e obter inventário QA antes de retomar os visuais novos. Processo específico/causa além do IPC ausente não determinados. Não há prova de falha do Chrome ou do portal; sem contorno de protocolos e sem pedir novos testes repetidos ao utilizador. |
**C136 — causa e correção:** a projeção v3 de `financial_review` não incluía `business_transaction.franchise_terms.initial_fee` nem `royalties`. A alteração podia conservar um parecer financeiro desatualizado. Apenas em QA, a projeção v4 incorpora esses dois campos já existentes. As regras históricas v2/v3 continuam verificadas pelo respetivo algoritmo, preservando assinaturas/ator/data; não se recalculam assinaturas silenciosamente. Antes/depois foram reproduzidos em memória e a taxa inicial foi depois demonstrada pelo HTTP/SQL normal. Royalties passou a regressão do serviço, não uma transição HTTP ou interface. O ficheiro ativo conserva o hash anterior; não foi corrigido por este lote.
**Limites da execução:** não se repetiram os seis percursos visuais base, arrendamento54, coedição15, suspensão/republicação31 ou recurso34. O novo caso56 é necessário para a falha financeira recém-identificada e não altera os casos anteriores. Dois erros de leitura de propriedades no harness foram corrigidos e os pedidos válidos aproveitados, sem criar oportunidades repetidas; não são falhas do portal. Só a disponibilização final foi retomada depois da aprovação já válida, sem a repetir.
### Consumidores e variantes ainda abertos
| Rota | Perfil e operação | Critério em falta | Evidência a produzir ou reutilizar |
| --- | --- | --- | --- |
| `/negocios/{slug}/manifestar-interesse`; `/management/interests` | Público/gestor: países, origem, erros e filtros | C134: foco/rótulos/erros/valores e chave preservados; publicação do anúncio pelo fluxo próprio ainda não demonstrada. | Reutilizar C133 API/SQL e build C134. Nova captura só dos critérios de interface; o anúncio sintético não encerra publicação. |
| `/minhas-oportunidades/15/resources` e `/15/edit` | Coeditor22/autor21: correção pós-submissão | Coedição de rascunho já demonstrada; falta coedição na correção e revogação nessa ação. | Reutilizar coedição/mapa/PDF prévios; novo estado needs_information e revogação em fixture própria, leitura/escrita recusadas. Não repetir rascunho comum. |
| `/oportunidades?view=map`, `/api/v1/investment/map`, `/carteira/{id}` | Público: pesquisa e mapa | Consumidores sem prova própria: filtros/limites/ausência de geometria, recuperação do contexto, legenda/teclado. | Resposta API com fonte/visibilidade + captura do consumidor; sem publicar camadas internas como preparação do teste. |
| `/management/investment/zones/{id}`; `/zonas/{id}`; `/api/v2/investment/zones/export.csv` | Gestor escreve recursos no seu âmbito; público consulta | Seletores/mapa/anexo e exportação por zona não encerrados pelo mapa de oportunidades. | Estado próprio QA, persistência/nova sessão, hash/scan e acesso público/restrito conforme autorização; captura e CSV do mesmo filtro. |
| `/investidor/terra-duat/{id}/editar`, `/{id}/documentos/{anexo}`, `/{id}/imprimir` | Investidor proprietário e gestor no âmbito | Hierarquia, documentos e impressão das variantes não cobertas por A/B; HTML de impressão não prova PDF gerado/etiquetado. | Reutilizar A/B apenas no que efetivamente cobre; novo documento/caso próprio, original/hash/scan, recusa outra conta, impressão e acessibilidade específicas. |
| `/balcao-virtual/dossiers/{id}/documentos/{documento}`; `/balcao-virtual/pedidos/{id}/recibo` | Titular/analista autorizado: ficheiro e recibo | Documentos por tipo e recuperação após retirada/revogação. O endpoint de recibo atual gera **TXT**, não PDF; não declarar o PDF concluído. | Protocolo/snapshot do mesmo pedido, conteúdo MIME real, hash/autorização e apresentação. A/B permanece fechado; PDF é critério documental próprio ainda sem implementação neste endpoint. |
| `/parcerias/salas/{id}/documentos/{anexo}` e `POST .../partilha` | Participante autorizado: partilha/revogação | Variantes de destinatário/estado e revogação ainda sem prova específica. | Reutilizar o recibo da sala1 apenas no âmbito efetivo; destinatário antes200/depois nega, original preservado e nova sessão. ACL individual de oportunidade continua indisponível e não é substituída pela sala de parceria. |
| `/minhas-oportunidades/{id}/workflow` e `/{id}/response` | Promotor/Validador/Publicador por tipo/âmbito | Variantes de categorias abaixo; §27 parcial. | Transição do campo específico→persistência→reabertura só dos pareceres afetados→aprovação independente→visibilidade prevista→nova sessão; captura só dos passos ainda sem prova. |
### Critérios restantes por categoria
| Categoria e referência válida | Semântica/materialidade restante | Documentos/Response restante |
| --- | --- | --- |
| Projeto30/52 | Licenciamento e pressupostos de cenários; alteração de evidência aninhada demonstrada em serviço, não em todos os consumidores. Risco/correção/condição prévios reutilizados. | Evidência própria por variante; PDF/exportações dos outros consumidores; §27 parcial. |
| Imobiliário31 e arrendamento54 | Venda/arrendamento preservados, renda4500 MZN/monthly. Construção planeada, ocupação contratada, encargos e limites urbanísticos por variante. | Título/licença/avaliação54 já scaneados e recuperados; documentos das modalidades restantes, sem presumir direitos reais. |
| Direitos sobre terra32 | Área/unidade/comunidades/plano no código com regressões; faltam novos casos de campo/consumidor. Parcelas/direitos externos continuam separados do limite administrativo. | Ato QA32 é simulação, não decisão externa real. Localidades/parcelas sem geometria própria mantêm lacuna; metadata/§27 parcial. |
| Venda de negócio33 | Financeiros/histórico/projeções/confidencialidade por variante; cadastro do anúncio existente é consumidor distinto. C133 cobre interesse/país/origem/SQL desse anúncio, não publicação. | Mandato/teaser/destinatários específicos; proposta de ausência de histórico não vira regra aprovada. |
| Parceria34 | Contribuições monetárias/não monetárias, obrigações e documentos adicionais; voto/recurso anteriores preservados. | Revogação da sala1 não encerra ACL individual de documentos da oportunidade; §27 e metadados de pareceres distintos. |
| Franquia35/56 | Taxa inicial56 HTTP/SQL agora demonstrada; royalties serviço apenas. UI da taxa, HTTP/UI de royalties, exclusividade, licença/titularidade e território continuam abertos. | Documento contratual56 é simulação própria com scan real; variantes de licença/confidencialidade por destinatário pendentes; §27 parcial. |
### Próximo trabalho executável e reversão QA
1. **Documentos por consumidor,4–6h estimadas:** recibo TXT/HTML versus PDF real, fundiário e anexos de zonas/parcerias; verificar tipos/scan/hash/revogação por rota. Pressupõe serviços QA e estados existentes disponíveis. Não consumir fila ativa ou notificações externas.
2. **Variantes de workflow,3–5h para franquia:** royalties, licença e exclusividade, sem repetir taxa inicial ou casos base. Outros tipos por pequenos lotes próprios conforme dados/documentos necessários. Restauração/partilha individual/ofertas/módulos/SLA mantêm decisões separadas.
3. **Visual/acessibilidade:** C131/C134, novos seletores/limites/WebP/materialidade quando o conector voltar a expor uma janela QA. Não estimar conclusão enquanto faltar o transporte; leitor de ecrã e dispositivos reais são provas distintas.
Não é candidata de ativação. Delta de código deste lote: **apenas PHP `OpportunityReviewMateriality.php` na cópia QA**, sem nova compilação; o manifesto QA C134 mantém SHA `cf78d5516251bc27c0d1b74fdfc257adf9a3113276dce9109c3c312e57d70fe9`. Fonte anterior privada preservada e hash conferido. Reversão QA: desabilitar ensaio desta variante e recuperar a fonte anterior quando não houver decisões v4 a utilizar; conservar todos os dados/IDs/documentos/decisões v4, sem recalcular assinaturas ou tentar fazê-las valer pelo algoritmo v3. Nova candidata deverá incluir o algoritmo v4 e os históricos v2/v3, com backup/restauro correspondente. Nenhuma instalação ou ativação autorizada por esta entrega.
Provas sanitizadas: `connector-diagnosis-C135.json`; `franchise-materiality-before/after.json`; `workflow-franchise-materiality/finish-HTTP.json`; `consumer-lot-quarantine/derive/recover-HTTP.json`; `consumer-lot-document-state-original/derivatives.json`; `consumer-lot-final-SQL.json`; `consumer-lot-preservation.json`. Cada grupo enumera IDs e limites em `proof-groups.json`. Sem cookies, códigos, QR ou segredos anexados.
<!-- /consumer-QA-C135-C136-20261012 -->
# Consumidores territoriais/país e critérios restantes
As 46 ocorrências históricas AUD-FIELD são mantidas com os seus IDs/referências. Linhas de código não são requisitos funcionais concluídos. Rotas abaixo vêm de método/controlador/registo atual ou de consumidor que importa o componente comum; «por localizar» é lacuna explícita. Interface nova não observada; não implica ausência de API. A matriz/backlog canónicos continuam os existentes.
| ID/componente de origem | Rotas atuais relacionadas | Perfil/ação | Critério específico em falta |
|---|---|---|---|
| AUD-FIELD-001 `resources/js/components/interactive-investment-map.tsx` | /api/v 1/partnerships; /educacao; /oportunidades | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-002 `resources/js/components/interactive-investment-map.tsx` | /api/v 1/partnerships; /educacao; /oportunidades | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-003 `resources/js/components/investment-map-panel.tsx` | /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones/{id}; /carteira/{id}; /management/investment/zones/{id}; /management/portfolio/{id}; /oportunidades/{slug}; /zonas/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-004 `resources/js/components/investment-territory.tsx` | /; /Simulador; /api/v 1/business-opportunities; /api/v 2/investment/admin/zones; /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones; /api/v 2/investment/zones/{id}; /apoio; /balcao-virtual; /balcao-virtual/pedidos/{id}; /carteira; /como-investir; /documentos; /educacao; /formularios/empresa; /formularios/investidor; /investidor/terra-duat/novo; /investidor/terra-duat/{id}/editar; /legislacao; /management/ai; /management/education; /management/education/demands/{id}/analysis; /management/investment/zones; /management/investment/zones/{id}; /management/opportunities/create; /management/opportunities/{id}/edit; /management/opportunities/{id}/resources; /management/opportunities/{id}/view; /management/portfolio; /management/{resource}/create; /management/{resource}/{id}/edit; /management/{structure}/create; /management/{structure}/{id}/edit; /manifestar-interesse/{slug?}; /minhas-oportunidades/{id}/resources; /negocios; /oportunidades; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal; /zonas; /zonas/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-005 `resources/js/components/investment-territory.tsx` | /; /Simulador; /api/v 1/business-opportunities; /api/v 2/investment/admin/zones; /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones; /api/v 2/investment/zones/{id}; /apoio; /balcao-virtual; /balcao-virtual/pedidos/{id}; /carteira; /como-investir; /documentos; /educacao; /formularios/empresa; /formularios/investidor; /investidor/terra-duat/novo; /investidor/terra-duat/{id}/editar; /legislacao; /management/ai; /management/education; /management/education/demands/{id}/analysis; /management/investment/zones; /management/investment/zones/{id}; /management/opportunities/create; /management/opportunities/{id}/edit; /management/opportunities/{id}/resources; /management/opportunities/{id}/view; /management/portfolio; /management/{resource}/create; /management/{resource}/{id}/edit; /management/{structure}/create; /management/{structure}/{id}/edit; /manifestar-interesse/{slug?}; /minhas-oportunidades/{id}/resources; /negocios; /oportunidades; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal; /zonas; /zonas/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-006 `resources/js/components/structure-geography.tsx` | /carteira/{id}; /management/portfolio/{id}; /oportunidades/{slug}; /parcerias/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-007 `resources/js/pages/ai/index.tsx` | /management/ai | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-008 `resources/js/pages/desk/case.tsx` | /balcao-virtual/dossiers/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-009 `resources/js/pages/desk/request.tsx` | /balcao-virtual/pedidos/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-010 `resources/js/pages/desk/request.tsx` | /balcao-virtual/pedidos/{id} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-011 `resources/js/pages/education/analysis.tsx` | /management/education/demands/{id}/analysis | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-012 `resources/js/pages/education/index.tsx` | /management/education | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-013 `resources/js/pages/education/index.tsx` | /management/education | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-014 `resources/js/pages/investment/business-interest.tsx` | /negocios/{slug}/manifestar-interesse | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-015 `resources/js/pages/investment/business-marketplace.tsx` | /api/v 1/business-opportunities; /negocios | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-016 `resources/js/pages/investment/business-wizard.tsx` | Rota específica por localizar; componente comum/ramo dinâmico | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-017 `resources/js/pages/investment/catalogue.tsx` | /educacao; /oportunidades | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-018 `resources/js/pages/investment/catalogue.tsx` | /educacao; /oportunidades | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-019 `resources/js/pages/investment/catalogue.tsx` | /educacao; /oportunidades | Anónimo/consumidor público e gestor no modo administrativo | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-020 `resources/js/pages/investment/profile.tsx` | /api/v 1/investment/profile; /investidor/profile | Anónimo/consumidor público e gestor no modo administrativo | Residência/constituição/origem distintos; master/snapshot, erros e recuperação porperfil restante. |
| AUD-FIELD-021 `resources/js/pages/investment/submission.tsx` | /api/v 1/investment/submissions/{id}; /investidor/manifestacoes/{id} | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-022 `resources/js/pages/investment/zone.tsx` | /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones/{id}; /management/investment/zones/{id}; /zonas/{id} | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-023 `resources/js/pages/investment/zone.tsx` | /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones/{id}; /management/investment/zones/{id}; /zonas/{id} | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-024 `resources/js/pages/investment/zone.tsx` | /api/v 2/investment/admin/zones/{id}; /api/v 2/investment/zones/{id}; /management/investment/zones/{id}; /zonas/{id} | Anónimo/consumidor público e gestor no modo administrativo | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-025 `resources/js/pages/investment/zones.tsx` | /api/v 2/investment/admin/zones; /api/v 2/investment/zones; /management/investment/zones; /zonas | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-026 `resources/js/pages/investment/zones.tsx` | /api/v 2/investment/admin/zones; /api/v 2/investment/zones; /management/investment/zones; /zonas | Anónimo/consumidor público e gestor no modo administrativo | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-027 `resources/js/pages/land-assistance/form.tsx` | /investidor/terra-duat/novo; /investidor/terra-duat/{id}/editar | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-028 `resources/js/pages/management/editor.tsx` | /management/{resource}/create; /management/{resource}/{id}/edit | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-029 `resources/js/pages/management/opportunity-draft.tsx` | /management/opportunities/create; /management/opportunities/{id}/edit; /management/opportunities/{id}/view; /minhas-oportunidades/create; /minhas-oportunidades/{id}/edit | Promotor 21/coeditor 22, Validador 24/Publicador 25 só no âmbito; externo 23 nega | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-030 `resources/js/pages/management/opportunity-resources.tsx` | /management/opportunities/{id}/resources; /minhas-oportunidades/{id}/resources | Promotor 21/coeditor 22, Validador 24/Publicador 25 só no âmbito; externo 23 nega | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-031 `resources/js/pages/management/opportunity-resources.tsx` | /management/opportunities/{id}/resources; /minhas-oportunidades/{id}/resources | Promotor 21/coeditor 22, Validador 24/Publicador 25 só no âmbito; externo 23 nega | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-032 `resources/js/pages/partnerships/catalogue.tsx` | /api/v 1/partnerships | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-033 `resources/js/pages/partnerships/catalogue.tsx` | /api/v 1/partnerships | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Limite/ponto correcto, âmbito/privacidade, legenda, teclado/foco e móvel; APIgeom não demonstra apresentação. |
| AUD-FIELD-034 `resources/js/pages/partnerships/editor.tsx` | /parcerias/criar; /parcerias/{id}/editar | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-035 `resources/js/pages/portal/manage.tsx` | /management/portal-services | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-036 `resources/js/pages/portal/manage.tsx` | /management/portal-services | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-037 `resources/js/pages/portal/services.tsx` | /Simulador; /apoio; /balcao-virtual; /como-investir; /documentos; /formularios/empresa; /formularios/investidor; /legislacao; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-038 `resources/js/pages/portal/services.tsx` | /Simulador; /apoio; /balcao-virtual; /como-investir; /documentos; /formularios/empresa; /formularios/investidor; /legislacao; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-039 `resources/js/pages/portal/services.tsx` | /Simulador; /apoio; /balcao-virtual; /como-investir; /documentos; /formularios/empresa; /formularios/investidor; /legislacao; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-040 `resources/js/pages/portal/services.tsx` | /Simulador; /apoio; /balcao-virtual; /como-investir; /documentos; /formularios/empresa; /formularios/investidor; /legislacao; /parcerias; /sectores; /sectores/{slug}; /simulador-fiscal | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-041 `resources/js/pages/PortalInvestidor.tsx` | /; /manifestar-interesse/{slug?} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-042 `resources/js/pages/PortalInvestidor.tsx` | /; /manifestar-interesse/{slug?} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-043 `resources/js/pages/PortalInvestidor.tsx` | /; /manifestar-interesse/{slug?} | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-044 `resources/js/pages/portfolio/index.tsx` | /carteira; /management/portfolio | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
| AUD-FIELD-045 `resources/js/pages/portfolio/workspace.tsx` | /investidor | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar país; gravar/recuperar campo no consumidor correto; origem separada e filtro/estatística quando aplicável. |
| AUD-FIELD-046 `resources/js/pages/structures/editor.tsx` | /management/{structure}/create; /management/{structure}/{id}/edit | Perfil do consumidor/política; identificar variantes ainda não demonstradas | Pesquisar→selecionar→limpar descendentes→guardar→nova sessão; erro/rótulo/foco e relação de pai; sem persistência nos filtros, retorno/F 5. |
Os casos 30–35/54, recurso 30, catálogo e filtros do workflow têm provas anteriores e GET atual suplementar. Não encerrar automaticamente todasestas linhas. Para negócios: interesse exige anúnciopublicado inexistente na QAatual; para mapas:173 correspondências/semlocalidades noexemplar; para educação: actor/draftincompletoausentes. Biblioteca/CRM/Balcão/doc derivados e indicadores têm requisitos agregados próprios no backlog, sem associação geográfica automática.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,141 @@
# InvesteMoz: três entregas para decisão da Tempo
**13/10/2026. Proposta: concluir primeiro o núcleo operacional das seis categorias base, em 36–64 horas de trabalho técnico restante.** A Tempo pode incluir também o percurso integrado já ensaiado, elevando o âmbito para 40–72 horas. Concluir todos os consumidores existentes corresponde aos 60–110 anteriores. As opções abaixo delimitam trabalho; não alteram flags, permissões, dados ou funcionalidades disponíveis.
Esta é a síntese da mesma auditoria, não um novo backlog. Os IDs, referências, versões e estados da matriz permanecem. A/B e C37 conservam os fechos válidos; C132 é um incidente separado. Nenhuma implementação, ativação ou nova prova funcional foi executada nesta reorganização.
## 1. Produto utilizável agora
### Disponível no ativo, com limites conhecidos
O endereço é **https://portal-investidor.test**, local à máquina onde o Laragon está instalado. O recibo de disponibilização de 12/10 identifica a entrega `2e2f16c83483`, código `a02ef2300d6c`, com as seis categorias base abertas. Este estado prevalece sobre relatórios históricos que ainda dizem workflow OFF.
| Funcionalidade | Entrada e perfil | O que a evidência permite afirmar | Limite atual |
| --- | --- | --- | --- |
| Autenticação e administração | `/login`, `/dashboard`, `/perfis/gestao`; titulares administrativos existentes | HTTPS, MFA, sessão, acesso ao dashboard e administração têm provas anteriores. Login/MFA/dashboard foram reconfirmados manualmente após a contenção C132. | C132 ainda espera as confirmações individuais de recuperação de Aurora, Palmira e Mario; não presumir que receberam acesso recuperado. C37 é o fecho específico da conta QA18. |
| Criar e acompanhar oportunidades | `/minhas-oportunidades`, `/minhas-oportunidades/create`; Promotor no âmbito atribuído | Navegação/política de Aurora, seis tipos, guardar rascunho, recursos e submissão estão disponibilizados; correção, revisão e publicação existem para os papéis independentes. | O primeiro processo documental legítimo no destino ainda não foi observado integralmente. A prova integral abaixo é QA. Publicação pública requer divulgação autorizada no próprio processo; disponibilização restrita não prova catálogo público. |
| Revisão e publicação | `/minhas-oportunidades`; Validador e Publicador com os âmbitos já atribuídos | Políticas e filas correspondem aos papéis. Administração de segurança não concede acesso operacional universal aos anexos. | Não declarar todas as variantes de cada categoria concluídas. As lacunas concretas estão no núcleo e no quadro por categoria abaixo. |
| País de constituição — COUNTRY02 | Cadastro mestre de organização pelo fluxo existente autorizado | 050000 instalado; duas colunas; histórico e organizações preservados. 030000/040000 também estão instalados e não são uma nova dependência de preparação. | O país mestre real da Tempo permanece sem valor confirmado. Não o inferir do NUIT/contacto; o preenchimento autorizado é posterior e não exige recriar a organização. |
Referência do estado ativo: `outputs/investmoz-workflow-opening-20261012/resultado.md`, manifesto de execução, `web-enabled.json` e `navegacao-perfis-leitura.json`. A disponibilidade não é convertida numa alegação de ensaio humano integral no destino.
### Percursos integralmente demonstrados em QA que já podem ser aproveitados
| Conjunto existente | Resultado demonstrado e correspondência | Limite que permanece |
| --- | --- | --- |
| Oportunidades das seis categorias base | Casos 30–35: edição/gravação/recuperação, submissão, correção, revisão independente, condição fundamentada, aprovação, disponibilização no âmbito ensaiado e histórico. Grupos WF6/MAT6 em `proof-groups.json`; AUD-OP-03/04 e AUD-PROFILE-08/09/11/12/28. | Casos sintéticos, não todas as modalidades. Projeto, imobiliário, terra, parceria e franquia têm disponibilização restrita; venda de negócio tem prova do teaser. Terra inclui um ramo positivo de simulação expressamente identificado, não um direito atribuído. |
| Arrendamento, coedição e transições já provadas | Caso 54 preserva renda 4500 MZN/mês, três documentos, correção/revisão/publicação restrita e nova sessão. LEASE54, COEDIT-GEO; suspensão/republicação 31 e recurso 34 têm recibos próprios. | Não repetir coedição ou os percursos completos sem mudança relevante. Restauração permanece decisão separada. |
| Percurso integrado do investidor A/B | Ideia → dossier → nova sessão → aplicabilidade → ferramenta financeira → resultado no dossier correto → Balcão → acompanhamento; tarefa independente enquanto terra espera; 320/390 px nos critérios aceites. Cinco fases e 19 etapas conservadas. | 190000 e a disponibilização ativa do percurso continuam separados. A/B não encerram todas as variantes das 19 etapas ou a acessibilidade integral. |
| Agronegócio do legado | Consulta pública → artigo → autenticação somente para guardar → dossier → referência → nova sessão → artigo, confirmado manualmente. AUD-LEG-04. | Apenas piloto comprovado; integração dos restantes setores, dispositivos e acessibilidade mantêm critérios próprios. Não está incluído no pacote ativo acima. |
| Documentos dos consumidores ensaiados | Originais/scan/recuperação e PDF fundiário de três páginas apresentado no browser, com hashes e provas anteriores preservados. | WebP 56, royalties/licença 56 e retirada documental após encerramento têm API/SQL, mas apresentação nova ainda pendente. PDF enviado, impressão do browser e gerador servidor são capacidades distintas; recibo Balcão atual é TXT. |
**O conector C135 impede novas observações automáticas nesta sessão, não invalida estes percursos já observados.** Não anunciar uma demonstração ao vivo automatizada disponível enquanto o transporte estiver ausente. API/SQL recentes de C133/C136 e código compilado de C134/C137 não entram nesta lista como percursos visuais integralmente concluídos.
## 2. Essencial para concluir o produto prioritário
### Núcleo proposto: operar as seis categorias base
Saída: uma oportunidade nas variantes expressamente incluídas pode ser criada, guardada incompleta, recuperada, completada, submetida, corrigida, revista independentemente, publicada no âmbito autorizado e acompanhada. Dados territoriais, países, documentos e materialidade necessários a esse processo devem conservar-se. A aprovação interna não representa decisão externa; a ficha e a interface devem distinguir publicação restrita de catálogo público.
| Item / requisitos existentes | Correções | Implementação restante | Verificação | Total | Dependência e critério de saída |
| --- | ---: | ---: | ---: | ---: | --- |
| Perfis, conflitos e acesso — AUD-PROFILE | 1–2 h | 0 h | 1–2 h | **2–4 h** | Atribuições existentes, sem novo registo/terceiro aprovador. Verificar apenas conflitos/revogação dos âmbitos incluídos ainda sem cobertura; titular administrativo não ganha acesso universal. C132 não está nesta parcela. |
| Contratos, materialidade e workflow das seis categorias — AUD-OP-01…05; AUD-PROFILE-08/11/12/28 | 3–5 h | 5–9 h | 4–6 h | **12–20 h** | Reutilizar WF6, MAT6 e LEASE54. Incluir C131/contactos e C136/materialidade; ver só variantes alteradas ou ainda abertas. Reabrir apenas pareceres afetados, manter assinaturas históricas, impedir autoaprovação. Recuperar estado/valores/documentos após a transição. Quadro por categoria abaixo. |
| Países/origem, filtros e estatísticas dos formulários incluídos — AUD-COUNTRY-01…07; AUD-STATS; AUD-FIELD | 2–3 h | 1–3 h | 3–4 h | **6–10 h** | País mestre, residência e origem separados; reutilizar C133, sem reescrever valores antigos. Completar consumidores do núcleo e C134 se o formulário de interesse for incluído. Submissão/replay → um registo/evento → filtro/indicador correto → nova sessão. |
| Seletores/mapas do núcleo — AUD-GEO/REL/FIELD | 1–2 h | 2–4 h | 3–4 h | **6–10 h** | Usar cadastro e correspondências inequívocas existentes; UI de 56 ainda aberta. Alterar pai limpa filhos, IDs recuperados, mapa explica limite administrativo/ausência de geometria, sem apresentar limite como parcela. A importação/publicação ativa é ação futura separada; não depende de resolver todos os 173 casos. |
| Documentos privados dos fluxos incluídos — AUD-OP-02; AUD-SCAN; AUD-LIB | 2–4 h | 1–3 h | 3–5 h | **6–12 h** | ClamD/fila/derivadas existentes e provas de recuperação reutilizadas. Recuperar original e derivada autorizados, negar acesso indevido e preservar original/histórico. Se uma lacuna de confidencialidade afetar o âmbito incluído, tem de ser corrigida. ACL individual desabilitada não é apresentada como funcional. |
| Acessibilidade das rotas do núcleo — AUD-UI | 2–4 h | 0 h | 2–4 h | **4–8 h** | Provas antigas de teclado/axe/320/390 px reutilizadas; observar apenas páginas/erros/estados alterados, rótulos, foco, leitura e controlos de mapa/documentos. C135 condiciona a parte visual nova; dispositivos físicos continuam prova distinta. |
| **Núcleo, sem duplicações** | **11–20 h** | **9–19 h** | **16–25 h** | **36–64 h** | QA e candidata delimitada; instalação/intervenção ativa separadas. |
As estimativas não são requisitos novos nem garantia de corrigir variantes desconhecidas nessa faixa. Correções significam comportamento existente com falha; implementação significa completar critérios já pedidos; verificação inclui apenas cobertura em falta e reconciliação da candidata. Não se reserva um teste por frase: uma prova pode cobrir vários IDs quando coincide o consumidor, campo, perfil, transição e resultado.
### Parcela de 12–20 horas por categoria
Estas parcelas já estão na linha de workflow acima. **Não voltar a somá-las**, nem incluir nelas as horas de mapas, países, anexos comuns ou acessibilidade.
| Categoria / caso reutilizado | Lacuna essencial no âmbito proposto | Critério específico | Parcela |
| --- | --- | --- | ---: |
| Projeto de investimento — 30/52 | Licenciamento aplicável, pressupostos do cenário e materialidade da evidência aninhada ainda sem percurso completo por variante. | Alterar o dado/evidência pertinente, recuperar e reabrir só a revisão afetada; não inventar viabilidade/aprovação externa. | **2–4 h** |
| Imobiliário — venda 31/arrendamento 54 | Compatibilidade/documentos e estados do ramo incluído; provas válidas de renda/correção preservadas. | Renda/periodicidade e documentos continuam íntegros; venda e arrendamento recuperáveis. Construção/ocupação/limites sem prova integral não são declarados concluídos. | **2–3 h** |
| Direitos sobre terra — 32 | Área/unidade, comunidades e encargos nos campos/consumidores efetivamente incluídos. | Evidência aplicável preservada; ausência de ato competente impede apresentar o direito como atribuído. Mapa administrativo continua distinto da parcela. | **2–4 h** |
| Venda de negócio — 33 | Mandato, histórico e apresentação do ramo incluído; o anúncio C133 não foi publicado por esse workflow. | Promotor real e autorização de divulgação recuperáveis; revisão independente e teaser autorizado; fixture não encerra publicação legítima. | **2–3 h** |
| Parceria de negócio — 34 | Contribuições/obrigações monetárias e não monetárias do contrato existente. | Valores/documentos/estado gravados; alteração substantiva reabre apenas as revisões afetadas. A sala de negociação não substitui a oportunidade canónica. | **2–3 h** |
| Franquia — 35/56 | UI dos ramos recentes de taxa/royalties/licença e condições de titularidade/exclusividade incluídas. | Reutilizar HTTP/SQL de C136 e royalties/licença; mostrar reabertura e conservação das outras assinaturas, recuperação e visibilidade correta. | **2–3 h** |
| **Total já incluído** | | | **12–20 h** |
Response permanece um **contrato de compatibilidade**, com IDs/história preservados e `normative_response_complete=false`. Completar os campos/recuperações utilizados no núcleo cabe neste âmbito; uma migração normativa integral de identidades/metadados não cabe nas 12–20 h e continua decisão/desenho próprio. Não criar aprovação fictícia, não perder referências e não chamar conformidade integral à compatibilidade.
### Dependências reais e ordem
1. Escolher o conjunto a concluir. Não alterar o produto por uma exclusão apenas proposta nesta síntese.
2. Fechar os comportamentos incluídos de contratos/perfis; países e documentos podem avançar em paralelo. Preparar estados/documentos QA antes dos ensaios; usar as atribuições existentes, não pedir novamente funcionários ou comprovativos externos da operadora Tempo.
3. Integrar seletores/mapas dos consumidores incluídos. Casos territoriais ambíguos e geometrias ausentes mantêm aviso e nomes, sem associação automática.
4. Executar apenas os critérios visuais novos após um transporte suportado estar disponível. C135 foi separado para suporte; não reiniciar portal/serviços para o resolver nem usar um protocolo alternativo proibido.
5. Fixar a candidata, confirmar dependências e preparar backup/restauro correspondente ao destino e acervo efetivamente incluídos. O ativo já tem 030000/040000/050000; verificar presença, não reinstalar. 190000 só entra se for escolhida a disponibilização do percurso integrado. Alteração ativa mantém autorização própria.
Critério de fecho: **a pessoa conclui a atividade incluída no ambiente previsto, vê o resultado e recupera-o noutra sessão, com acessos permitidos/negados corretos**. Compilação, testes e hashes sustentam esse resultado. Uma falta de prova visual relevante mantém a candidata desse âmbito sem aceitação visual; a indisponibilidade do conector não cria uma nova regra de negócio para a Tempo.
## 3. Evolução posterior
### Complemento dos percursos existentes: 24–46 horas
Adiar estas parcelas permite terminar o núcleo isolado; conserva os pedidos no mesmo backlog. Se a Tempo optar pelo percurso integrado como primeira entrega, a linha de dossier passa para o conjunto essencial, sem repetir A/B.
| Parcela já existente | Correções | Implementação restante | Verificação | Total | Conteúdo e dependência |
| --- | ---: | ---: | ---: | ---: | --- |
| Restantes consumidores de mapas | 1–2 h | 2–3 h | 1–3 h | **4–8 h** | Zonas/carteira/parcerias/Balcão/educação fora do núcleo. Não inclui resolver 173 correspondências sem dados inequívocos. |
| Balcão/orientação/CRM adicional | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Origem/atribuições/documentos/próxima ação dos consumidores restantes. A/B já provado; sem dependência de CRM externo e sem converter TXT em PDF por omissão. |
| Negócios/salas/bolsa adicionais | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Variantes de candidatura/marcos/exportação e C137 visual. C137 não bloqueia o workflow canónico se essas salas não forem incluídas; continua pendente no seu consumidor. |
| Dossier/percurso adicional | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Variantes existentes além de A/B e compatibilidade das cinco fases/19 etapas. 190000 apenas na entrega integrada; A/B não repetido. |
| Restantes setores do legado existente | 1–2 h | 3–5 h | 2–3 h | **6–10 h** | Biblioteca/contexto/fontes únicos; Energia/Mineração distintos, Turismo sem relações geográficas inferidas, Mercado Financeiro privado enquanto sem conteúdo. |
| Acessibilidade das rotas adicionais | 1–2 h | 0 h | 1–2 h | **2–4 h** | Apenas rotas deste complemento; horas do núcleo não são contadas outra vez. |
| **Complemento, sem duplicações** | **6–12 h** | **8–17 h** | **10–17 h** | **24–46 h** | Independente da aprovação de ofertas, competências modulares e SLA. |
### Incrementos adicionais já pedidos: 76–152 horas preliminares
| Incremento do backlog existente | Estimativa | Dependência própria |
| --- | ---: | --- |
| Simulador fiscal/contributivo | **16–32 h** | Regra/artigo, período, parâmetros disponíveis e cenários; fonte oficial já aceite, sem taxas/zeros substitutos. |
| Educação: rascunhos e jornadas/painéis | **12–24 h** | Perfis/contratos próprios; novas jornadas conservam a prioridade posterior já determinada. |
| Fundos | **8–16 h** | Dados reais de janelas/elegibilidade; não inventar fundos. |
| Comparador societário e modelos | **8–16 h** | Correspondência documental/legal e parâmetros. |
| Capitalização/guião da Bolsa | **8–16 h** | Fontes/processo e condições de aplicabilidade; não representa aprovação externa. |
| Negócios similares/importação de estabelecimentos | **12–24 h** | Fonte, identidade, deduplicação e critérios próprios. O interesse existente C133 é da faixa 60–110, não deste incremento. |
| Editor/versionamento de checklists | **8–16 h** | Regras configuráveis e versões. Checklists/gates existentes do workflow não são cobrados aqui outra vez. |
| Indicadores de utilização | **4–8 h** | Métrica/denominador/apresentação próprios. Filtros e estatísticas existentes de solicitações pertencem aos 60–110. |
| **Total, baixa confiança até contrato/dados por incremento** | **76–152 h** | Não é orçamento das quatro modalidades experimentais, ofertas ou SLA. |
Restauração, ofertas de financiamento/fornecimento, competências modulares e SLA/calendário/nomeações continuam decisões separadas. A proposta pendente de restauração é Publicador autorizado, motivo e auditoria, para revisão não pública, sem republicação automática; rascunho eliminado logicamente tem regra distinta. Não bloqueiam o núcleo normal se não estiverem nele incluídos. Fontes, geometrias de localidades/parcelas ou exemplares inexistentes não recebem um prazo fictício.
## Reconciliação das estimativas
| Âmbito | Correções | Implementação restante | Verificação | Total |
| --- | ---: | ---: | ---: | ---: |
| Núcleo recomendado | 11–20 h | 9–19 h | 16–25 h | **36–64 h** |
| Complemento existente | 6–12 h | 8–17 h | 10–17 h | **24–46 h** |
| **Faixa anterior de percursos existentes, preservada** | **17–32 h** | **17–36 h** | **26–42 h** | **60–110 h** |
| Incrementos posteriores distintos | Não decompostos antes do desenho por incremento | | | **76–152 h** |
36–64 + 24–46 = **60–110**; 60–110 + 76–152 = **136–262**. Se só o núcleo for escolhido, o saldo adiado é 24–46 + 76–152 = **100–198**, não outro orçamento a acrescentar ao total. O trabalho já provado não é novamente estimado. As parcelas são distribuição de planeamento do saldo anterior, com confiança média no código conhecido e menor nas variantes não ensaiadas; não são medições de execução nem datas prometidas.
Fora destes totais: espera/reparação do conector, confirmações e investigação C132, dispositivos reais, dados/fontes ausentes, resolução de todos os 173 casos cartográficos, migração normativa integral de IDs, decisões não aprovadas, janela/intervenção de ativação no destino. Estas exclusões não encerram requisitos nem significam zero esforço; não são necessárias para operar o núcleo se não afetarem o comportamento incluído. QA/build/manifesto da candidata estão na verificação; a execução ativa e o backup/restauro do destino serão delimitados quando a revisão estiver fixada.
## Opções concretas para a Tempo
| Opção | Produto a concluir | Trabalho técnico restante | Trabalho adiado da faixa 60–110 | Efeito |
| --- | --- | ---: | ---: | --- |
| **A — Núcleo operacional, recomendado para a próxima candidata** | Seis categorias nos ramos definidos, dados/documentos privados, revisão/publicação e acompanhamento; mapas/países/acessibilidade desses consumidores. | **36–64 h** | **24–46 h** | Termina um produto operacional delimitado; não espera legado, salas adicionais, novos simuladores, restauração ou §27 integral. |
| **B — Núcleo e percurso integrado do investidor** | A + variantes existentes do dossier/percurso, com cinco fases/19 etapas; aproveita A/B e prepara a dependência 190000 apenas para essa disponibilização. | **40–72 h** | **20–38 h** | Recupera a experiência integrada como parte da primeira entrega; sem repetir A/B nem construir jornadas educativas novas. |
| **C — Todo o âmbito existente** | A + todos os consumidores do complemento, incluindo legado setorial existente. | **60–110 h** | **0 h** | Mais cobertura transversal antes da candidata; ainda não inclui os incrementos posteriores 76–152. |
Redução adicional dentro de A só é concreta depois de a Tempo escolher as categorias/modalidades a excluir: não subtrair horas arbitrariamente nem retirar controlos essenciais de confidencialidade, independência ou gravação. Corrigir C136 e validar os critérios visualmente afetados não é dispensável numa entrega que inclua franquia. Pode-se adiar §27 integral, restauração, camadas não resolvidas e variantes imobiliárias não demonstradas sem converter isso em bloqueio de cadastro de rascunhos.
**Decisão solicitada: A, B ou C como âmbito da próxima candidata.** Nenhum pedido anterior é cancelado por esta escolha; o restante mantém o seu ID, referência e critério no backlog. Até à escolha, não se inicia uma expansão de desenvolvimento por conta desta síntese.
## C135: encaminhamento para suporte, separado do portal
Pedido sanitizado preparado em `C135-pedido-suporte.md`. Falha já registada: transporte IPC nativo ausente (`os error 2`), inventário apps/browsers vazio e `Browser is not available: iab`, antes de selecionar uma janela. Resets/importação documentados já falharam; não repetidos. Não foi estabelecida a causa específica no host.
**Estado do envio: não submetido.** Não há ferramenta/canal de suporte ligado que permita enviar o pedido nesta sessão. O canal oficial é feedback no compositor através de `/`; a documentação também identifica o reporte de problemas. [OpenAI Docs — Feedback and logs](https://learn.chatgpt.com/docs/reference/troubleshooting#feedback-and-logs). O texto pronto permite uma única entrega ao suporte, sem segredos nem o histórico integral da conversa. Não foi aberto um ticket fictício nem contornada a restrição da ferramenta. Alternativa de teste só será usada se estiver realmente disponível e permitida.
Sete grupos visuais novos continuam abertos: C131/contactos, C134/interesse, C137/retirada após encerramento, seletores/mapa 56, WebP 56, royalties 56 e licença 56. Cada opção inclui apenas os grupos que pertencem ao seu âmbito; os restantes não desaparecem da matriz.
@@ -0,0 +1,22 @@
# Demonstração existente — entrada única QA
**Entrada: https://portal-investidor.test:18445/dashboard.** Alvo exclusivo stability_consumers_20261011_084534_test:55441, 295 tabelas, cookie QApróprio Secure/Http Only/Same Site Lax, HTTPSreconhecido. HTTPS/HTTP/MFA testados; nova observação da interface indisponível pelo conector. Não é demonstração do ativo, nem depende dos funcionários reais.
Contas já existentes: Promotor 21, coeditor 22, Validador 24, Publicador 25, externo 23, Gestor 17. Usar as credenciais locais de cada sintético e a entrada específica do seu autenticador; não copiar segredos/códigos/cookies para chat/evidências. Fixtures correspondentes estão no armazenamento privado já usado; não criar novas identidades nem desativar MFA.
| Passo a partir do dashboard | Perfil/URL QA | Resultado esperado/cobertura |
|---|---|---|
| Abrir Minhas oportunidades/Nova oportunidade |21: `/minhas-oportunidades` e `/minhas-oportunidades/create` |Menu habilitado nas seisbase; criar nova preparação incompleta é permitido. Não modificar casos de prova publicados para esta observação.|
| Observar edição/guardar/recuperar |21: `/minhas-oportunidades/16/edit` |Draft existente recuperável; testar só nova correção de contacto sem perder valores. Normais operações do draft já têm provas anteriores.|
| Contacto C131 |21, draft 16, formulárioexistente |`Contacto`+espaços internos+`QA auditoria`normaliza 21 caracteres; campo curto 422; válido→contactoúnico/replay, refresh/nova sessão. HTTP/persistência demonstrados; aparência/foco do erro atual pendentes.|
| Observar um processo submetido |24: `/minhas-oportunidades/17/view` e lista |Caso sintético 17 submetido. Criador não aprova a própria criação; revisão/condição/documentos/atribuição seguem âmbito. Esta rota 17 deve ser suplementada visualmente, não foi incluída nos 96 GET dirigidos.|
| Observar aprovação e publicação |25: `/minhas-oportunidades/20/view`(aprovado); casos 30–35/54 publicados |A publicação restrita não coloca automaticamente no catálogo público. Provas históricascorreção→aprovação 24→publicação 25 reutilizadas; não repetir transições sem critério restante.|
| Arrendamento |21/24/25: `/minhas-oportunidades/54/view` |Renda 4500 MZN/monthly preservada em documentos/correção/revisão/publicação restrita/nova sessão, conformeprovas anteriores. Variantes não demonstradas claramente indisponíveis para submeter.|
| Recursos/mapa |21/24/25: `/minhas-oportunidades/30/resources` |200 com recursos; permissõesde edição específicas. Arquivo não oferece restauração proposta; publicação não abreoriginais. Seleção/drawjátemprovashistóricas específicas, consumidoresrestantespendentes.|
| Negação |23: `/minhas-oportunidades/30/view`, `/resources`, `/response` |403 na sessão corrente;96 GET dirigidos confirmam todosos oito casosfora do âmbito.|
| Diagnóstico C132 |Semlogin: `/_inertia/devtools/entries` |404 mesmoambiente local apóscorreção QA; não existecapacidade de leitura diagnóstica pública no delta.|
| Gestão antiga/estatísticas |17: `/management/opportunities`, `/management/opportunity-origin` |200; não substituir Promotor/Validador/Publicador por Gestorlegado. `/management/negocios`403 nestegestor épolítica própria, semprova de botãoinútilno menu.|
Casos publicados existentes:30 projeto,31 imobiliário,32 terra,33 venda,34 parceria,35 franquia,54 arrendamento. Mostram resultados conhecidos e recuperação, não garantem todasas variantes. Cenas de correção intermediária não existem para todos nesse retrato; não fabricar um historial nem restaurar publicações para as demonstrar.
Limitações: legado/percursointegrado/experimentos/notificações OFFna QA 18445 atual. Os percursos A/B e legado anteriormenteobservados permanecem evidências no clone respetivo, não novos fechos decorrentes deste roteiro. Não pedir novos MFAreais nem repetir C37/A-B. Quando umaetapa nãoestiver disponível, registar ocritério e deixar explícita a lacuna.
@@ -0,0 +1,91 @@
<!-- option-B3-exit-table-20261013 -->
## Opção B: tabela única dos critérios de saída
[Tabela atual: concluído/prova, trabalho executável, C135 e dependência concreta](saldo-opcao-B.md).22 grupos, sem novos IDs ou outro backlog; A/B/C37 preservados.25–43 h estimadas restantes (5–10 correções+5–10 implementação+15–23 verificação), não horas consumidas nem prazo garantido.
Projeto 30: PDF próprio/scan real/hash, licença aplicável sintética, revisão jurídica apenas, aprovação 24/publicação 25 restrita e outra sessão; visual ainda aberto. Scanner QA13310 tinha assinaturas >48 h; atualizado só emQA, limite intacto/fila alheia preservada. Sem delta de código do produto ou recompilação. Ativo intacto; candidata final não fixada.
C132 separado:14–17 confirmadas, recuperação individual concluída; investigação histórica/limites ainda abertos. Sem envio, rotação ou alteração ativa. As secções datadas abaixo preservam o histórico; para o estado atual usar esta tabela.
<!-- /option-B3-exit-table-20261013 -->
<!-- option-B2-saldo-20261013 -->
## Opção B: saldo atualizado, C140/C141 e critérios restantes
[Saldo por critério, consumidor, bloqueio e esforço](saldo-opcao-B.md). **Restam 25–43 h técnicas**, reestimativa da faixa 40–72, separadas em 5–10 correções, 5–10 implementação pedida e 15–23 verificação. Não é percentagem de conclusão nem tempo medido; espera C135/ativação/evolução fora. B continua sem candidata final.
C140: unidade explícita da parcela guardada/recuperada emQA, sem converter área 1100; apenas cadastral reabre. C141: preparação de área/unidade incompleta guardável; submissão 422→completar par→revisões/condição preexistente→aprovação 24/publicação 25 restrita→nova sessão.148 tarefas anteriores e originais/dossiers preservados; 6 tarefas novas próprias, sem prazos. Interface nova aberta por C135, separado das falhas do produto.
A/B e C37 preservados. C132 separado:14/16/17 confirmadas, apenas 15 pendente; nenhum segredo/envio/rotação/alteração ativa. Zero alterações do portal ativo.
<!-- /option-B2-saldo-20261013 -->
# Opção B: âmbito fixado e primeiro incremento executado em QA
13/10/2026. [Âmbito e aceitação fixados antes da execução](ambito-B-aceitacao-QA.md), SHA-256 `7583e2f85bed065efc0d8592bdfd304144de7b8b6d390230e2ee049e45422714`. A Tempo autorizou B exclusivamente em QA. Este incremento **não encerra B nem é pacote pronto para ativação**; completa critérios novos por HTTP/SQL e prepara a interface correspondente.
## Resultados deste incremento
| Item / requisitos | Percurso e resultado | Evidência / limite |
| --- | --- | --- |
| Preparação do percurso — AUD-DESK-02 | QA real `stability_consumers_20261011_084534_test:55441` confirmada antes de escrever.030000/040000/050000 e a migração exata `2026_10_09_190000_prepare_investor_path` já instaladas. Flag `INVESTOR_PATH_ENABLED` OFF era a causa da indisponibilidade neste clone; habilitada apenas no ficheiro QA.5fases/19etapas e13contextos existentes recuperados; dossier privado alheio403. | `option-B-preflight-before-enable.json`, `option-B-enable-path-QA.json`, `option-B-read-path-HTTP.json`. Zero instalações repetidas. Configuração ativa intacta; não é nova demonstração visual A/B. |
| Franquia/exclusividade — AUD-OP-03/04, AUD-PROFILE-28 | Caso56: revisão→exclusividade alterada→submissão; reabre marca/licença e legal. Financeiro/confidencialidade mantêm hash/ator/data. Autor autoaprovação403; aprovação antes das revisões422; revisão/aprovação24→publicação25→nova sessão. Taxa1250, royalties e licença intactos. | `option-B-franchise-exclusivity-HTTP.json`. Publicação **interna/restrita**, sem documentos novos. UI desta variante permanece aberta. |
| C138, país/origem e apoio fundiário — AUD-COUNTRY-03/04, AUD-GEO-02, AUD-STATS-01 | Rascunho incompleto→guardar Portugal/residência, BR/origem e CaboDelgado→Ancuabe/distrito→Ancuabe/posto→Ancuabe-Sede→submeter apoio→nova sessão→recuperar. Mesmo envio devolvia409 antes; agora202 com o mesmo recibo. Dados diferentes409, não titular404/anónimo401. | `option-B-land-country-before/after-HTTP.json`. Não atribui terra, direitos ou geometrias de parcela; mapa/UI por observar. |
| Estatísticas e não duplicação | FiltroISO PT/origemBR recupera o recibo com valor legado Portugal. Repetições não aumentam estatísticas de origem. SQL confirma1caso/interest/recibo/consentimento/outbox/evento support_requested; versão3 mantida. | `option-B-land-statistics-HTTP.json`, `option-B-final-SQL.json`. Coleções de origem separadas; país/pesquisa filtram a listagem. Não declarar os totais globais como se todos esses filtros se aplicassem. |
| C139, maturidade pública — AUD-OP-01/03/04, AUD-PROFILE-28 | Filtro público7/8 dava422. Agora usa8posições; referências contêm catálogos V2/histórico distintos. Caso33 passou etapa7 e depois8 por edição→submissão→aprovação24→publicação pública25→pesquisa/ficha→nova sessão. Versão pública V2, nível e rótulo coincidem; dados privados ocultos. | `option-B-C139-before-HTTP.json`, `option-B-public-maturity-workflow-HTTP.json`. Esta publicação é pelo workflow real QA, não estado preparado. Interface nova continua pendente. |
| Projeto/licença — AUD-OP-03/04, AUD-PROFILE-28 | Caso 30: identificação da licença alterada, aplicabilidade “não aplicável” conservada; reabre apenas revisão jurídica/territorial, preserva a técnica; aprovação 24 → publicação restrita 25 → nova sessão com os campos guardados. | `option-B-project-license-HTTP.json`. Não representa licença concedida ou novo documento aplicável. |
| Parceria/contribuições | Caso 34: capital 1000 → 1250 e descrição de ativos não monetários; reabre financeiro/governação, conserva societário/legal; aprovação 24 → publicação restrita 25 → recuperação integral. | `option-B-partnership-contribution-HTTP.json`. Obrigações adicionais e salas continuam com critérios próprios. |
| Terra/área e comunidade | Caso 32: área 1000 → 1100 e comunidade afetada. Draft incompleto recuperável; submissão 422 junto à consulta. Área/comunidade reabrem cadastral/comunitária, conservando jurídica/autoridade. A publicação mantém 422 enquanto a consulta não está concluída, mesmo após aprovação interna. Na continuação **sintética QA**, a conclusão simulada reabre apenas comunidade, mantém os outros três pareceres; 24 aprova → 25 publica restrito → nova sessão. | `option-B-land-community-HTTP.phase1.json`, `option-B-land-community-HTTP.json`. Nenhum ato/direito real. Unidade da área não existe neste schema canónico; documentos de consulta específicos ainda não demonstrados, reutilizaram-se peças próprias da oportunidade. |
| Negócio/exercício realizado | Caso 33: lucro do exercício 2025, 50 → 65; apenas financeiro reabre. Societário/legal/confidencialidade mantêm hash/ator/data. Aprovação 24 → publicação pública 25 → recuperação dos períodos/valores noutra sessão. | `option-B-business-history-HTTP.json`. Não cobre mandato nem entidade sem exercícios; a proposta modular não foi ativada. |
| Compilação e recursos — AUD-UI-01 | TypeScript e compilação de produção passaram;159ficheiros preparados, incluindo manifesto.157recursos referenciados no manifesto servidos porHTTPS com hash correto, sem ignorar TLS. HTML do catálogo entrega registo33/nível8 e8etapas. | `option-B-build-QA.json`, `option-B-web-verification.json`. Manifesto QA `982aa0666bb1f75fb5d9616737f11c918059caa3925ff93177ad7d85a68ecb7f`; anterior e assets conservados. Servir HTML/chunks não é observar a interface. |
As correções C131/C133/C134/C136 preparadas anteriormente são reutilizadas no conjunto B; C137 e salas adicionais permanecem fora. Notificações, CRM/AI externos continuam OFF. Não houve migrations, nova identidade, concessão de permissões, alteração de serviço ou escrita ativa.
## Causas e correções
**C138:** o controlador fundiário recusava `support_requested` antes de chamar `InterestSubmission`. A chave estável e o recibo já existiam; a pré-condição de estado impedia recuperar a resposta após perda do primeiro retorno. A correção mantém autenticação/titularidade/validação, verifica versão e equivalência do payload, reutiliza chave/serviço existentes e devolve o caso sem nova revisão/evento. Conteúdo alterado ou recibo inconsistente é recusado. Apenas `LandAssistanceController.php` em QA; não cria tabelas nem muda regras de consentimento.
**C139:** o consumo público mantinha `between:1,6`, a interface usava os seis rótulos históricos e a publicação não projetava a etapa canónica explicitamente aprovada. A correção reutiliza `OpportunityMaturity`, valida1–8, fornece os dois catálogos, projeta etapa/rótulo/versão na publicação e conserva os valores públicos anteriores no histórico, sem inventar versão histórica ausente. A API expõe somente a versão publicada; não revela o draft/contexto privado. O filtro é por posição, não converte semanticamente posições1–6 entre catálogos. Rótulos históricos e restantes cadastros não são renumerados.
Erros do harness ficaram separados: importação de módulo com hífen, pressuposto de coluna `id` numa tabela pivot, chave `title` em vez de `official_title` e colunaID do backlog. Corrigidos sem os tratar como falhas do portal. A revisão já iniciada33 foi aproveitada; não houve repetição da ação bem-sucedida.
## Preservação e estado da candidata
SQL READ ONLY reconcilia casos/Balcão/journeys/rascunhos/documentos/memberships/organizações anteriores por hash. As132tarefas anteriores também permanecem iguais. As 16 novas tarefas pertencem só às revisões/publicações 30/32/33/34/56, com prazosNULL; não foram inventados SLA ou titulares. Os únicos dados novos fora dessas revisões são o caso fundiário sintético e o seu único recibo/consentimento/outbox/evento.
Código/configuração/bundle ativos são verificados contra os hashes anteriores e permanecem intactos. A contenção C132 não é reaberta. A conta 16 confirmou manualmente entrega/MFA/dashboard; faltam 14/15, sem novo ensaio ou alteração ativa. A matriz conserva3.401IDs/linhas e7.739ocorrências;11 requisitos existentes recebem evidência (10 de B e a confirmação separada de C132), 27 grupos de provas. Nenhum novo requisito, fecho agregado ou visual. A/B/C37 preservados.
O pacote deste incremento consolida fontes preparadas de B, compilação, âmbito, matriz e provas para revisão. **A revisão final de B ainda não está fixada:** faltam as verificações abaixo. Não renovar/apresentar um backup como correspondente a uma candidata final que ainda pode mudar; conservar as provas anteriores e renovar backup/restauro da revisão/acervo efetivamente finais antes de propor ativação. Não foi efetuado um novo backup do ativo nem o seu restauro.
## Demonstração integrada preparada no ambiente QA
Entrada única: **https://portal-investidor.test:18445/dashboard**. Usar exclusivamente as contas sintéticas deste ambiente e as suas instruções locais; não enviar credenciais ou códigos para a conversa.
| Perfil / acesso | O que observar | Limite da evidência |
| --- | --- | --- |
| Investidor QA18 → `/investimentos` | Selecionar dossierA `73bf1982-d182-4588-a153-07e933bdbe12`: sem terra/financiamento externo,5/19,2resultados e2pedidos. DossierB `4ff5555c-ab50-4c5f-bb83-89aa84e776fa`: ambos necessários,1resultado/1pedido/1tarefa eS10a aguardar. | A/B já aceites: localização por leitura e dados preservados; não repetir testes. Resultados, pedidos, contexto de ferramentas e preparação paralela já ensaiados. |
| Promotor QA21 → `/minhas-oportunidades` | Criar/guardar rascunho pelo dashboard; consultar 30/32/33/34/56, histórico, versões, recursos e resultados recentes. | Base e arrendamento visuais anteriores reutilizados; as novas variantes são provas API/SQL. Não usar Auditor/Superutilizador como substituto do Promotor. |
| Validador QA24 / Publicador QA25 → mesma fila | Consultar decisões/revisões e publicação do âmbito autorizado. 33 é público; 30/32/34/56 são restritos. | Revisões/publicações novas foram ações autenticadas distintas; clicabilidade/apresentação novas ainda por observar. |
| Público, sem login | `/oportunidades?maturity_level=8&opportunity_id=33&include_national=1`; ficha `/oportunidades/inv-mz-gen-4570398436803108` | HTML/API/chunks corretos; ficha não expõe documentos/contexto privado. Seleção/rótulos/foco/móvel novos ainda por observar. |
| Promotor QA21 | `/investidor/terra-duat/01a133c2-1596-7270-a361-268574380c75` | Caso sintético deC138; recuperar país/origem/território/recibo. Esta preparação de apoio não é submissão oficial nem decisão sobre terra. |
O quadro prepara uma revisão do produto existente; não é pedido para o proprietário executar sucessivamente testes incompletos. `option-B-demo-existing-AB.json` identifica os mesmos dossiers por leitura, sem nova sessão18 ou alteração dos cenários.
## Critérios restantes de B
- Visual dos novosC131/C134/C138/C139, seletores/mapas/WebP e ramos recentes de royalties/licença/exclusividade. C135 continua sem transporte; sem resets, protocolo alternativo ou teste visual declarado por API. Pedido de suporte preparado, não submetido por ausência de canal ligado.
- Semântica/documentos das variantes ainda sem prova: licença aplicável/evidência específica de projeto, unidade canónica de área e documentos próprios de consulta, mandato e outras variantes do negócio. Identificação de licença não aplicável, comunidade sintética, exercício existente e contribuições de parceria passaram em HTTP; os critérios visuais correspondentes continuam abertos.
- País mestre reutilizado e consumidores/estados adicionais incluídos, sem misturar residência, constituição e origem. Este fundiário prova o requerente individual, não uma entidade real.
- Mapas/apresentação, permissões/documentos e acessibilidade dos consumidores incluídos ainda sem prova. Dispositivos reais permanecem distintos; documentos etiquetados/§27 integral não são anunciados completos.
- Compatibilidade das variantes do percurso19etapas ainda sem prova e consolidação final, com compilação/manifesto e backup/restauro correspondentes. As provas A/B cobrem os critérios aceites, não todas as variantes.
Próximo trabalho executável dentro do mesmo B: reconciliar a unidade da área com o contrato aprovado e os recursos existentes; licença/evidência aplicável e mandato do consumidor correto; países/documentos restantes. Não repetir as variantes API concluídas de projeto, comunidade, exercício e parceria. Não amplia o âmbito, não ativa o destino e não repete os fechos válidos.
## Confirmação separada do incidente C132
Mensagem do responsável em 13/10: **conta 16 — recebido, MFA configurado e dashboard acessível**. Registo manual em `C132-account16-manual-recovery.json`; não é observação nova pelo conector. Conta 17 já confirmada. Restam 14 e 15, além dos limites conhecidos da investigação histórica; o incidente continua aberto. Nenhum segredo, envio, rotação, sessão ou configuração ativa foi alterado por este registo.
## Dependências e reversão do incremento
As migrações 030000/040000/050000/190000 já estão instaladas no clone e não foram repetidas. Mantêm-se cifra, scanner e configuração dos serviços existentes; este lote não consome filas alheias. As peças e relações documentais anteriores ficaram intactas. As novas revisões exigem apenas os perfis sintéticos já existentes, sem nomeações reais nem SLA.
QA: conservar os backups privados de fontes, manifesto/assets e flag anteriores. A reversão técnica restaura apenas os ficheiros/configuração do clone, preservando o histórico dos ensaios e dados; não reautoriza acessos revogados nem apaga versões. O pacote de revisão contém hashes das fontes/bundle preparados, não os backups privados. Não é um pacote de ativação e não comprova novo backup/restauro do destino. Esse ensaio correspondente será renovado depois de fixar a candidata final de B.
@@ -1,24 +1,59 @@
<!-- portal-stability-authorized-activation-20261011:begin -->
## Estado mais recente — COUNTRY02 ativo, revisão 485ee04c40b2
Somente `050000` foi aplicada pela interface autenticada em 11/10/2026 às 10:39:39 UTC e COUNTRY02 habilitado às 10:39:51 UTC. Prévia correspondente à revisão/código/backup/destino `investemoz:5432`; aplicação302, repetição200 com mesmo recibo e conteúdo diferente/mesma chave409. Verificação READ ONLY final em 2026-10-11T10:49:16+00:00: duas colunas opcionais, 288 tabelas, 13 contas, zero organizações/representações, 80 migrations e 127 audits. Uma auditoria de instalação; nenhuma nova tabela, conta, organização ou representação. Restantes flags OFF e pacotes 030000/040000/190000 ausentes.
Chromium confirmou HTTPS reconhecido, login/MFA, perfil, atualização e voltar/avançar com histórico cifrado. Nova sessão com segundo MFA e GET do perfil 200/no-store, acompanhada de confirmação manual. Logout 302/API 401 e Voltar ao login sem perfil privado. Chave/cipher e MFA originais preservados; rotação normal de `remember_token` do ator 13 reconciliada por comparação campo a campo, sem exportar valores.
Backup/restauro real correspondente verificado às 10:03:46 UTC (288 tabelas, 31 sequências, 379 ficheiros e 2 MFA); hashes do pacote/backup e código/bundle instalados conferidos. Certificado/cookie/runtime/vhost predefinido e 46 ativos carregados aprovados. C118: Laragon regenerava o vhost `auto.`; bytes HTTPS aprovados conservados no ficheiro personalizado sem esse prefixo. Arranque direto único aceite expressamente pelo responsável; nenhum hash do pacote mudou.
**Gravação ativa do país mestre permanece pendente de uma organização legítima e representação autorizada (0/0).** Esse critério mantém AUD-COUNTRY-02 parcial, embora a extensão esteja ativa. AUD-OPS-01 permanece parcial pelos restantes consumidores/pacotes. A/B e C37 preservados; não se encerram a auditoria global nem outras decisões.
Mesma matriz: 3393 requisitos/linhas e 6845 referências; 7 concluídos, 3386 abertos (3235 parciais, 145 não implementados, 1 implementado mas não ativado e 5 decisões concretas). Apenas AUD-COUNTRY-02/AUD-OPS-01 atualizados. [Resultado, auditoria e limites](../../../../outputs/investmoz-portal-stability-activation-20261011/resultado.md) e [ajustes operacionais](../../../../outputs/investmoz-portal-stability-activation-20261011/ajustes-execucao.md). Contenção somente COUNTRY02 OFF preserva HTTPS/schema/dados/histórico; restauro completo continua sujeito a decisão separada. Blocos abaixo são histórico anterior.
<!-- portal-stability-authorized-activation-20261011:end -->
<!-- portal-stability-20261011:begin -->
## Estado atual — estabilização integrada QA, ativação suspensa
**A instrução de suspensão substitui qualquer passo histórico para retomar a ativação. COUNTRY02 permanece desabilitado no ativo.** A autorização anterior `13644ed74a48`/`162daff6ce08` fica registada no âmbito original, sem aprovar automaticamente os acréscimos da revisão fixa `485ee04c40b2`. Nenhuma alteração ativa nesta estabilização; Apache ativo não reiniciado.
COUNTRY02 foi demonstrado no Chromium com Apache/PHP do destino, hostname `portal-investidor.test`, HTTPS reconhecido e produção final: estado anterior → login/MFA → prévia → instalação somente 050000 → replay único → perfil/PT/F5 → MZ/v3 → voltar/avançar cifrados → logout/API401/Back sem master → nova sessão/MFA/recuperação. SQL: duas colunas, zero tabelas novas, uma auditoria de instalação, duas edições cifradas; fixtures apenas em QA. Backup original real restaurado (288 tabelas/31 sequências/379 ficheiros/2 MFA) e backup pós-utilização QA também restaurado, preservando os dados novos.
Frente C110–C112 consolidada com C113–C117: 25 chamadas em 14 componentes usam utilitário CSPRNG comum; cURL/DLL corrigido só na cópia Apache QA; OPcache isolado; GeoJSON por feature dentro de 128 MiB; bootstrap MFA normal sem recifrar; mensagens consecutivas não perdem texto. Critérios e limites individuais no relatório. O clone cartográfico atual contém 408 registos com hash integral preservado; 393 é histórico. Não houve divulgação nem instalação de outros pacotes ativos.
Ativo lido às 09:40:51 UTC: 13 contas/0 organizações/0 representações/79 migrations/126 audits; 050000 ausente, flag false e código/config/bundle/chave/dados originais. Dados mestres legítimos/vínculos continuam necessários para a gravação real do país, mas não para DDL. Faltam a apreciação explícita do delta e o levantamento da suspensão antes de disponibilizar. Ofertas, competências modulares, SLA, workflow/documentos/cartografia/acessibilidade/dispositivos reais mantêm os critérios próprios. A/B e C37 preservados, sem repetir os ensaios completos.
[Relatório e limitações](../../../../outputs/investmoz-portal-stability-20261011/relatorio-estabilizacao.md) · [Causas/reprodução](../../../../outputs/investmoz-portal-stability-20261011/casos-reproducao.md) · [Consumidores/rotas/perfis](../../../../outputs/investmoz-portal-stability-20261011/cobertura-consumidores.md) · [Manifesto fixo](../../../../outputs/investmoz-portal-stability-20261011/manifesto-candidata.json) · [Procedimento único e reversão](../../../../outputs/investmoz-portal-stability-20261011/procedimento-unico.md).
Mesma matriz: 3393 requisitos/3393 linhas/6845 referências, 7 concluídos e 3386 abertos (3234 parciais, 145 não implementados, 2 implementados mas não ativados, 5 decisões concretas). Somente AUD-COUNTRY-02 e AUD-OPS-01 receberam critérios novos; restantes células/referências preservadas. Os blocos abaixo são histórico datado.
<!-- portal-stability-20261011:end -->
# Execução do percurso InvestMoz — I0 e I1–I3 em QA
<!-- qa-semantic-20261010:begin -->
## Resultado atual por categoria — semântica e atribuições em QA, 10/10/2026
Este bloco é a evidência mais recente desta matriz; as secções anteriores abaixo permanecem como histórico. Estados antigos sobre objetos opacos, coordenação editorial e ausência de 190000 ficam confrontados com os resultados concretos deste bloco. **Código preparado e HTTP/persistência em QA não encerram interface nem funcionalidade ativa.** Não houve escrita na base ativa. C37 e aceitação visual permanecem pendentes.
Servidor **http://127.0.0.1:18097**, base **desk_restore_20261009_174726_test:55441**, Fortify e MFA normais. **Promotor QA 21** continua a conta de ensaio do dashboard. Não usar Auditor ou Superutilizador em seu lugar.
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| --- | --- | --- | --- | --- | --- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| ------------------------- | -------------------------------- | ------------------------------- | ------------------------------- | ------------------------- | --------------------------------------------- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
As dez categorias recuperaram dados noutra sessão autenticada. As seis com contrato definido aceitaram os cenários semânticos documentados; as quatro restantes conservaram rascunhos, sem inventar um perfil modular para as submeter. Fundiário #32 separa aprovação interna da decisão externa. Venda #33 passou depois pelo percurso editorial público, sem divulgar resumo/dados privados.
@@ -36,40 +71,41 @@ As dez categorias recuperaram dados noutra sessão autenticada. As seis com cont
Mesma matriz: **3.386 requisitos / 3.386 linhas**, **6.838 ocorrências de origem**. IDs, fontes, critérios, versões divergentes e referências anteriores conservados.
| Estado canónico | Requisitos | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências de origem |
| ------------------------------- | ---------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31 e AUD-OPS-01**, em [matriz-requisitos.csv](matriz-requisitos.csv). Nenhum desses critérios visuais foi fechado por API.
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Incremento canónico e workflow em QA — 10/10/2026
Servidor **http://127.0.0.1:18097**; destino guardado **desk_restore_20261009_174726_test:55441**. Zero escritas na base ativa. **C37 e toda a aceitação visual deste incremento permanecem pendentes.** Props da interface, API e persistência foram verificadas; nenhum clique ou renderização no navegador foi observado.
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --- | --- | --- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
Os requisitos acima continuam **parciais**: nenhum passou a concluído pelo incremento. O detalhe está no [relatório do workflow](workflow-oportunidades-qa.md); fontes, versões, critérios e percursos permanecem na [mesma matriz](matriz-requisitos.csv).
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| ------------------------------ | ----------------------------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requisitos abertos**. As referências e versões anteriores foram preservadas.
@@ -77,6 +113,7 @@ Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requ
<!-- qa-workflow-20261010:end -->
<!-- qa-profiles-v1-20261010:begin -->
## Cobertura após perfis v1 — 10/10/2026
I0–I3 permanecem em QA. Cinco fases e 19 etapas preservadas, sem renumeração. C37, A/B e C43 visuais continuam pendentes. A autorização organizacional reutiliza OpportunityManagement, Resources, Fortify e entidades existentes; nenhuma jornada educativa nova foi iniciada.
@@ -94,6 +131,7 @@ Coordenadores, pareceristas, suporte e recurso estão explicitamente mapeados na
> Registos anteriores preservados como histórico. Os estados correntes são os da matriz e do bloco mais recente acima; uma entrega posterior não altera retroativamente a evidência anterior.
<!-- qa-dashboard-20261010:begin -->
## Continuação independente C43/C44 —10/10/2026
QA exclusiva: http://127.0.0.1:18097, alvo real `desk_restore_20261009_174726_test:55441`. Ativo consultado por transação SQL READ ONLY; 0 escritas/instalações/publicações ativas. Cinco fases/19 etapas, 5 dossiers/95 etapas e 393 geometrias QA preservados. C37 e aceitação visual permanecem abertos.
@@ -114,37 +152,38 @@ Revisão atual não candidata; nenhuma aceitação integralI 1–I3 por contagem
<!-- qa-dashboard-20261010:end -->
<!-- qa-independent-20261010:begin -->
## Lote independente I0–I3 — 10/10/2026
QA exclusiva: http://127.0.0.1:18097; alvo confirmado `desk_restore_20261009_174726_test:55441`. Testes de feature usam outra QA, `investmoz_test:55441`, com guarda antes de qualquer escrita. Sem alterações, instalação, importação ou publicação na base ativa. Cinco fases/19 etapas preservadas;5 dossiers/95 etapas na QA web, sem criação de jornadas educativas.
| Requisito | Entrega e prova | Critérios ainda abertos |
| --- | --- | --- |
| AUD-GEO-01/02/03; C38 | Correspondências explícitas Maputo Província, Maputo Cidade e Matola; descendentes por nome exato+pai. Ação autenticada/MFA no servidor 18097 insere 32 limites internos:2 províncias+8 distritos+22 postos. 361 originais e 1990 geo_locations preservados. 32/32 novos recuperados via endpoint consumidor; público: 0/32. 393/393 contextos por serviço;1920/1920 referências territoriais por API. ProvinceSelect liga o nome guardado ao preview sem reescrever valores. |31 distritos/157 postos por nome; localidades sem polígonos neste exemplar; integração renderizada por consumidor e ato de divulgação separados. |
| AUD-COUNTRY-01–04/06–07, STATS-01 | Provas renovadas por método/formulário: perfil/empresa/manifestação/público/quatro apoios/carteira/interesse público em negócio/wizard/fundiário/três Balcões/simulador/CRM. Gravação→GET→filtro→agregado quando aplicável; residência/constituição/fiscal/fundos distintos da origem declarada; unknown preservado. |Seleção, recibos, variações condicionais, filtros/tabela e nova sessão na interface. Não contar testes documentais selecionados pela palavra original como requisitos de países. |
| AUD-LAND-01, PART-01, LIB-01/02, SCAN-01; C39/C40 |404 dos originais cifrados corrigido em fundiário e sala de parceria por VerifiedDocumentBinary comum; novos uploads registam tamanho/autor. PDF/PNG/JPEG com ClamD real, hash, quarentena/perfis/partilha/revogação/adulteração/recuperação. Lote documental QA privado, idempotente, sem substituir identidade conflituosa; actor sem permissão/ambiente ativo recusados. |Renderização PDF/impressão, ações visuais e restantes consumidores/tipos; lote ativo autenticado. Serviço ClamD real demonstrado separado de arranque/manutenção permanente/GD ativo. |
| AUD-OP-02/SCAN-01; C41/C42 |PDFs sintéticos apenas com cabeçalho não provavam legibilidade: novos testes usam PDF válido de uma página, parseado independentemente. No servidor 18097, novo PDF anexado à oportunidadeQA12→scan real→download→nova sessão→recuperação; outra conta 403. Cinco binários anteriores preservados por SHA; PNG/3WebP recuperados, sem novo scan das derivadas. Credenciais fixas do script removidas; passwords/remember tokens de dois atoresQA auxiliares rodados; MFA/conta 18 preservados. |PDF renderizado e interface documental pendentes. O placeholder anterior permanece conservado como evidência e não certifica abertura de PDF. |
| AUD-OP-03/04 |Schema normativo §26 preparado e rastreável:110 definições,9 contratos Create/Patch/Response, sem renumerar IDs. |Workflow e validação/gates especializados continuam não implementados; nenhum fecho funcional atribuído ao artefacto. |
| C37, AUD-UI-01, I1–I3 |Evidências anteriores conservadas, nenhum novo ensaio de login investidor neste lote. |Login/reload/logout/nova sessão e A/B completos na interface continuam pendentes. |
| Requisito | Entrega e prova | Critérios ainda abertos |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-GEO-01/02/03; C38 | Correspondências explícitas Maputo Província, Maputo Cidade e Matola; descendentes por nome exato+pai. Ação autenticada/MFA no servidor 18097 insere 32 limites internos:2 províncias+8 distritos+22 postos. 361 originais e 1990 geo_locations preservados. 32/32 novos recuperados via endpoint consumidor; público: 0/32. 393/393 contextos por serviço;1920/1920 referências territoriais por API. ProvinceSelect liga o nome guardado ao preview sem reescrever valores. | 31 distritos/157 postos por nome; localidades sem polígonos neste exemplar; integração renderizada por consumidor e ato de divulgação separados. |
| AUD-COUNTRY-01–04/06–07, STATS-01 | Provas renovadas por método/formulário: perfil/empresa/manifestação/público/quatro apoios/carteira/interesse público em negócio/wizard/fundiário/três Balcões/simulador/CRM. Gravação→GET→filtro→agregado quando aplicável; residência/constituição/fiscal/fundos distintos da origem declarada; unknown preservado. | Seleção, recibos, variações condicionais, filtros/tabela e nova sessão na interface. Não contar testes documentais selecionados pela palavra original como requisitos de países. |
| AUD-LAND-01, PART-01, LIB-01/02, SCAN-01; C39/C40 | 404 dos originais cifrados corrigido em fundiário e sala de parceria por VerifiedDocumentBinary comum; novos uploads registam tamanho/autor. PDF/PNG/JPEG com ClamD real, hash, quarentena/perfis/partilha/revogação/adulteração/recuperação. Lote documental QA privado, idempotente, sem substituir identidade conflituosa; actor sem permissão/ambiente ativo recusados. | Renderização PDF/impressão, ações visuais e restantes consumidores/tipos; lote ativo autenticado. Serviço ClamD real demonstrado separado de arranque/manutenção permanente/GD ativo. |
| AUD-OP-02/SCAN-01; C41/C42 | PDFs sintéticos apenas com cabeçalho não provavam legibilidade: novos testes usam PDF válido de uma página, parseado independentemente. No servidor 18097, novo PDF anexado à oportunidadeQA12→scan real→download→nova sessão→recuperação; outra conta 403. Cinco binários anteriores preservados por SHA; PNG/3WebP recuperados, sem novo scan das derivadas. Credenciais fixas do script removidas; passwords/remember tokens de dois atoresQA auxiliares rodados; MFA/conta 18 preservados. | PDF renderizado e interface documental pendentes. O placeholder anterior permanece conservado como evidência e não certifica abertura de PDF. |
| AUD-OP-03/04 | Schema normativo §26 preparado e rastreável:110 definições,9 contratos Create/Patch/Response, sem renumerar IDs. | Workflow e validação/gates especializados continuam não implementados; nenhum fecho funcional atribuído ao artefacto. |
| C37, AUD-UI-01, I1–I3 | Evidências anteriores conservadas, nenhum novo ensaio de login investidor neste lote. | Login/reload/logout/nova sessão e A/B completos na interface continuam pendentes. |
| Nível INE 2019 | Esperado no exemplar | Resolvido QA | Pendente |
| --- | ---: | ---: | ---: |
| Província |11|11|0|
| Distrito |159|128|31|
| Posto |411|254|157|
| Total |581|393|188|
| -------------- | -------------------: | -----------: | -------: |
| Província | 11 | 11 | 0 |
| Distrito | 159 | 128 | 31 |
| Posto | 411 | 254 | 157 |
| Total | 581 | 393 | 188 |
Os denominadores da edição 2019 não são os 1920 territórios do cadastro existente. [188 lacunas por nome](correspondencias-cartograficas.md), incluindo Cidade De Maputo agregado e Mandie duplicado no próprio workbook; nenhuma equivalência por código/fuzzy, nem fusão de cadastros. Aceitação das fontes oficiais preservada.
**Mesma matriz, sem requisitos amplos recém-fechados:**3354 requisitos/3354 linhas canónicas;5830 ocorrências de origem. IDs, fontes, trechos, diferenças de versão, critérios e estados conservados.
| Estado | Requisitos/linhas | Ocorrências |
| --- | ---: | ---: |
| parcial | 3198 | 5380 |
| não implementado | 146 | 440 |
| dependente de decisão concreta | 4 | 4 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 5 | 5 |
| Estado | Requisitos/linhas | Ocorrências |
| ------------------------------ | ----------------: | ----------: |
| parcial | 3198 | 5380 |
| não implementado | 146 | 440 |
| dependente de decisão concreta | 4 | 4 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 5 | 5 |
Evidências privadas: `geometry-crosswalk-http-qa.json` (aplicação posterior22, além das 2+8 anteriores registadas na auditoria), `geometry-crosswalk-preservation-qa.json` (total 32 novas), `geometry-crosswalk-consumers-http-qa.json` (HTTP 32 novas/0 públicas), `geometry-consumers-path-qa.json` (serviço393), `territory-catalogue-coverage.json` (catálogo1920). Não confundir aplicação parcial inicial interrompida por Mandie com duplicação: as 10 já aplicadas foram reutilizadas na continuação; ambiguidade nominal fica pendente e não bloqueia outras correspondências únicas.
@@ -177,12 +216,12 @@ Evidências: mfa-key-diagnosis-qa.json, mfa-session-invalidation-qa.json, mfa-pe
**Mesma matriz:**3354 requisitos/linhas canónicas,5830 ocorrências preservadas; parcial: 3198 requisitos/5380 ocorrências; não implementado: 146 requisitos/440 ocorrências; dependente de decisão concreta: 4 requisitos/4 ocorrências; implementado mas não ativado: 1 requisitos/1 ocorrências; concluído e demonstrado: 5 requisitos/5 ocorrências. Nenhum requisito amplo fechado por este lote. `candidate_revision_fixed=false`, `integrated_ui_ab_passed=false`, `activation_ready=false`; não fixar candidata antes dos resultados manuais e correções.
| Requisito | Correção/prova concreta deste lote | Estado |
| --- | --- | --- |
| AUD-GEO-02/03, OPS-01 | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`. Fontes retidas/edição/hash/scan; nomes exatos+pai+país, conflitos, preview vinculado ao ator/estado, MFA, `geo_write_receipts`, `audit_events` append-only; nada publicado. HTTP real com login+TOTP, três níveis,361 reutilizadas/0 novas; replay e reversão de lote de reutilização mantêm361. QA de testes demonstra criação e reversão de lote novo, preservação de histórico e recusas de alteração/publicação/FK/scan expirado/MFA/alvo não QA. | Código preparado + API/persistência QA; interface e ativo pendentes |
| AUD-SCAN-01 | C31: nome da rota assinada corrigido para `management.opportunity-image-preview`, mantendo URL. Servidor web QA gera3WebP320/640/1280; PDF+PNG+3derivadas têm cinco scans reais ClamAV1.5.4, clean/hash próprios, cifragem Laravel e classificação restricted; downloads reais comparados, assinaturas ausentes403 e outra conta403. QA de testes prova quarentena423, scanner inconclusivo e retry real, substituição sem apagar original, versão409, exclusão/restauro e adulteração409. | Operações de oportunidades demonstradas por API/persistência; apresentação visual pendente |
| AUD-LIB-01/SCAN-01/DESK-02 | C35 corrigiu erro500 ao omitir data/emissor opcionais. C36 corrigiu recuperação404 de originais cifrados: os consumidores comparavam o hash do ciphertext com o original. VerifiedDocumentBinary reutiliza decifragem/integridade sem cópia pública nem alteração de permissões. PortalRealDocumentConsumersTest usa ClamD real: biblioteca privada→scan→classificação→publicação separada→download; versão409/dedup/404hash. Balcão testa upload/confidential→scan→download, dedup/403estranho. Original canónico cifrado é reutilizado sem duplicar documents; downloads na gestão/Balcão/biblioteca e view PDF devolvem os bytes originais; antes de publicação/adulteração404. | API/persistência QA; bytes de preview PDF verificados, renderização visual pendente; sem publicação ativa nem fecho global |
| AUD-UI-01/DASH-01/SIM-01/DESK-02/GUIDE-01/CRM-01 | A/B repetidos por HTTP no servidor recuperado; nova sessão real, IDs/drafts próprios, recuperação, aplicabilidade, resultado20/0 e20/70000, Balcão e tarefa concluída enquanto terra aguarda; outra conta/contexto recusados. | API/persistência QA; cenários completos na interface pendentes |
| Requisito | Correção/prova concreta deste lote | Estado |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| AUD-GEO-02/03, OPS-01 | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`. Fontes retidas/edição/hash/scan; nomes exatos+pai+país, conflitos, preview vinculado ao ator/estado, MFA, `geo_write_receipts`, `audit_events` append-only; nada publicado. HTTP real com login+TOTP, três níveis,361 reutilizadas/0 novas; replay e reversão de lote de reutilização mantêm361. QA de testes demonstra criação e reversão de lote novo, preservação de histórico e recusas de alteração/publicação/FK/scan expirado/MFA/alvo não QA. | Código preparado + API/persistência QA; interface e ativo pendentes |
| AUD-SCAN-01 | C31: nome da rota assinada corrigido para `management.opportunity-image-preview`, mantendo URL. Servidor web QA gera3WebP320/640/1280; PDF+PNG+3derivadas têm cinco scans reais ClamAV1.5.4, clean/hash próprios, cifragem Laravel e classificação restricted; downloads reais comparados, assinaturas ausentes403 e outra conta403. QA de testes prova quarentena423, scanner inconclusivo e retry real, substituição sem apagar original, versão409, exclusão/restauro e adulteração409. | Operações de oportunidades demonstradas por API/persistência; apresentação visual pendente |
| AUD-LIB-01/SCAN-01/DESK-02 | C35 corrigiu erro500 ao omitir data/emissor opcionais. C36 corrigiu recuperação404 de originais cifrados: os consumidores comparavam o hash do ciphertext com o original. VerifiedDocumentBinary reutiliza decifragem/integridade sem cópia pública nem alteração de permissões. PortalRealDocumentConsumersTest usa ClamD real: biblioteca privada→scan→classificação→publicação separada→download; versão409/dedup/404hash. Balcão testa upload/confidential→scan→download, dedup/403estranho. Original canónico cifrado é reutilizado sem duplicar documents; downloads na gestão/Balcão/biblioteca e view PDF devolvem os bytes originais; antes de publicação/adulteração404. | API/persistência QA; bytes de preview PDF verificados, renderização visual pendente; sem publicação ativa nem fecho global |
| AUD-UI-01/DASH-01/SIM-01/DESK-02/GUIDE-01/CRM-01 | A/B repetidos por HTTP no servidor recuperado; nova sessão real, IDs/drafts próprios, recuperação, aplicabilidade, resultado20/0 e20/70000, Balcão e tarefa concluída enquanto terra aguarda; outra conta/contexto recusados. | API/persistência QA; cenários completos na interface pendentes |
**Correspondências:** províncias11→9/2; distritos159→120/39; postos411→232/179. Esperado refere o exemplar2019, não um cadastro atual certificado. Maputo e Maputo City são as duas pendências provinciais. Distritos:9 por pai não resolvido/30 por nome; postos:86 por pai/93 por nome. [Todas220 lacunas por nome/código/pai/causa](correspondencias-cartograficas.md). Sem polígonos de localidades no exemplar; nenhum limite equivale a implantação/DUAT. Aceitação da fonte oficial preservada.
@@ -200,15 +239,15 @@ Interface ainda não observada; I0–I3 permanecem parciais. Provas anteriores d
## Histórico do lote inicial — limites da evidência então obtida
| Requisito existente | Falha/capacidade tratada | Evidência concreta | Código / QA / ativo |
|---|---|---|---|
| AUD-SIM-01, AUD-DESK-02 — C25 | Um rascunho corrente por conta impedia investimentos independentes. Criação e recuperação agora usam dossier autorizado; ID e armazenamento local ficam separados. Conta ou contexto indevidos não dão acesso ao snapshot. | `InvestorPathTest`: mesma conta, A/B, dois drafts, replay, conflito, recuperação por contexto, conta terceira negada; testes antigos de anónimo/claim preservados. | Preparado / API e persistência demonstradas / sem ativação |
| AUD-DASH-01, AUD-UI-01 — I1 | Painel do investidor composto e página do dossier: projeto recente, pendências, documentos, resultados, tarefas, próxima ação e acesso direto às ferramentas. Gestão conserva as suas funções. | Resposta Inertia verifica componente/19 etapas/5 fases, versões e separação investidor/gestão; TypeScript e build. | Preparado atrás de flag / dados do painel verificados / interface visual pendente |
| AUD-DESK-02, AUD-SIM-02 — I2 | Ferramenta abre no contexto, devolve evidência financeira por ID/versão/hash; descrição já preenchida no pedido Balcão com evento de proveniência. | A/B API: guardar → GET → associação idempotente → nova sessão HTTP → resultado recuperado; 20 unidades e 70.000,00 pelas fórmulas existentes em teste frontend. | QA demonstrada para este percurso / prefill transversal ainda parcial / ativo inalterado |
| AUD-GUIDE-01, AUD-DOC-01 — I3 | Definição imutável das 19 etapas e cinco fases ligada à instância; aplicabilidade sim/não/desconhecida, fundamentos, dependências por ação e distinção entre preparação, conferência interna e ato externo. | 38 etapas para A/B; preparar S18 permitido enquanto S17 falta, operar recusado; versões antigas409; conclusão/decisão externa sem evidência recusada; mudar ramo preserva estado/fundamento anterior. | Extensão instalada somente em QA / interface pendente / ativo sem colunas novas |
| AUD-CRM-01, AUD-DESK-01 | Tarefa independente aceite no CRM existente, atribuída ao responsável e concluída enquanto terra aguarda; resultados recuperados pelo dono. | APIs existentes de tarefas; permissões, versão e evento. Nenhuma chamada externa nos cenários. | QA demonstrada / gestão visual pendente / nenhum envio externo |
| AUD-SIM-02 — C26 | Recusa de rollback do núcleo não pode desativar RLS antes de detetar dados/versões a preservar. | Regressão inicial recusou segunda definição; ensaio novo confirma recusa e igualdade das políticas RLS antes/depois. | Corrigido no código / QA demonstrada / sem rollback ativo |
| AUD-GEO-02/03 — I0 | Geometrias oficiais privadas agora também na cópia QA do percurso. | Importação 9 províncias +120 distritos +232 postos; repetição zero novos, 361 reutilizados. Originais/hash/scan/edição INE2019 preservados. | QA povoada / camadas públicas e visual por consumidor pendentes / ativo0 geometrias |
| Requisito existente | Falha/capacidade tratada | Evidência concreta | Código / QA / ativo |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| AUD-SIM-01, AUD-DESK-02 — C25 | Um rascunho corrente por conta impedia investimentos independentes. Criação e recuperação agora usam dossier autorizado; ID e armazenamento local ficam separados. Conta ou contexto indevidos não dão acesso ao snapshot. | `InvestorPathTest`: mesma conta, A/B, dois drafts, replay, conflito, recuperação por contexto, conta terceira negada; testes antigos de anónimo/claim preservados. | Preparado / API e persistência demonstradas / sem ativação |
| AUD-DASH-01, AUD-UI-01 — I1 | Painel do investidor composto e página do dossier: projeto recente, pendências, documentos, resultados, tarefas, próxima ação e acesso direto às ferramentas. Gestão conserva as suas funções. | Resposta Inertia verifica componente/19 etapas/5 fases, versões e separação investidor/gestão; TypeScript e build. | Preparado atrás de flag / dados do painel verificados / interface visual pendente |
| AUD-DESK-02, AUD-SIM-02 — I2 | Ferramenta abre no contexto, devolve evidência financeira por ID/versão/hash; descrição já preenchida no pedido Balcão com evento de proveniência. | A/B API: guardar → GET → associação idempotente → nova sessão HTTP → resultado recuperado; 20 unidades e 70.000,00 pelas fórmulas existentes em teste frontend. | QA demonstrada para este percurso / prefill transversal ainda parcial / ativo inalterado |
| AUD-GUIDE-01, AUD-DOC-01 — I3 | Definição imutável das 19 etapas e cinco fases ligada à instância; aplicabilidade sim/não/desconhecida, fundamentos, dependências por ação e distinção entre preparação, conferência interna e ato externo. | 38 etapas para A/B; preparar S18 permitido enquanto S17 falta, operar recusado; versões antigas409; conclusão/decisão externa sem evidência recusada; mudar ramo preserva estado/fundamento anterior. | Extensão instalada somente em QA / interface pendente / ativo sem colunas novas |
| AUD-CRM-01, AUD-DESK-01 | Tarefa independente aceite no CRM existente, atribuída ao responsável e concluída enquanto terra aguarda; resultados recuperados pelo dono. | APIs existentes de tarefas; permissões, versão e evento. Nenhuma chamada externa nos cenários. | QA demonstrada / gestão visual pendente / nenhum envio externo |
| AUD-SIM-02 — C26 | Recusa de rollback do núcleo não pode desativar RLS antes de detetar dados/versões a preservar. | Regressão inicial recusou segunda definição; ensaio novo confirma recusa e igualdade das políticas RLS antes/depois. | Corrigido no código / QA demonstrada / sem rollback ativo |
| AUD-GEO-02/03 — I0 | Geometrias oficiais privadas agora também na cópia QA do percurso. | Importação 9 províncias +120 distritos +232 postos; repetição zero novos, 361 reutilizados. Originais/hash/scan/edição INE2019 preservados. | QA povoada / camadas públicas e visual por consumidor pendentes / ativo0 geometrias |
As provas numéricas finais e fingerprints ficam em `storage/app/private/investmoz-v2/portal-audit/investor-path-evidence.json`; logs/JUnit ficam no mesmo diretório. Não substituem a aceitação de cada cláusula da matriz.
@@ -235,14 +274,14 @@ Reversão preferida: desativar `INVESTOR_PATH_ENABLED`, manter dados/versões/ev
## Plano consolidado — ainda não autorizado no ativo
| Ordem | Alteração | Dependência/efeito e contagem prevista | Reversão/condição de fecho |
|---|---|---|---|
| 1 | Correções de código I0/C25/C26 e interface I1–I3 | Validar a versão final; preservar URLs/perfis. Flag do novo percurso desativada no ativo. Não requer instalar novamente Balcão/Bolsa/gestão básica. | Reverter código novo e manter dados; backend/UI A/B completos antes do fecho. |
| 2 | Extensão de recursos de oportunidades030000 | Mecanismo autenticado existente, migration pendente uma vez; backup/restauro, compatibilidade e fingerprint novos. Preparar anexos/derivadas sem publicar automaticamente. | Guardas de dados/ficheiros existentes; ClamD/GD limitam operações afetadas. |
| 3 | Extensão do percurso190000 | Reutiliza `/management/balcao-install` e instala só migrations ausentes. +2 colunas/+1 definição; +0 dossiers/+0 etapas por instalação. Prévia exige API/persistência, A/B visual, backup/compatibilidade da versão final. | `down` sem uso preserva definição; depois do uso, desativação e preservação. A autorização atual não inclui este ato ativo. |
| 4 | Configuração de disponibilização do percurso | `INVESTOR_PATH_ENABLED` é separado da instalação; não é ativado pelo schema nem por `ready`. Disponibilizar só após aceitação UI e autorização ativa futura. | Flagfalse; sem apagar entidades/decisões/eventos. |
| 5 | Importação cartográfica oficial privada | Lote separado, prévia autenticada/hash/scan/correspondências únicas. Previsão361=9+120+232 somente se base ainda0 e sem conflitos; +0 territórios/+0 pontos ou relações inferidas. | Retirar disponibilidade pelo mecanismo auditado, preservar origem e versões. Não adaptar o CLI QA para ativo. Mecanismo autenticado específico ainda falta. |
| 6 | Disponibilidade cartográfica por consumidor | Classificação/divulgação e camada por operação, aprovadas expressamente. Cadastro e importação não autorizam publicação nem representam local de investimento. | Reverter a disponibilização, manter os originais. Aceitação de seletor/mapa individual na interface. |
| Ordem | Alteração | Dependência/efeito e contagem prevista | Reversão/condição de fecho |
| ----- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | Correções de código I0/C25/C26 e interface I1–I3 | Validar a versão final; preservar URLs/perfis. Flag do novo percurso desativada no ativo. Não requer instalar novamente Balcão/Bolsa/gestão básica. | Reverter código novo e manter dados; backend/UI A/B completos antes do fecho. |
| 2 | Extensão de recursos de oportunidades030000 | Mecanismo autenticado existente, migration pendente uma vez; backup/restauro, compatibilidade e fingerprint novos. Preparar anexos/derivadas sem publicar automaticamente. | Guardas de dados/ficheiros existentes; ClamD/GD limitam operações afetadas. |
| 3 | Extensão do percurso190000 | Reutiliza `/management/balcao-install` e instala só migrations ausentes. +2 colunas/+1 definição; +0 dossiers/+0 etapas por instalação. Prévia exige API/persistência, A/B visual, backup/compatibilidade da versão final. | `down` sem uso preserva definição; depois do uso, desativação e preservação. A autorização atual não inclui este ato ativo. |
| 4 | Configuração de disponibilização do percurso | `INVESTOR_PATH_ENABLED` é separado da instalação; não é ativado pelo schema nem por `ready`. Disponibilizar só após aceitação UI e autorização ativa futura. | Flagfalse; sem apagar entidades/decisões/eventos. |
| 5 | Importação cartográfica oficial privada | Lote separado, prévia autenticada/hash/scan/correspondências únicas. Previsão361=9+120+232 somente se base ainda0 e sem conflitos; +0 territórios/+0 pontos ou relações inferidas. | Retirar disponibilidade pelo mecanismo auditado, preservar origem e versões. Não adaptar o CLI QA para ativo. Mecanismo autenticado específico ainda falta. |
| 6 | Disponibilidade cartográfica por consumidor | Classificação/divulgação e camada por operação, aprovadas expressamente. Cadastro e importação não autorizam publicação nem representam local de investimento. | Reverter a disponibilização, manter os originais. Aceitação de seletor/mapa individual na interface. |
Nenhum `ready=true` histórico certifica esta versão. As mudanças invalidam os fingerprints/provas antigas de recursos e Balcão; devem ser renovados. O guard da instalação do percurso exige A/B visual e recusa a execução enquanto essa prova falta. Nenhuma instalação ativa, importação ativa ou alteração de dados ativos foi executada.
File diff suppressed because it is too large Load Diff
@@ -1,18 +1,19 @@
<!-- qa-visual-results-20261010:begin -->
## Ensaios visuais e pendências atuais — 2026-10-10T17:57:54.604301+00:00
Trabalho exclusivo na QA da porta 18097, base `desk_restore_20261009_174726_test:55441`. Nenhuma alteração na base ativa. A mesma matriz mantém **3393 requisitos / 3393 linhas / 6845 ocorrências de origem**: 3235 parciais, 145 não implementados, 5 dependentes de decisão, 1 implementado mas não ativado e 7 concluídos e demonstrados. Os estados globais não mudaram; foram atualizados subcritérios com provas próprias. A ausência de requisitos globalmente classificados “com falha” não significa ausência de casos abertos.
| Requisito | Demonstrado em QA | Critérios ainda pendentes |
| --- | --- | --- |
| C37; UI01; PROFILE24–25 | MFA manual QA18 aceite às 17:40:21 e 17:46:42 UTC; autenticação persistida e dashboard 200. Responsável confirmou acesso. O 403 inicial era do relatório administrativo reservado. Mensagem e retorno ao painel corrigidos; Chromium QA21 provou recusa 403, retorno e F5 sem perder sessão. | F5, logout e novo login no navegador habitual QA18. Não declarar o loop anterior resolvido por inferência: o rastreio não demonstra um ciclo persistente. Uma atualização Inertia 409 isolada não é perda de autenticação. |
| A/B; GUIDE01; SIM02; DESK01–02; CRM01 | Chromium desktop QA18: criação → gravação → nova sessão → recuperação → aplicabilidade → ferramenta → resultado no dossier → preparação no Balcão → acompanhamento interno → nova recuperação. Cinco fases e 19 etapas preservadas. A dispensa S10; B aguarda informação externa em S10 enquanto S02 avança. Resultado: equilíbrio de 20 unidades e défice A=0 / B=70.000 MZN. QA23 recebe 403/404; gestor não vê resultados financeiros privados. | Balcão demonstrado em preparação DRAFT, sem submissão ou decisão externa. Restantes critérios especializados, fiscalidade, documentos e consumidores não encerrados. Repetição final A/B móvel ainda necessária. |
| DASH01; PROFILE05/32 | QA21, a partir do dashboard: “Minhas oportunidades” e “Nova oportunidade” → rascunho incompleto #50 → guardar → nova sessão → recuperar → editar. Promotor solicita arquivo; Publicador QA25 arquiva com fundamento; estado recuperado. | Restauração por perfil ausente no workflow. Definir e implementar ator/regra coerentes sem conceder arquivo direto ao Promotor por inferência. Workflow e contratos especializados ainda exigem demonstrações próprias. |
| COUNTRY01–04/06/07 | Residência PT guardada no perfil e recuperada após F5. Negócio e fundiário DRAFT: país PT / origem FR guardados e recuperados. Balcão A/B: PT / ZA recuperados noutra sessão. Quatro formulários públicos apresentam 249 países cada. Gestão: filtros ZA/unknown, quatro manifestações sem origem e zero pedidos submetidos ZA, com rascunhos excluídos. | Nos formulários públicos, a presença de opções não prova submissão ou recuperação. Concluir cada gravação e estatística positiva de origem conhecida no UI. Nos rascunhos de negócio/fundiário, F5 não substitui nova sessão. |
| GEO01–03 | Oportunidade própria QA21 #51 e criação de projeto, cluster e corredor: Cabo Delgado registado → API com uma geometria acessível → um polígono SVG visível em cada consumidor. | Seleções desse ensaio não guardadas. Recuperar relações por consumidor e testar descendentes, restantes mapas e perfis. Tiles externos bloqueados no ensaio, sem confirmação da base externa. 408 associações anteriores e 173 pendentes preservadas; Mandie/Guro ambíguo. |
| LEG02/03/06/07; C77–C83 | Corrigidos landmarks, ARIA, hierarquia de títulos, reflow, foco das tabelas e idioma HTML pt-MZ em QA. Quinze execuções dirigidas de axe, em 320/390/1440px, sem violações automáticas ou overflow. Três páginas com skiplink primeiro e tabelas financeiras operadas por teclado. | Cobertura integral, leitor de ecrã, dispositivos reais, mais perfis e editor C74. O dossier QA21 verifica o componente móvel corrigido, sem substituir a repetição final A/B. |
| DOC01; C84 | Retirada mensagem global falsa de ClamD pendente; scan e motor apresentados por ficheiro/versão. Os 22 scans reais anteriores permanecem demonstrados. | PDFs, exportações, partilhas, derivadas e operações restantes exigem provas próprias. Um original limpo não comprova a derivada. |
| OPS01 | Backup QA 2026-10-10T17:48:11+00:00: 295 tabelas e 103 ficheiros restaurados. Ativo READ ONLY, backup 2026-10-10T17:48:52+00:00: 288 tabelas restauradas numa base QA distinta e cinco ficheiros conferidos no arquivo. Instalador/publicação: 9 testes / 93 asserções, além de TypeScript. | Aplicação, compatibilidade e reversão da futura revisão candidata no clone fresco do ativo. Revisão candidata global e ativação continuam por fixar. Contagens de testes não substituem critérios funcionais. |
| Requisito | Demonstrado em QA | Critérios ainda pendentes |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| C37; UI01; PROFILE24–25 | MFA manual QA18 aceite às 17:40:21 e 17:46:42 UTC; autenticação persistida e dashboard 200. Responsável confirmou acesso. O 403 inicial era do relatório administrativo reservado. Mensagem e retorno ao painel corrigidos; Chromium QA21 provou recusa 403, retorno e F5 sem perder sessão. | F5, logout e novo login no navegador habitual QA18. Não declarar o loop anterior resolvido por inferência: o rastreio não demonstra um ciclo persistente. Uma atualização Inertia 409 isolada não é perda de autenticação. |
| A/B; GUIDE01; SIM02; DESK01–02; CRM01 | Chromium desktop QA18: criação → gravação → nova sessão → recuperação → aplicabilidade → ferramenta → resultado no dossier → preparação no Balcão → acompanhamento interno → nova recuperação. Cinco fases e 19 etapas preservadas. A dispensa S10; B aguarda informação externa em S10 enquanto S02 avança. Resultado: equilíbrio de 20 unidades e défice A=0 / B=70.000 MZN. QA23 recebe 403/404; gestor não vê resultados financeiros privados. | Balcão demonstrado em preparação DRAFT, sem submissão ou decisão externa. Restantes critérios especializados, fiscalidade, documentos e consumidores não encerrados. Repetição final A/B móvel ainda necessária. |
| DASH01; PROFILE05/32 | QA21, a partir do dashboard: “Minhas oportunidades” e “Nova oportunidade” → rascunho incompleto #50 → guardar → nova sessão → recuperar → editar. Promotor solicita arquivo; Publicador QA25 arquiva com fundamento; estado recuperado. | Restauração por perfil ausente no workflow. Definir e implementar ator/regra coerentes sem conceder arquivo direto ao Promotor por inferência. Workflow e contratos especializados ainda exigem demonstrações próprias. |
| COUNTRY01–04/06/07 | Residência PT guardada no perfil e recuperada após F5. Negócio e fundiário DRAFT: país PT / origem FR guardados e recuperados. Balcão A/B: PT / ZA recuperados noutra sessão. Quatro formulários públicos apresentam 249 países cada. Gestão: filtros ZA/unknown, quatro manifestações sem origem e zero pedidos submetidos ZA, com rascunhos excluídos. | Nos formulários públicos, a presença de opções não prova submissão ou recuperação. Concluir cada gravação e estatística positiva de origem conhecida no UI. Nos rascunhos de negócio/fundiário, F5 não substitui nova sessão. |
| GEO01–03 | Oportunidade própria QA21 #51 e criação de projeto, cluster e corredor: Cabo Delgado registado → API com uma geometria acessível → um polígono SVG visível em cada consumidor. | Seleções desse ensaio não guardadas. Recuperar relações por consumidor e testar descendentes, restantes mapas e perfis. Tiles externos bloqueados no ensaio, sem confirmação da base externa. 408 associações anteriores e 173 pendentes preservadas; Mandie/Guro ambíguo. |
| LEG02/03/06/07; C77–C83 | Corrigidos landmarks, ARIA, hierarquia de títulos, reflow, foco das tabelas e idioma HTML pt-MZ em QA. Quinze execuções dirigidas de axe, em 320/390/1440px, sem violações automáticas ou overflow. Três páginas com skiplink primeiro e tabelas financeiras operadas por teclado. | Cobertura integral, leitor de ecrã, dispositivos reais, mais perfis e editor C74. O dossier QA21 verifica o componente móvel corrigido, sem substituir a repetição final A/B. |
| DOC01; C84 | Retirada mensagem global falsa de ClamD pendente; scan e motor apresentados por ficheiro/versão. Os 22 scans reais anteriores permanecem demonstrados. | PDFs, exportações, partilhas, derivadas e operações restantes exigem provas próprias. Um original limpo não comprova a derivada. |
| OPS01 | Backup QA 2026-10-10T17:48:11+00:00: 295 tabelas e 103 ficheiros restaurados. Ativo READ ONLY, backup 2026-10-10T17:48:52+00:00: 288 tabelas restauradas numa base QA distinta e cinco ficheiros conferidos no arquivo. Instalador/publicação: 9 testes / 93 asserções, além de TypeScript. | Aplicação, compatibilidade e reversão da futura revisão candidata no clone fresco do ativo. Revisão candidata global e ativação continuam por fixar. Contagens de testes não substituem critérios funcionais. |
**C80 corrigido:** a resposta tardia do GET do rascunho podia substituir preenchimento já iniciado. Edição e avanço ficam bloqueados até a recuperação terminar; o retorno exige o snapshot completo guardado. Chromium com resposta deliberadamente atrasada comprovou bloqueio, recuperação e libertação. A/B recuperaram os inputs corretos noutra sessão, preservando versões anteriores.
@@ -28,20 +29,21 @@ As versões históricas abaixo ficam preservadas. Afirmações antigas sobre fal
# Legado Tempo — piloto de agronegócio em QA
<!-- qa-c71-sectors-result-20261010:begin -->
## Resultado atual — 2026-10-10T16:23:25.695297+00:00
**QA18097 recuperada; nenhuma alteração na base ativa.** C71 técnico corrigido: faltavam26 ficheiros de catálogos partilhados, incluindo `global/2964`, necessários ao `pg_dump`. O agente/processo que os removeu continua desconhecido. O cluster danificado foi preservado e substituído por cluster novo em diretório estável, apenas no alvoQA55441. As 295 tabelas/34.902 linhas e 31 sequências iniciais conferiram; schema/owners/ACL/triggers equivalentes após normalização explícita de 2 constraints varchar/text e slots de colunas removidas. A cópia física retida confere em 75575 ficheiros por nomes, tamanhos ehashes; isso não afirma restauro lógico de todos os bancos históricosQA.
**Backup/restauro posterior ao lote:** 2026-10-10T16: 22:44+00:00,295 tabelas e 103 ficheiros privados conferidos em `profile_restore_20261010_162229_test:55441`. APP_KEY, MFA e contas preservados. Não é prova de backup da base ativa nem fixa candidata global. QA/login voltou aHTTP200; manutenção arquivada. 2FAS Auth continua compatível com TOTP; a rejeição manualQA18 registada foi de palavra-passe antes do MFA, sem justificar troca de aplicação.
| Requisito / caso | Evidência deste lote | Lacuna concreta |
| --- | --- | --- |
| AUD-OPS-01 / C71 | Cluster saudável, dados/sequências/permissões preservados, backup/restauro renovado,0escritasativas. Estado global passa de com falha para parcial. | C37/QA18,A/B e outros consumidores; candidata e backup ativo/autorização própria. |
| AUD-LEG-01/05/07 |22 ficheiros (17 artigos+5 imagens) importados privadamente, hashes recuperados,22 scans ClamD reais; replay sem duplicações/eventos/scans novos. |32 das 50 versões observadas continuam não importadas; sitemap misto/paginação/links externos/C68 e cobertura integral. |
| AUD-LEG-02/03/06 / C72 |16 artigos novos com texto públicos, título deInfraestruturas preservado. Chromium desktop: imagens/pesquisa/artigos→MFA21→4 dossiers→retorno→logout→nova sessão→F5/replay. HTTP e persistência separados,8 dossiers no total. | Móvel/acessibilidade/mais perfis e percursosA/B completos não encerrados. |
| AUD-LEG-04 |Leitura pública; guardar requer login. Anónimo/QA23 sem contexto privado; QA23recebe403 ao dossier alheio. Estado de consulta/proteçãoQA mantido concluído no âmbito demonstrado. | Disponibilização ativa e demais aceitações são independentes. |
| Mercado Financeiro |OrigemHTML e respostaInertiaHTTP200 contêm corpo vazio; exemplar22 no lote fica privado na biblioteca (recurso23). `/mercado-financeiro` e respetiva exploração404,sem página vazia apresentada como entrega. | Obter conteúdo real/versão com texto; não usar Fintech nem inventar corpo. |
| C74 |Imagens semAssunto eram recusadas porPUT422. QA aceita tema vazio sem inferir setor; interface tornaAssunto opcional. Cinco metadados vazios guardados/recuperados; teste dedicado1/11. | Editor administrativo sem ensaio visual próprio; alteração protegida pela guardaQA. |
| Requisito / caso | Evidência deste lote | Lacuna concreta |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| AUD-OPS-01 / C71 | Cluster saudável, dados/sequências/permissões preservados, backup/restauro renovado,0escritasativas. Estado global passa de com falha para parcial. | C37/QA18,A/B e outros consumidores; candidata e backup ativo/autorização própria. |
| AUD-LEG-01/05/07 | 22 ficheiros (17 artigos+5 imagens) importados privadamente, hashes recuperados,22 scans ClamD reais; replay sem duplicações/eventos/scans novos. | 32 das 50 versões observadas continuam não importadas; sitemap misto/paginação/links externos/C68 e cobertura integral. |
| AUD-LEG-02/03/06 / C72 | 16 artigos novos com texto públicos, título deInfraestruturas preservado. Chromium desktop: imagens/pesquisa/artigos→MFA21→4 dossiers→retorno→logout→nova sessão→F5/replay. HTTP e persistência separados,8 dossiers no total. | Móvel/acessibilidade/mais perfis e percursosA/B completos não encerrados. |
| AUD-LEG-04 | Leitura pública; guardar requer login. Anónimo/QA23 sem contexto privado; QA23recebe403 ao dossier alheio. Estado de consulta/proteçãoQA mantido concluído no âmbito demonstrado. | Disponibilização ativa e demais aceitações são independentes. |
| Mercado Financeiro | OrigemHTML e respostaInertiaHTTP200 contêm corpo vazio; exemplar22 no lote fica privado na biblioteca (recurso23). `/mercado-financeiro` e respetiva exploração404,sem página vazia apresentada como entrega. | Obter conteúdo real/versão com texto; não usar Fintech nem inventar corpo. |
| C74 | Imagens semAssunto eram recusadas porPUT422. QA aceita tema vazio sem inferir setor; interface tornaAssunto opcional. Cinco metadados vazios guardados/recuperados; teste dedicado1/11. | Editor administrativo sem ensaio visual próprio; alteração protegida pela guardaQA. |
**Contagens canónicas:**3393 requisitos/3393 linhas, 6845 ocorrências de origem; 3235 parciais, 145 não implementados, 5 dependentes de decisão, 1 implementado mas não ativado, 7 concluídos e demonstrados, 0 com falha. Casos adicionais e aceitações abertas continuam visíveis dentro dos requisitos parciais;0 com falha global não significa portal sem erros. BacklogCSV é projeção reconciliada dos mesmos3393 IDs, incluindo39 anteriormente omitidos, não outra matriz.
@@ -57,15 +59,16 @@ As versões históricas abaixo ficam preservadas. Afirmações antigas sobre fal
<!-- qa-c71-sectors-result-20261010:end -->
<!-- legacy-manual-sectors-20261010:begin -->
## Confirmação manual recebida do responsável — 10/10/2026
Confirmado nesta conversa: **leitura pública → autenticação → criar/escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo**. Conta, perfil, dispositivo e hora de execução não foram indicados; não os presumir. “Criar/escolher” conserva o relato do responsável, sem declarar que ambas as alternativas foram ensaiadas separadamente.
| Critério confirmado manualmente | Correspondência na matriz existente |
| --- | --- |
| Leitura pública e autenticação ao entrar no percurso privado | AUD-LEG-03 e AUD-LEG-04 |
| Criar/escolher dossier e guardar referência | AUD-LEG-03, AUD-LEG-06; gravação/consumidor em AUD-LEG-07 |
| Nova sessão, recuperação do dossier e abertura do artigo | AUD-LEG-03, AUD-LEG-06 e AUD-LEG-07 |
| Critério confirmado manualmente | Correspondência na matriz existente |
| ------------------------------------------------------------ | --------------------------------------------------------- |
| Leitura pública e autenticação ao entrar no percurso privado | AUD-LEG-03 e AUD-LEG-04 |
| Criar/escolher dossier e guardar referência | AUD-LEG-03, AUD-LEG-06; gravação/consumidor em AUD-LEG-07 |
| Nova sessão, recuperação do dossier e abertura do artigo | AUD-LEG-03, AUD-LEG-06 e AUD-LEG-07 |
Só estes subcritérios receberam a confirmação manual. Nenhum estado global foi alterado, nenhuma API/persistência recebeu prova técnica adicional por inferência e nenhuma linha foi acrescentada à matriz. O relato manual fica separado das provas Chromium/API/READ ONLY anteriores.
@@ -75,12 +78,12 @@ Só estes subcritérios receberam a confirmação manual. Nenhum estado global f
As 92 entradas do inventário existente foram conferidas antes da seleção. Os quatro artigos de entrada foram novamente recolhidos por leitura anónima: HTTP200 e corpo/data de modificação iguais ao exemplar inicial. Os artigos descendentes e imagens usam os snapshots já inventariados, com hash conferido. Sitemap misto, paginação e restante acervo continuam abertos.
| Fonte legada | Identidade e cadastro existente | Conteúdo e lacuna concreta |
| --- | --- | --- |
| [Energia & Mineração](https://investemoz.tempo.co.mz/energia-mineracao) | 171981 / setor QA2 (`energia`) | Índice com ligações explícitas a Energia172679 e Mineração172674; preservar as três identidades e os setores existentes2/8/7. |
| [Turismo](https://investemoz.tempo.co.mz/turismo) | 171990 / setor QA3 (`turismo`) | Artigo setorial e 11 artigos territoriais explicitamente ligados; categoria Turismo preservada, sem inferir geometrias. |
| [Infraestruturas](https://investemoz.tempo.co.mz/infraestruturas) | 171992 / setor QA4 (`infraestruturas`) | Artigo integral; C72 removia um título h1. Normalização h1→h2 preparada e conferida sobre o original. |
| [Mercado Financeiro](https://investemoz.tempo.co.mz/mercado-financeiro) | 171994 / setor QA6 (`mercado-financeiro`) | Corpo vazio no exemplar atual. Arquivar metadados/original; não inventar texto nem substituir por Fintech. |
| Fonte legada | Identidade e cadastro existente | Conteúdo e lacuna concreta |
| ----------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| [Energia & Mineração](https://investemoz.tempo.co.mz/energia-mineracao) | 171981 / setor QA2 (`energia`) | Índice com ligações explícitas a Energia172679 e Mineração172674; preservar as três identidades e os setores existentes2/8/7. |
| [Turismo](https://investemoz.tempo.co.mz/turismo) | 171990 / setor QA3 (`turismo`) | Artigo setorial e 11 artigos territoriais explicitamente ligados; categoria Turismo preservada, sem inferir geometrias. |
| [Infraestruturas](https://investemoz.tempo.co.mz/infraestruturas) | 171992 / setor QA4 (`infraestruturas`) | Artigo integral; C72 removia um título h1. Normalização h1→h2 preparada e conferida sobre o original. |
| [Mercado Financeiro](https://investemoz.tempo.co.mz/mercado-financeiro) | 171994 / setor QA6 (`mercado-financeiro`) | Corpo vazio no exemplar atual. Arquivar metadados/original; não inventar texto nem substituir por Fintech. |
**Lote privado preparado: 17 versões de artigos + 5 imagens = 22 documentos.** Inclui quatro entradas setoriais, dois artigos de Energia/Mineração e 11 artigos territoriais de Turismo. A imagem de fundo genérica é um único exemplar por bytes, referenciado por vários artigos; não representa a fotografia de cada território. URLs com/sem barra são conservados como aliases do mesmo ID/versão/hash. Autoria, publicação, alteração, classificação original e HTML ficam preservados.
@@ -98,6 +101,7 @@ Provas privadas: `legacy-sector-reconciliation-20261010/reconciliation.json`, `i
<!-- legacy-manual-sectors-20261010:end -->
<!-- qa-legacy-browser-20261010:begin -->
## Verificação do piloto na interface — 10/10/2026, exclusivamente QA
**O piloto existente foi demonstrado em Chromium instalado**, com contextos separados, sem usar o perfil pessoal do utilizador. O controlo nativo continua indisponível (`native pipe`, os error 2, duas sondagens); esse problema não impediu renderização, cliques e capturas por Playwright. C37/QA18 permanece pendente; este ensaio usou Promotor QA21 e outra conta sintética QA23.
@@ -127,14 +131,14 @@ Servidor guardado: `desk_restore_20261009_174726_test`, PostgreSQL loopback **55
## Inventário e reconciliação
| Unidade | Quantidade / situação | Artefacto |
| --- | --- | --- |
| URLs efetivamente recolhidos | 92; 91 HTTP200 e um HTTP404 | `legado-inventario.csv`; originais e hashes no inventário privado |
| Versões de artigos observadas | 50 agrupadas por ID legado, alteração anunciada e hash do corpo; URLs equivalentes conservados | `legado-conteudos-reconciliados.csv` |
| Referências entre páginas/recursos | 2.826 ocorrências identificadas, incluindo destinos externos e paginação não recolhidos | `legado-referencias.csv` |
| Sitemap anunciado | 30.170 entradas; URLs de `infopublica.tempo.co.mz`, apesar da recolha no domínio InvestMoz | `legado-sitemap-anunciado.csv`; não afirmar que essas páginas foram recolhidas |
| Importação do piloto | Dois documentos e dois recursos existentes: artigo6 e imagem5; repetição sem novos documentos/recursos | `legacy-import-preview-qa.txt`, `legacy-import-qa.json` privados |
| Associações do artigo | Tema agronegócio; imagem referenciada no `thumbnail` original; apoio editorial à S01 | `portal_resource_links` existentes, com citação/âmbito; nenhuma associação territorial automática |
| Unidade | Quantidade / situação | Artefacto |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| URLs efetivamente recolhidos | 92; 91 HTTP200 e um HTTP404 | `legado-inventario.csv`; originais e hashes no inventário privado |
| Versões de artigos observadas | 50 agrupadas por ID legado, alteração anunciada e hash do corpo; URLs equivalentes conservados | `legado-conteudos-reconciliados.csv` |
| Referências entre páginas/recursos | 2.826 ocorrências identificadas, incluindo destinos externos e paginação não recolhidos | `legado-referencias.csv` |
| Sitemap anunciado | 30.170 entradas; URLs de `infopublica.tempo.co.mz`, apesar da recolha no domínio InvestMoz | `legado-sitemap-anunciado.csv`; não afirmar que essas páginas foram recolhidas |
| Importação do piloto | Dois documentos e dois recursos existentes: artigo6 e imagem5; repetição sem novos documentos/recursos | `legacy-import-preview-qa.txt`, `legacy-import-qa.json` privados |
| Associações do artigo | Tema agronegócio; imagem referenciada no `thumbnail` original; apoio editorial à S01 | `portal_resource_links` existentes, com citação/âmbito; nenhuma associação territorial automática |
O levantamento é progressivo. Não fecha a cobertura histórica do acervo: entradas do sitemap, paginação, destinos externos e conteúdos fora do piloto permanecem inventariados e por reconciliar/importar. Fontes oficiais já aceites mantêm essa decisão. O artigo Tempo é editorial: não recebe classificação oficial pelo facto de citar corredores ou políticas.
@@ -158,12 +162,12 @@ O dossier conserva apenas referência ao recurso/documento, hash, versão de met
## Referências visuais usadas
| Evidência real | Adaptação QA |
| --- | --- |
| CSS legado `app-CshAeK4J.css`: Noto Sans e Noto Serif; head inclui Instrument Sans | Instrument Sans do portal conservada; Noto Sans/Serif empacotadas localmente apenas no build QA do piloto, sem chamadas a fontes externas durante consulta |
| `welcome-DyF43GB5.js`: vermelho `#ED1C24`, hover `#b22222`, verde `#10352b`, fundo `#f6f3ea` | Fundo claro e verde profundo; vermelho escuro nos controlos para contraste legível. Não copiar cores claras com texto de contraste insuficiente |
| Hero fotográfico; cartões `rounded-2xl`, grelha móvel de uma coluna e expansão em ecrãs maiores | Imagem original, cartões sem animação obrigatória, grelha responsiva, largura de leitura limitada |
| Imagem ligada ao post e hospedagem Tempo | Original na biblioteca, alt descritivo, dimensões declaradas e origem explícita; não afirmar que a fotografia identifica um terreno disponível |
| Evidência real | Adaptação QA |
| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CSS legado `app-CshAeK4J.css`: Noto Sans e Noto Serif; head inclui Instrument Sans | Instrument Sans do portal conservada; Noto Sans/Serif empacotadas localmente apenas no build QA do piloto, sem chamadas a fontes externas durante consulta |
| `welcome-DyF43GB5.js`: vermelho `#ED1C24`, hover `#b22222`, verde `#10352b`, fundo `#f6f3ea` | Fundo claro e verde profundo; vermelho escuro nos controlos para contraste legível. Não copiar cores claras com texto de contraste insuficiente |
| Hero fotográfico; cartões `rounded-2xl`, grelha móvel de uma coluna e expansão em ecrãs maiores | Imagem original, cartões sem animação obrigatória, grelha responsiva, largura de leitura limitada |
| Imagem ligada ao post e hospedagem Tempo | Original na biblioteca, alt descritivo, dimensões declaradas e origem explícita; não afirmar que a fotografia identifica um terreno disponível |
Foco visível, labels de pesquisa, mensagens de pesquisa sem resultado, hierarquia de títulos, links identificados e layout móvel preparados em React. Estas condições não equivalem a inspeção visual, medição no navegador ou aceitação de acessibilidade completa.
File diff suppressed because one or more lines are too long
@@ -1,18 +1,66 @@
<!-- internal-tempo-designation-20261011-2876cdfa900a -->
## Regra definida pela proprietária: equipa interna Tempo — 11/10/2026
Aurora atua na operação do portal, não na gestão empresarial. A designação interna expressa pelo responsável é suficiente como fundamento do grant; **não exigir representação/comprovativos de Promotor externo para Aurora**. Palmira/Mario continuam transversais às seis categorias, sem memberships corporativas automáticas. As exigências históricas de representação e comprovativos abaixo aplicam-se aos pedidos externos, não às designações internas confirmadas. A Tempo define estas funções; a restrição genérica anterior era uma limitação de código.
Delta anterior 41a5ce778932 preservado; novo delta QA `2876cdfa900a`: cadastro mestre da operadora reutilizável, grant interno autenticado/auditado/idempotente sem documentos externos ou poderes de empresa, promotor real separado do operador e impedimentos de autoria/acumulação preservados. Doze provas HTTP/persistência; Chromium com três grants, atualização/nova sessão e entrada do Promotor pelo dashboard para criar/guardar/recuperar rascunho de promotor real distinto. Bundle de produção gerado em QA; zero alterações ativas.
Restam contas próprias/contacto/MFA, disponibilização autorizada da nova revisão e grants reais. Administração pode abrir independentemente do workflow; não acrescentar dependência documental externa para os funcionários. Workflow ativo OFF e COUNTRY02 ON; A/B/C37 preservados. Procedimento/limites: `outputs/investmoz-internal-designation-20261011/procedimento-e-evidencias.md`; manifesto e provas no mesmo diretório.
<!-- internal-tempo-designation-20261011 -->
## Regra definida pela proprietária: equipa interna Tempo — 11/10/2026
Aurora atua na operação do portal, não na gestão empresarial. A designação interna expressa pelo responsável é suficiente como fundamento do grant; **não exigir representação/comprovativos de Promotor externo para Aurora**. Palmira/Mario continuam transversais às seis categorias, sem memberships corporativas automáticas. As exigências históricas de representação e comprovativos abaixo aplicam-se aos pedidos externos, não às designações internas confirmadas. A Tempo define estas funções; a restrição genérica anterior era uma limitação de código.
Delta anterior 41a5ce778932 preservado; novo delta QA `1ab007740c44`: cadastro mestre da operadora reutilizável, grant interno autenticado/auditado/idempotente sem documentos externos ou poderes de empresa, promotor real separado do operador e impedimentos de autoria/acumulação preservados. Doze provas HTTP/persistência; Chromium com três grants, atualização/nova sessão e entrada do Promotor pelo dashboard para criar/guardar/recuperar rascunho de promotor real distinto. Bundle de produção gerado em QA; zero alterações ativas.
Restam contas próprias/contacto/MFA, disponibilização autorizada da nova revisão e grants reais. Administração pode abrir independentemente do workflow; não acrescentar dependência documental externa para os funcionários. Workflow ativo OFF e COUNTRY02 ON; A/B/C37 preservados. Procedimento/limites: `outputs/investmoz-internal-designation-20261011/procedimento-e-evidencias.md`; manifesto e provas no mesmo diretório.
<!-- onboarding-release-parallel-20261011 -->
## Preparação independente dos papéis e disponibilização do delta — 11/10/2026
Delta `41a5ce778932` e ZIP original preservados. Backup do destino pós-030000/040000 renovado: 295 tabelas, 31 sequências, 1291 ficheiros, quatro originais e dois conjuntos MFA legíveis; restauro somente em clone QA 55441. Ensaio QA de troca de código/bundle, flags, repetição de ZIP e reversão passou. Disponibilização da administração ainda não executada.
Palmira e Mario dependem de contacto/MFA próprios e atribuição autenticada nos seis tipos; **não dependem dos comprovativos de Aurora nem de representação na Tempo**. Aurora tem frente própria: organização legítima, representação, envio de comprovativos e aprovação independente. Faltam as vias autenticadas de criação/representação e upload pré-Promotor. Operações OFF até às condições de abertura, sem reabrir COUNTRY02/A/B/C37.
Procedimento, limitações e reversão: `outputs/investmoz-operational-onboarding-20261011/procedimento-disponibilizacao.md`. O relatório inicial e os blocos seguintes permanecem como histórico; a numeração anterior não cria uma dependência entre estes papéis.
<!-- onboarding-designations-20261011 -->
## Preparação das pessoas e administração de perfis — 11/10/2026
Designações confirmadas: Aurora Chachuaio (Promotor da Tempo, Lda); Palmira Uamusse (Validador transversal); Mario Melembe (Publicador transversal, catálogo público após aprovação independente). Seis categorias base para os três. Tempo, Lda é a proprietária do portal por declaração do responsável. Consulta READ ONLY: os três emails ainda não existem; zero organizações/memberships e grants. Não atribuir representação de Promotor a Palmira/Mario. Os titulares 2/13 mantêm funções de segurança, sem novos papéis operacionais.
Registo disponível no destino em HTTPS com flags operacionais OFF. SMTP STARTTLS/AUTH235 conferido sem envio; entrega/confirmacão próprias ainda pendentes. Delta `41a5ce778932` preparado numa árvore QA separada: administração/pedidos independentes das operações, preservando MFA, revogação e auditoria. Seis provas HTTP/persistência e percurso Chromium dashboard → atribuir → atualizar → nova sessão → recuperar, com operações 404 e zero oportunidades. Bundle recompilado apenas em QA; ativo não alterado.
Critérios restantes por requisito: `AUD-PROFILE-01` contas próprias verificadas/MFA e grants reais; `AUD-PROFILE-03/04` cadastro mestre legítimo da Tempo, Lda, representação de Aurora e comprovativos/revisão independente; `AUD-PROFILE-31` disponibilização autenticada do novo delta após backup correspondente e habilitação limitada após atribuições. Faltam criação autenticada de organização/representação e envio próprio de comprovativos antes de ser Promotor, reutilizando as tabelas e o processamento documental existentes. COUNTRY02 preservado, A/B e C37 fechados nos âmbitos anteriores, restauração/partilha/modulares/ofertas/SLA/190000 fora desta preparação.
Detalhes e hashes: `outputs/investmoz-operational-onboarding-20261011/preparacao-operacional.md` e `manifesto.json`. Os blocos seguintes mantêm a cronologia anterior.
# Perfis e oportunidades — reconciliação da versão 1
<!-- workflow-service-plan-b1-b3-20261011 -->
Atualização de preparação dos serviços de 11/10/2026: [intervenção B1/B2](../../../../outputs/investmoz-workflow-service-plan-20261011/intervencao-b1-b2.md), [tabela de designação B3](../../../../outputs/investmoz-workflow-service-plan-20261011/designacoes-b3.md) e [fundamento do bootstrap](../../../../outputs/investmoz-workflow-service-plan-20261011/bootstrap-fundamento.md). A candidata `98a8e0b70892` permanece intacta. Nenhuma tarefa/serviço/privilégio/schema do destino foi alterado.
Correção de interpretação de B3: três contas distintas no bootstrap são uma restrição do código atual, não uma exigência organizacional expressa na v1. A especificação exige dois titulares e aprovação independente para substituição/elevação. Antes da inicialização, o executor usa a Gate legada `manage-portal` (`PORTAL_MANAGER_EMAILS` e email verificado), mais MFA recente; não recebe automaticamente Superutilizador. A forma da cerimónia requer decisão separada antes de alterar o código; nomes e âmbitos continuam por designar pelo responsável.
B1/B2 continuam abertos no destino. Foi identificado que as tarefas existentes atualizam outra instalação ClamAV; o portal usa 3310. CLI GD/WebP foi verificado, mas não comprova SAPI web ou supervisão. A proposta contém XMLs não registados, limites só do vhost e worker periódico da fila default partilhada; execução do watchdog/limites HTTP permanece por ensaiar em QA antes do destino. COUNTRY02 ativo, A/B/C37 encerrados, restauração de oportunidades e partilha individual indisponíveis. Nenhum requisito novo ou contagem da matriz foi criado.
<!-- qa-installation-cartography-20261010:begin -->
## Estado atual — instalador, documentos e cartografia
QA exclusivamente: **http://127.0.0.1:18097**, `desk_restore_20261009_174726_test:55441`. Ativo inspecionado apenas por leitura em 2026-10-10T12:26:56+00:00: 030000, 040000 e 09/190000 ausentes; zero geometrias; manifesto preservado. **C37, Promotor QA21 e A/B permanecem visualmente pendentes. Candidata à ativação ainda não fixada.**
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --- | --- | --- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
Prova de recuperação QA: dump consistente → nova base `profile_restore_20261010_123125_test:55441` → **295 tabelas com linhas/hashes iguais e 71 ficheiros fisicamente recuperados por hash**; todos os ficheiros referenciados recuperados por hash. Arquivo privado inclui o runtime e a chave QA estável. Readiness só atesta preparação técnica desta revisão. Repetir após fixar a candidata e preparar backup ativo apenas numa futura ativação autorizada.
@@ -24,24 +72,25 @@ Prova de recuperação QA: dump consistente → nova base `profile_restore_20261
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Resultado atual por categoria — semântica e atribuições em QA, 10/10/2026
Este bloco conserva a revisão semântica anterior; o estado atual está no início do documento; as secções anteriores abaixo permanecem como histórico. Estados antigos sobre objetos opacos, coordenação editorial e ausência de 190000 ficam confrontados com os resultados concretos deste bloco. **Código preparado e HTTP/persistência em QA não encerram interface nem funcionalidade ativa.** Não houve escrita na base ativa. C37 e aceitação visual permanecem pendentes.
Servidor **http://127.0.0.1:18097**, base **desk_restore_20261009_174726_test:55441**, Fortify e MFA normais. **Promotor QA 21** continua a conta de ensaio do dashboard. Não usar Auditor ou Superutilizador em seu lugar.
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| --- | --- | --- | --- | --- | --- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| ------------------------- | -------------------------------- | ------------------------------- | ------------------------------- | ------------------------- | --------------------------------------------- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
As dez categorias recuperaram dados noutra sessão autenticada. As seis com contrato definido aceitaram os cenários semânticos documentados; as quatro restantes conservaram rascunhos, sem inventar um perfil modular para as submeter. Fundiário #32 separa aprovação interna da decisão externa. Venda #33 passou depois pelo percurso editorial público, sem divulgar resumo/dados privados.
@@ -59,40 +108,41 @@ As dez categorias recuperaram dados noutra sessão autenticada. As seis com cont
Mesma matriz: **3.386 requisitos / 3.386 linhas**, **6.838 ocorrências de origem**. IDs, fontes, critérios, versões divergentes e referências anteriores conservados.
| Estado canónico | Requisitos | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências de origem |
| ------------------------------- | ---------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31 e AUD-OPS-01**, em [matriz-requisitos.csv](matriz-requisitos.csv). Nenhum desses critérios visuais foi fechado por API.
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Incremento canónico e workflow em QA — 10/10/2026
Servidor **http://127.0.0.1:18097**; destino guardado **desk_restore_20261009_174726_test:55441**. Zero escritas na base ativa. **C37 e toda a aceitação visual deste incremento permanecem pendentes.** Props da interface, API e persistência foram verificadas; nenhum clique ou renderização no navegador foi observado.
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --- | --- | --- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
Os requisitos acima continuam **parciais**: nenhum passou a concluído pelo incremento. O detalhe está no [relatório do workflow](workflow-oportunidades-qa.md); fontes, versões, critérios e percursos permanecem na [mesma matriz](matriz-requisitos.csv).
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| ------------------------------ | ----------------------------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requisitos abertos**. As referências e versões anteriores foram preservadas.
@@ -100,19 +150,20 @@ Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requ
<!-- qa-workflow-20261010:end -->
<!-- qa-profiles-v1-20261010:begin -->
## Perfis v1: resultado do lote em QA — 10/10/2026
A v1 foi lida integralmente: 530 parágrafos, confrontados com os 471 do exemplar anterior, AGENTS, auditoria, código, schema PostgreSQL e configuração. Fortify, contas, documentos, relações, IDs, classificações, histórico, cinco fases e 19 etapas foram preservados. Keycloak foi avaliado como recomendação; não há necessidade de SSO/federação demonstrada para substituir Fortify neste lote. A aceitação das fontes oficiais permanece intacta.
**A mesma matriz contém 3.386 requisitos/linhas e 6.838 ocorrências de origem.** Os 3.354 requisitos e 5.830 referências anteriores foram conservados. Acrescentaram-se 32 requisitos verificáveis, os 1.001 parágrafos dos dois exemplares e sete referências diretas da reconciliação. Parágrafos de estrutura e tabelas são referências, não pedidos independentes. Inventário: 591 exemplares, versões e anexos; 202 ficheiros acessíveis nesta varredura, incluindo 12 marcadores de bloqueio Office preservados por bytes/hash.
| Estado canónico | Requisitos | Ocorrências |
| --- | ---: | ---: |
| parcial | 3228 | 6371 |
| não implementado | 146 | 454 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências |
| ------------------------------ | ---------: | ----------: |
| parcial | 3228 | 6371 |
| não implementado | 146 | 454 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
O sexto concluído é apenas **AUD-PROFILE-27**, a avaliação arquitetural de Keycloak. Não encerra autenticação visual nem uma integração externa. **AUD-OP-03 passa a parcial**, pelas regras e transições novas; o workflow integral continua aberto.
@@ -138,7 +189,6 @@ Evidências sanitizadas: `profiles-v1-http-qa.json`, `profiles-v1-mfa-enrollment
[Correspondência por requisito](perfis-v1-reconciliacao.md), [roteiro manual](roteiro-manual-perfis-v1.md), [backlog](backlog.md), [ativação e reversão](plano-ativacao.md). Relatório e backlog também disponíveis no servidor QA, com autenticação, em `/qa-auditoria/relatorio-executivo` e `/qa-auditoria/backlog`.
### Correspondência derivada da mesma matriz
Esta projeção não é outro inventário editável. Fontes e versões integrais permanecem no CSV.
@@ -484,25 +534,25 @@ Fonte integral: `Gestao de perfis investeMOZ v1.docx`, versão 1.0, 10/10/2026,
## Correspondência dos perfis
| Perfil v1 | Entidades e controlos reutilizados | Âmbito e regra |
| --- | --- | --- |
| Utilizador público | `users`, verificação Fortify, favoritos/alertas/pedidos existentes | Dados e pedidos próprios; catálogo público; solicita perfil, sem criar oportunidades |
| Promotor | `users`, `memberships`, autorização por tipo, OpportunityManagement/Resources | Organização representada e tipos aprovados; pessoal apenas próprio; guarda e responde a correções |
| Validador | Papel atribuído a `users`, oportunidades/auditoria existentes | Âmbito/tipo, MFA, independência do autor/editores/organização; revisão sem publicação |
| Publicador | Papel atribuído a `users`, versão aprovada e auditoria | MFA, aprovação independente da versão; não edita conteúdo técnico |
| Auditor | Papel atribuído a `users`, `audit_events` e configurações | Leitura e exportação minimizada; negação de escrita operacional prevalece |
| Superutilizador | Dupla controlada ligada a `users`, Fortify/MFA, auditoria | Administração de perfis; operação exige elevação independente e papel operacional |
| Perfil v1 | Entidades e controlos reutilizados | Âmbito e regra |
| ------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Utilizador público | `users`, verificação Fortify, favoritos/alertas/pedidos existentes | Dados e pedidos próprios; catálogo público; solicita perfil, sem criar oportunidades |
| Promotor | `users`, `memberships`, autorização por tipo, OpportunityManagement/Resources | Organização representada e tipos aprovados; pessoal apenas próprio; guarda e responde a correções |
| Validador | Papel atribuído a `users`, oportunidades/auditoria existentes | Âmbito/tipo, MFA, independência do autor/editores/organização; revisão sem publicação |
| Publicador | Papel atribuído a `users`, versão aprovada e auditoria | MFA, aprovação independente da versão; não edita conteúdo técnico |
| Auditor | Papel atribuído a `users`, `audit_events` e configurações | Leitura e exportação minimizada; negação de escrita operacional prevalece |
| Superutilizador | Dupla controlada ligada a `users`, Fortify/MFA, auditoria | Administração de perfis; operação exige elevação independente e papel operacional |
## Responsabilidades adicionais — não são novos perfis
| Responsabilidade citada | Correspondência proposta | Limite |
| --- | --- | --- |
| Coordenador de validação | Validador com responsabilidade `validation_coordinator` explicitamente atribuída | Atribuir/reencaminhar; mesmos impedimentos para decidir |
| Responsável técnico/jurídico | Validador com âmbito e responsabilidade técnica/jurídica | Parecer documentado, não decisão externa presumida |
| Suporte técnico | Superutilizador com responsabilidade técnica, ou tarefa atribuída a suporte no mecanismo existente | Diagnóstico de incidente; não ganha acesso ao conteúdo ou decisão por receber tarefa |
| Gestor operacional/direção/conformidade | Superutilizador administrativo; Auditor para controlo sem escrita | Escalar e auditar; não ultrapassa segregação operacional |
| Instância de recurso | Validador com responsabilidade `appeal_reviewer`, distinto de autor, editores e decisor inicial | Decisão de recurso preserva decisão original; não publica |
| Coordenador de publicação | Publicador com responsabilidade de coordenação | Reatribuir publicação; não aprova conteúdo |
| Responsabilidade citada | Correspondência proposta | Limite |
| --------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Coordenador de validação | Validador com responsabilidade `validation_coordinator` explicitamente atribuída | Atribuir/reencaminhar; mesmos impedimentos para decidir |
| Responsável técnico/jurídico | Validador com âmbito e responsabilidade técnica/jurídica | Parecer documentado, não decisão externa presumida |
| Suporte técnico | Superutilizador com responsabilidade técnica, ou tarefa atribuída a suporte no mecanismo existente | Diagnóstico de incidente; não ganha acesso ao conteúdo ou decisão por receber tarefa |
| Gestor operacional/direção/conformidade | Superutilizador administrativo; Auditor para controlo sem escrita | Escalar e auditar; não ultrapassa segregação operacional |
| Instância de recurso | Validador com responsabilidade `appeal_reviewer`, distinto de autor, editores e decisor inicial | Decisão de recurso preserva decisão original; não publica |
| Coordenador de publicação | Publicador com responsabilidade de coordenação | Reatribuir publicação; não aprova conteúdo |
Estas correspondências técnicas não nomeiam responsáveis reais. Responsáveis institucionais, SLA, tolerância, limites de ciclos e política documental por tipo precisam de valores aprovados e versionados antes de automatizar escalamentos. Não se inventam prazos. Enquanto ausentes, devem ficar visíveis e sem encerramento automático.
@@ -1,4 +1,398 @@
<!-- C132-contained-20261012 -->
## C132 contido no ativo — incidente ainda aberto
Autorização específica do responsável executada: apenas `config/inertia.php`, DevTools OFF desde 12/10 18:57:15 UTC. HTTP anónimo index/detalhe real/detalhe arbitrário **404**. Login **200** e confirmação manual de **login, MFA e dashboard**. C131 não aplicado; COUNTRY02, papéis, bundle, chave/cifra, A/B e C37 preservados.
276 diagnósticos em 279 ficheiros preservados restritamente. Cookies/passwords/tokens mascarados nos exemplares retidos, mas quatro sementes TOTP e 32 códigos de recuperação correspondentes às contas 14–17 foram expostos: renovados seletivamente, obrigatoriedade MFA preservada. Zero correspondências entre os valores retidos e as credenciais atuais. Backup/restauro do destino renovado antes da resposta às credenciais, 295 tabelas/31 sequências, clone isolado 55441. Restam entrega individual das novas entradas e delimitação histórica; **não declarar fecho do incidente**.
[Relatório de contenção, alcance, período, provas e medidas restantes](C132-incidente-contido.md). Os retratos anteriores de C132 exposto abaixo são histórico anterior à contenção, não o estado atual. A matriz existente mantém os IDs; AUD-PROFILE-26 passa a parcial, sem fecho da privacidade integral.
<!-- /C132-contained-20261012 -->
<!-- audit-current-20261012 -->
## Correções atuais em QA — delta a23156a65be2 — 12/10/2026
Base preservada: entrega 2e2f16c83483/código a02ef2300d6c, COUNTRY02 e workflow/perfis ON; 030000/040000/050000 já instalados. Este plano **não autoriza alterações no ativo** e não repete instalações. C132 foi confirmado também no destino por GET anónimo (445 metadados, detalhe operacional 200); a correção QA não elimina essa exposição. Conter prioritariamente pela desativação explícita autorizada, sem redistribuir diagnósticos privados.
| Alteração exata | Efeito | Dependência/teste | Reversão |
|---|---|---|---|
| app/Services/OpportunityContacts.php(C131) |Normalização antes do Validator; mesma chave/identidade/dedup/autorizações; nenhuma coluna/tabela nova.|POSTválido, replay/mesmo UUID, curto 422, logout/nova sessão/recuperação; observação UIpendente.|Conservar fonte anterior e restaurar só este ficheiro perante regressão; contacto válido já gravado continua válido.|
| config/inertia.php(C132) |DevTools explicitamente OFF, incluindo APP_ENV=local; não altera MFA, negócio, flags, cifra ou HTTPS.|Listagem/detalhe 404, login/MFA e páginas normais 200; sem publicar/expurgar diagnósticos.|**Não reabrir diagnósticos como contenção.** Se for necessário retirar outra correção, manterdevtools OFF por configuração explícita equivalente e decidir restauro de código separadamente.|
Produção: duas fontes PHP; nenhum recurso React alterado, não exige recompilação dos 159 recursos existentes. Sintaxe e hashes conferidos. Manifesto [manifesto-correcoes-qa.json](../../../../outputs/investmoz-audit-current-20261012/manifesto-correcoes-qa.json), fontes preparadas privadas de execução apenas no pacote de revisão. Não disponibilizar se qualquer hash de base divergir.
Sequência futura, após completar critérios dirigidos e autorização concreta:
1. Fixar delta/bundle reutilizado e conferir basea 02. Fazer nova leitura alvo/configuração/flags/migrations/serviços/fila; não consumir trabalhos ativos.
2. Renovar backup/restauro **do destino/revisão correspondente** (DB+originais/recursos+config/cifra/ACLs) no clone isolado. O backup 11:10:30 UTC 12/10 com 295 tabelas/31 seq/1391 ficheiros é histórico válido, não prova este novo delta.
3. Disponibilizar somente duas fontes PHP pelos controlos existentes; sem migrations/instaladores, sem flags novas/contas/grants. 030000/040000/050000 não reaplicar. 190000 continua separado do workflow isolado e só entra no percurso integrado.
4. Conferir PHPweb/HTTPS/recursos e ausência de duas rotasdiagnósticas; repetir apenas contactos/erros/permissões/sessão afetados. Auditar disponibilização/hashes e preservar originais/cifra/história.
5. Perante divergência: parar antes da troca. Perante regressão: conter a açãoafetada e repor fonte correspondente; preservar DevTools OFF, HTTPS, dados, colunas, histórico. Restauro completo exige decisão separada.
Sem intervenções Laragon/CA/DLL/worker/Clam D previstas neste delta. Verificação fresca de metadados do worker pode requerer leitura elevada por ACL; isso não justifica novas tarefas/consumo de fila sem necessidade. Nenhuma intervenção humana solicitada neste lote. A/B, C37, onboarding e grants não voltam à sequência de instalação. Planos históricos abaixo não são ações pendentes.
<!-- /audit-current-20261012 -->
<!-- workflow-opening-2e2f16c83483-20261012 -->
## Estado atual — workflow disponibilizado em 12/10/2026
**Entrega 2e2f16c83483 / código a02ef2300d6c disponibilizada; seis categorias base abertas para os perfis já atribuídos. COUNTRY02 e administração ON.** [Resultado, acessos e limitações](../../../../outputs/investmoz-workflow-opening-20261012/resultado.md), [manifesto de execução](../../../../outputs/investmoz-workflow-opening-20261012/manifesto-execucao.json), [HTTPS e 159 recursos conferidos](../../../../outputs/investmoz-workflow-opening-20261012/web-enabled.json) e [navegação por perfil](../../../../outputs/investmoz-workflow-opening-20261012/navegacao-perfis-leitura.json).
Autorização do responsável: «pode fazer a entrega». Nove fontes/159 recursos, três gates conjuntos; nenhuma migration, conta, organização, representação, atribuição, importação, publicação ou alteração de serviço. Backup real anterior à intervenção de 11:10:30UTC restaurado/verificado:295 tabelas/31sequências/1391ficheiros/4originais/6MFA. Código/dados/grants/cifra/histórico preservados e contenção preparada. Bootstrap e validação de funcionários concluídos não voltam a ser requisitos pendentes.
**Critérios restantes incluídos:** acompanhamento do primeiro processo/documentos legítimos no destino; a conferência HTTP/política não é uma nova demonstração visual humana. QA/contacto e fechos A/B/C37 preservados, sem repetição. **Fora:** contrato normativo integral/cargo ainda parcial, variantes não demonstradas, restauração/partilha individual, camadas cartográficas, legado,190000,modulares/ofertas/competências/SLA,acessibilidade integral/dispositivos reais. Notificações OFF. As pendências não identificadas como dependência deste âmbito não bloqueiam os acessos já abertos.
As referências a workflow OFF/designações/importações/ativação pendentes nos blocos abaixo conservam o histórico e não substituem este estado atual. Mesma matriz, sem novos IDs/fontes ou fechos globais.
<!-- /workflow-opening-2e2f16c83483-20261012 -->
<!-- workflow-authorized-activation-20261011 -->
## Execução técnica autorizada no destino — 41caea0f900f
**Código/bundle, B1/B2, 030000 → 040000 e bootstrap cruzado concluídos no destino. COUNTRY02 preservado ON; fluxos operacionais OFF.** [Resultado e limites](../../../../outputs/investmoz-workflow-activation-20261011/resultado.md), [provas sanitizadas](../../../../outputs/investmoz-workflow-activation-20261011/evidencias-destino.json), [procedimento executado/reversão](../../../../outputs/investmoz-workflow-activation-20261011/procedimento-executado.md) e [designações](../../../../outputs/investmoz-workflow-activation-20261011/designacoes-operacionais.md).
Pacote/code/manifesto41caea0f900f/117d2d889701 preservados. Backup do destino de17:12:20UTC restaurado/verificado no clone:288 tabelas/31sequências/867ficheiros/4originais. No destino, somente030000 pela conta2 e040000 pela conta13, por ações HTTP autenticadas:288→291→295tabelas/5colunas/0novas sequências. Auditoria sem duplicações. Bootstrap:pedido13/confirmação2, sessões/MFA próprios, uma dupla/um pedido consumido. Zero novas identidades/organizações/representações ou concessões operacionais.
ClamD3310/LocalService/assinaturas28150 e ACLs positivas/negativas demonstrados. PHPweb20M/24M/256M/180s/GD/WebP e trêsvhosts verificados no Chromium com TLS reconhecido. Recarga própria graciosa do Apache expressamente autorizada após Laragon não recarregar a instância fora dele. Worker supervisionado habilitado após releitura da default vazia/notificações OFF; primeira execução0. O processamento documental completo/falha/repetição continua prova distinta do clone; no destino falta atividade documental legítima. Dados das288tabelas anteriores,4originais/2envelopesMFA eCOUNTRY02 preservados.
**Pendências operacionais:** designarPromotor/Validador/Publicador com contaexistente,organização/representação legítima,tipos/âmbito/responsabilidade; abertura dos fluxos separada. País mestre real aguardará organização legítima. Restauração/partilha individual,190000,cartografia/acervo/legado,modulares/ofertas/SLA continuam fora. A/B/C37 e provas QA válidas preservadas, sem repetição. Contenção preservaHTTPS/cifra/COUNTRY02/schema/histórico; restauro completo exige decisão separada.
Mesma matriz:3401requisitos/linhas,7739ocorrências, apenas3evidências complementadas; zero novosIDs/fontes e estados gerais preservados. Os blocos seguintes são históricos; as instalações e o bootstrap neles referidos como pendentes foram concluídos neste âmbito técnico.
<!-- /workflow-authorized-activation-20261011 -->
<!-- workflow-execution-preparation-20261011 -->
## Preparação técnica e habilitação operacional separadas
[Relatório da preparação](../../../../outputs/investmoz-workflow-execution-preparation-20261011/relatorio-preparacao.md), [proposta única de execução](../../../../outputs/investmoz-workflow-execution-preparation-20261011/procedimento-unico.md), [backup do destino](../../../../outputs/investmoz-workflow-execution-preparation-20261011/backup-destino-verificado.json) e [designações operacionais](../../../../outputs/investmoz-workflow-execution-preparation-20261011/designacoes-operacionais.md).
Candidata **41caea0f900f**, código **117d2d889701**, ZIP/manifesto imutáveis; 98a8e0b70892 e o plano histórico B1/B2 preservados. O responsável confirmou que ID 2/nala@tempo.co.mz e ID 13/onala@me.com são **duas pessoas diferentes**. Identificação e independência dos titulares resolvidas; nenhum bootstrap/grant ativo executado.
Backup/restauro do **destino real investemoz:5432** renovado **2026-10-11T17:12:20+00:00**, restaurado somente no novo clone 55441: **288 tabelas/31 sequências/867 ficheiros**, 4 originais/0 ausentes/2 MFA legíveis, linhas/seq/bytes iguais. Mais 68 ficheiros de serviços face aos 799, com scanner/config/assinaturas/PHP/XML e metadados de 986 ACLs. DACLs/tarefas recuperadas como ficheiros/metadados, não aplicadas no Windows ativo. Compatibilidade e reversão vazia 030000→040000 passaram no novo clone: 288→291→295 tabelas, 5 colunas; todas as linhas/colunas/seq e 050000 preservadas. Não é instalação autenticada no destino.
**Uma autorização técnica proposta:**código/bundle+B1/B2+030000→040000 autenticadas+bootstrap cruzado dos dois titulares. Manter COUNTRY02 ON e os fluxos operacionais OFF. Readiness preparado apenas em armazenamento privado de recuperação, ainda não disponibilizado aos instaladores do destino. Fila ativa lida sem consumo/notificações externas; nova leitura imediatamente antes do worker, parar perante NotifyInterestReceived ou classe desconhecida. Intervenção no destino continua por autorizar.
**Habilitação operacional separada:**faltam designações de Promotores, Validadores e Publicadores, com conta existente, organização/representação legítima, tipos e âmbito. Isso condiciona a abertura dos fluxos, não a preparação/instalação técnica. As provas de LocalService, bootstrap, coedição, categorias, A/B e C37 válidas foram reaproveitadas. Nenhuma nova prova de dispositivos reais/acessibilidade integral foi declarada. Restauração/partilha individual, 190000, legado, ofertas/modulares/SLA permanecem fora; restauro completo do destino exige decisão própria.
Mesma matriz: 3401 requisitos/7739 ocorrências; três células de evidência atualizadas, nenhum ID/fonte/estado geral alterado. Os blocos seguintes preservam o histórico; as pendências de backup e de independência neles referidas ficam reconciliadas por este bloco atual.
<!-- /workflow-execution-preparation-20261011 -->
<!-- consolidated-workflow-qa-20261011 -->
## Candidata consolidada 41caea0f900f — QA, sem ativação
[Relatório e bloqueios](../../../../outputs/investmoz-workflow-consolidated-20261011/relatorio-consolidacao.md), [procedimento único](../../../../outputs/investmoz-workflow-consolidated-20261011/procedimento-unico.md) e [manifesto](../../../../outputs/investmoz-workflow-consolidated-20261011/manifesto.json).
Delta 117d2d889701 integrado: 22 ficheiros de código + 159 assets (181 no ZIP), referência 98a8e0b70892 preservada. Compilação de produção do delta verificada por bytes; nenhuma alteração de código adicional. Prévia Chromium/MFA 040000 com fingerprint novo e dependência 030000 corresponde ao restauro renovado; gestor legado fora da dupla QA recebe 403, titular autorizado recebe 200. Instalações/funcionalidades válidas não repetidas.
LocalService S-1-5-19 demonstrada no clone 55441: configuração lida, ClamD 13310, quatro scans PDF de 20 MiB/trêsWebP, fila 4 → 0 e repetição 0 → 0, zero recursos novos/falhas e hashes/cifra recuperados; escrita só nas áreas QA autorizadas, negada em código/vendor/config/.env e leitura alheia negada. Tarefa própria removida. Limite180s/lease 210 s anteriores preservados como prova distinta de utilizador interativo. Não é instalação/prova do destino 3310.
191 ficheiros reconciliados:22código + 159 bundle + 1 env+9documentais, incluindo os 4 originais do destino com hashes iguais e 5 ficheiros sintéticos. Backup 799 do destino tem âmbito maior; os 8 documentais exclusivos da QA 188 continuam no backup anterior. Restauro QA renovado 16:49:42 UTC: 295 tabelas / 31 sequências / 191 ficheiros / 9 MFA; renovar o backup/restauro do destino real e associar à revisão antes da intervenção.
B3: responsável confirmou nala@tempo.co.mz (**ID 2**) e onala@me.com (**ID 13**); email/MFA/gestão legada verificados READ ONLY e compatibilidade do envelope validada no clone. IDs 3/18 iniciais reconciliados. Designação registada, sem conceder privilégios. Ainda faltam autorização/cerimónia cruzada e contas/organização/tipos/âmbito operacionais. B1/B2: serviços 3310, supervisão/limites e ACLs efetivas do destino por autorizar/verificar; RX adicional não neutraliza escrita herdada. Notificações OFF e nova leitura da default imediatamente antes de iniciar worker; parar perante classe desconhecida ou notificação enfileirada.
Mesma matriz: 3401 requisitos / 7739 ocorrências, três evidências complementadas, zero IDs/estados gerais novos. COUNTRY02 ativo e fechos A/B/C37 preservados. Restauração/partilha individual/190000/legado/modulares/ofertas/SLA permanecem fora. Os blocos seguintes mantêm o histórico.
<!-- /consolidated-workflow-qa-20261011 -->
<!-- service-followup-qa-20261011 -->
## Serviços e confirmação cruzada — QA de 11/10/2026
[Relatório](../../../../outputs/investmoz-service-followup-20261011/relatorio.md) e [evidências](../../../../outputs/investmoz-service-followup-20261011/evidencias-por-criterio.json).
PT3M real: processo terminado entre 178.227 e 180.244 s; job reservado retomado após lease 210 s, sem duplicações. PDF 2,5 MiB, imagem 3,3 MB/três WebP, PHP web 20M/POST 24M/GD/WebP e rejeições20 MiB+1/25 MiB/10 MiB+1 demonstrados. Fronteira 20 MiB: web201; CLI 128M falha por memória; comando já previsto 256M recupera mesmojob/original sem reenviar, pico 148 MiB. Plano preservado; não omitir -d memory_limit=256M. Default do destino lida sem executar:zero jobs/falhas; tipos/efeitoSMTP explicitados.
Bootstrap cruzado demonstrado como **delta QA 117d2d889701**, sem integração na candidata 98a8e0b70892: pedido15/confirmação16 com MFA e auditoria separados, sem autoaprovação; pedido recuperado em nova sessão, sem privilégio antecipado. Segundo titular sem gestão geral prévia. Zero DDL adicional, entidades/Fortify reutilizados. Terceiro inicializador não é exigência organizacional; a futura candidata deve incorporar a nova cerimónia.
RestauroQA pós-uso **2026-10-11T16:29:27+00:00**:295 tabelas/31 sequências/191 ficheiros/9 MFA; não substitui o destino. B1/B2: intervenção/provaLocalService / PHPweb/ClamD no destino; B3: dois titulares/âmbitos legítimos e integração do delta. Mesmas3401 linhas/7739 ocorrências, zero IDs/estados gerais novos. COUNTRY02/A-B/C37 preservados; restauração/partilha individualOFF. Os blocos seguintes conservam a história.
<!-- /service-followup-qa-20261011 -->
<!-- workflow-scope-qa-20261011 -->
<!-- workflow-service-plan-b1-b3-20261011 -->
Atualização de preparação dos serviços de 11/10/2026: [intervenção B1/B2](../../../../outputs/investmoz-workflow-service-plan-20261011/intervencao-b1-b2.md), [tabela de designação B3](../../../../outputs/investmoz-workflow-service-plan-20261011/designacoes-b3.md) e [fundamento do bootstrap](../../../../outputs/investmoz-workflow-service-plan-20261011/bootstrap-fundamento.md). A candidata `98a8e0b70892` permanece intacta. Nenhuma tarefa/serviço/privilégio/schema do destino foi alterado.
Correção de interpretação de B3: três contas distintas no bootstrap são uma restrição do código atual, não uma exigência organizacional expressa na v1. A especificação exige dois titulares e aprovação independente para substituição/elevação. Antes da inicialização, o executor usa a Gate legada `manage-portal` (`PORTAL_MANAGER_EMAILS` e email verificado), mais MFA recente; não recebe automaticamente Superutilizador. A forma da cerimónia requer decisão separada antes de alterar o código; nomes e âmbitos continuam por designar pelo responsável.
B1/B2 continuam abertos no destino. Foi identificado que as tarefas existentes atualizam outra instalação ClamAV; o portal usa 3310. CLI GD/WebP foi verificado, mas não comprova SAPI web ou supervisão. A proposta contém XMLs não registados, limites só do vhost e worker periódico da fila default partilhada; execução do watchdog/limites HTTP permanece por ensaiar em QA antes do destino. COUNTRY02 ativo, A/B/C37 encerrados, restauração de oportunidades e partilha individual indisponíveis. Nenhum requisito novo ou contagem da matriz foi criado.
<!-- workflow-upgrade-qa-20261011 -->
## Atualização do clone do destino — 98a8e0b70892
**QA demonstrada; ativo não atualizado.**030000→040000 autenticadas no clone real288→295;050000/COUNTRY02,originais,permissões,cifra/histórico preservados. PDF/PNG/DOCX/XLSX e3WebP com scanClamDreal/hash/recuperação;worker sai após reservar e recupera mesmojob210s depois;repetições sem duplicação. C127:Super requer perfil operacional no âmbito+elevação de consulta independente15min,sem aprovação própria;revogação/novo login e outro dossier recusados. C128:derivadas reutilizadas. UI390px e asset carregado conferidos. A/B,C37 e provas válidas conservadas.
Lista única de bloqueios:B1ClamD do destino stale;B2worker/PHPdocumental supervisionados por comprovar no destino;B3dois titulares+terceiro gestorMFA+âmbitos legítimos por designar. Instalações só sob futura autorização;190000 não bloqueia workflow isolado. Restauração e partilha individual permanecem desabilitadas. Candidata/código:98a8e0b70892/557cbad27987,17ficheiros/158assets,`activation_ready=false`. Relatório e procedimento:`outputs/investmoz-workflow-upgrade-20261011/`.
Mesma matriz3401requisitos/linhas,7739ocorrências;seteIDs atualizados,zero novos. Backup/restauro REAL do alvo `2026-10-11T15:11:50+00:00`:288tabelas/31seq/799ficheiros/2MFA;QA pós-uso `2026-10-11T15:11:55+00:00`:295/31/188/9MFA. Não transformar este restauroQA em prova de funcionamento ativo. Renovar após ajustes/revisão/expiração/antes da intervenção.
*As secções seguintes conservam evidências e estados históricos;este bloco contém o estado atual.*
<!-- /workflow-upgrade-qa-20261011 -->
## Candidata delimitada e proteção documental — 11/10/2026
C126 corrigido somente em QA: a rota geral exige a autorização atual da oportunidade. Originais, derivadas e revogação de perfil foram demonstrados; a ACL individual continua indisponível e explicada na interface. R-ARCHIVE e R-DRAFT são propostas separadas. As variantes imobiliárias excluídas continuam recuperáveis em preparação, com submissão recusada e erros semânticos preservados.
Nova candidata **e871f8aadb59**, código **d19dd63b67b4**: 14 ficheiros de código e 158 assets recompilados. [Relatório com âmbito, ACL e decisões](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/relatorio.md), [procedimento](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/procedimento.md), [manifesto](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/manifesto.json). A referência `8af63e2fe657` mantém os bytes e o histórico, mas C126 impede a sua disponibilização.
Backup do **destino real** renovado em 2026-10-11T14:24:45+00:00: 288 tabelas, 31 sequências, 799 ficheiros e dois envelopes MFA, com restauro apenas em QA/55441. QA funcional: 295 tabelas, 31 sequências, 288 ficheiros e 17 envelopes MFA. A diferença de sete tabelas corresponde a 030000/040000; o acervo privado QA não foi importado no ativo.
**Ainda não pronto para ativação:** ClamD do destino com assinaturas obsoletas; worker/GD e processamento documental por demonstrar no destino; ensaio de atualização do clone e recibos/prévias específicos; designação de titulares e âmbitos legítimos. O destino tem apenas duas contas com MFA e o bootstrap exige dois titulares e um terceiro gestor independente com MFA: essa preparação humana falta. Zero geometrias no destino; importação separada se forem incluídos os limites administrativos. Não reaplicar 050000. 030000 precede 040000; 190000 permanece separado.
COUNTRY02 ativo, A/B e C37 preservados; nenhuma alteração no ativo. Mesma matriz: 3.401 requisitos/linhas, 7.739 ocorrências, dez requisitos existentes atualizados e zero IDs novos; estados gerais preservados.
<!-- workflow-functional-candidate-20261011:begin -->
## Candidata de workflow3d9d392e0a0f: sequência independente do percurso integrado
[Procedimento delimitado](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/procedimento.md) e [manifesto](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/manifesto.json). Sem autorização ativa para este pacote. COUNTRY02 ON preservado. Dependências:020000 instalado→030000→040000, somente se ausentes e mediante prévia autenticada correspondente; bootstrap/designações e flags são ações separadas.190000 continua necessário ao pacote do percurso integrado, não ao workflow isolado.
Futuro efeitoDDL:7 tabelas+5 colunas previstas nas migrations existentes, nenhum cadastro/conta/representação/publicação automática. Código/bundle12/158. Sem mudançaHTTPS/cookie/PHP/DLL/vhosts. Destino tem0 geometrias; importação de limites é pacote/decisão separados. Atualizar assinaturasClamD3310 e comprovar worker antes de prometer anexos/derivadas. Renovar backup/restauro alvo e ensaio de disponibilização do bundle/fingerprints finais; QA295não substitui alvo288. Contenção:desligar apenas flags deste pacote, preservandoCOUNTRY02 ON,HTTPS,cifra,schema,dados/documentos/histórico. Não executar `down` ou restauro completo após uso sem decisão própria.
<!-- workflow-functional-candidate-20261011:end -->
<!-- portal-stability-authorized-activation-20261011:begin -->
## Estado mais recente — COUNTRY02 ativo, revisão 485ee04c40b2
Somente `050000` foi aplicada pela interface autenticada em 11/10/2026 às 10:39:39 UTC e COUNTRY02 habilitado às 10:39:51 UTC. Prévia correspondente à revisão/código/backup/destino `investemoz:5432`; aplicação302, repetição200 com mesmo recibo e conteúdo diferente/mesma chave409. Verificação READ ONLY final em 2026-10-11T10:49:16+00:00: duas colunas opcionais, 288 tabelas, 13 contas, zero organizações/representações, 80 migrations e 127 audits. Uma auditoria de instalação; nenhuma nova tabela, conta, organização ou representação. Restantes flags OFF e pacotes 030000/040000/190000 ausentes.
Chromium confirmou HTTPS reconhecido, login/MFA, perfil, atualização e voltar/avançar com histórico cifrado. Nova sessão com segundo MFA e GET do perfil 200/no-store, acompanhada de confirmação manual. Logout 302/API 401 e Voltar ao login sem perfil privado. Chave/cipher e MFA originais preservados; rotação normal de `remember_token` do ator 13 reconciliada por comparação campo a campo, sem exportar valores.
Backup/restauro real correspondente verificado às 10:03:46 UTC (288 tabelas, 31 sequências, 379 ficheiros e 2 MFA); hashes do pacote/backup e código/bundle instalados conferidos. Certificado/cookie/runtime/vhost predefinido e 46 ativos carregados aprovados. C118: Laragon regenerava o vhost `auto.`; bytes HTTPS aprovados conservados no ficheiro personalizado sem esse prefixo. Arranque direto único aceite expressamente pelo responsável; nenhum hash do pacote mudou.
**Gravação ativa do país mestre permanece pendente de uma organização legítima e representação autorizada (0/0).** Esse critério mantém AUD-COUNTRY-02 parcial, embora a extensão esteja ativa. AUD-OPS-01 permanece parcial pelos restantes consumidores/pacotes. A/B e C37 preservados; não se encerram a auditoria global nem outras decisões.
Mesma matriz: 3393 requisitos/linhas e 6845 referências; 7 concluídos, 3386 abertos (3235 parciais, 145 não implementados, 1 implementado mas não ativado e 5 decisões concretas). Apenas AUD-COUNTRY-02/AUD-OPS-01 atualizados. [Resultado, auditoria e limites](../../../../outputs/investmoz-portal-stability-activation-20261011/resultado.md) e [ajustes operacionais](../../../../outputs/investmoz-portal-stability-activation-20261011/ajustes-execucao.md). Contenção somente COUNTRY02 OFF preserva HTTPS/schema/dados/histórico; restauro completo continua sujeito a decisão separada. Blocos abaixo são histórico anterior.
<!-- portal-stability-authorized-activation-20261011:end -->
<!-- portal-stability-20261011:begin -->
## Estado atual — estabilização integrada QA, ativação suspensa
**A instrução de suspensão substitui qualquer passo histórico para retomar a ativação. COUNTRY02 permanece desabilitado no ativo.** A autorização anterior `13644ed74a48`/`162daff6ce08` fica registada no âmbito original, sem aprovar automaticamente os acréscimos da revisão fixa `485ee04c40b2`. Nenhuma alteração ativa nesta estabilização; Apache ativo não reiniciado.
COUNTRY02 foi demonstrado no Chromium com Apache/PHP do destino, hostname `portal-investidor.test`, HTTPS reconhecido e produção final: estado anterior → login/MFA → prévia → instalação somente 050000 → replay único → perfil/PT/F5 → MZ/v3 → voltar/avançar cifrados → logout/API401/Back sem master → nova sessão/MFA/recuperação. SQL: duas colunas, zero tabelas novas, uma auditoria de instalação, duas edições cifradas; fixtures apenas em QA. Backup original real restaurado (288 tabelas/31 sequências/379 ficheiros/2 MFA) e backup pós-utilização QA também restaurado, preservando os dados novos.
Frente C110–C112 consolidada com C113–C117: 25 chamadas em 14 componentes usam utilitário CSPRNG comum; cURL/DLL corrigido só na cópia Apache QA; OPcache isolado; GeoJSON por feature dentro de 128 MiB; bootstrap MFA normal sem recifrar; mensagens consecutivas não perdem texto. Critérios e limites individuais no relatório. O clone cartográfico atual contém 408 registos com hash integral preservado; 393 é histórico. Não houve divulgação nem instalação de outros pacotes ativos.
Ativo lido às 09:40:51 UTC: 13 contas/0 organizações/0 representações/79 migrations/126 audits; 050000 ausente, flag false e código/config/bundle/chave/dados originais. Dados mestres legítimos/vínculos continuam necessários para a gravação real do país, mas não para DDL. Faltam a apreciação explícita do delta e o levantamento da suspensão antes de disponibilizar. Ofertas, competências modulares, SLA, workflow/documentos/cartografia/acessibilidade/dispositivos reais mantêm os critérios próprios. A/B e C37 preservados, sem repetir os ensaios completos.
[Relatório e limitações](../../../../outputs/investmoz-portal-stability-20261011/relatorio-estabilizacao.md) · [Causas/reprodução](../../../../outputs/investmoz-portal-stability-20261011/casos-reproducao.md) · [Consumidores/rotas/perfis](../../../../outputs/investmoz-portal-stability-20261011/cobertura-consumidores.md) · [Manifesto fixo](../../../../outputs/investmoz-portal-stability-20261011/manifesto-candidata.json) · [Procedimento único e reversão](../../../../outputs/investmoz-portal-stability-20261011/procedimento-unico.md).
Mesma matriz: 3393 requisitos/3393 linhas/6845 referências, 7 concluídos e 3386 abertos (3234 parciais, 145 não implementados, 2 implementados mas não ativados, 5 decisões concretas). Somente AUD-COUNTRY-02 e AUD-OPS-01 receberam critérios novos; restantes células/referências preservadas. Os blocos abaixo são histórico datado.
<!-- portal-stability-20261011:end -->
<!-- country02-active-https-attempt-20261011:begin -->
## COUNTRY02 — autorização registada, ativação por retomar
Entrega 13644ed74a48/código 162daff6ce08 e HTTPS explicitamente autorizados. Backup/restauro/linhas/sequências/envelopes revalidados READ ONLY 08:03:24UTC. Staging das 3 fontes/157 ativos/config HTTPS com flag=false, sintaxe Apache aprovada; não se obteve certificado ativo/prévia autenticada. Apache Laragon não é serviço Windows; reinício por serviço falhou e terminação de processos foi bloqueada por revisão automática. Confiança CA Windows e reinício normal Laragon dependem de intervenção local. Auxiliar inicial por ps1 foi recusado pela política; cmdlet nativo aguarda aviso, sem mudança de ExecutionPolicy.
Reversão pré-instalação executada: fonte 36/manifesto 753/.env/vhost/readiness repostos; às 08:13:55UTC,288 tabelas/13 contas/0 organizações/0 representações/79 migrations/126 audits/6 sessões e mesmos hashes; zero DDL/050000/auditoria COUNTRY02, flags=false e APP_KEY/cipher/MFA preservados. Não reiniciar Apache agora; coordenar depois de reaplicar TLS após confirmação da CA. Autorização mantida: não pedir novamente aprovação do mesmo âmbito. Ativo sem dados mestres/vínculos reais: gravação ativa do país não é demonstrada ; QA de gravação mantida. A/B,C37 e 25 UUID preservados.
[Resultado, provas, URL exato e critérios para retomar](../../../../outputs/investmoz-country02-https-activation-20261011/resultado.md). O pacote 136/162 continua imutável. Nenhum outro pacote ou nova entidade. AUD-COUNTRY-02 mantém **implementado mas não ativado**, AUD-OPS-01 mantém parcial. Os textos anteriores permanecem como histórico.
<!-- country02-active-https-attempt-20261011:end -->
<!-- country-https-qa-20261011:begin -->
## COUNTRY02 HTTPS — candidata preparada e QA demonstrada
**COUNTRY02 demonstrado em QA HTTPS**, entrega `13644ed74a48`, código `162daff6ce08`, compilação `d172b5c4f1a1`. Chromium em **https://country02-qa.test:18443**, certificado reconhecido após confirmação manual da CA temporária no CurrentUser/Root, sem bypass. TLS1.3/contexto seguro/WebCrypto, cookies próprios Secure/HttpOnly/Lax/host-only, regeneração dos IDs de sessão comprovada por hashes sanitizados e 47 recursos conferidos sem conteúdo misto.
Login/MFA → prévia/confirmar/instalar 050000 → perfil → guardar PT/F5 → atualizar MZ/versão3 → voltar/avançar cifrados → logout401 e Back com formulário de login sem master → nova sessão/MFA recupera MZ/fonte. C111 fechado no âmbito QA HTTPS com cifragem/private,no-store preservados. C112 encontrado e corrigido: resposta Fortify limpa a chave do histórico depois da invalidação da sessão. C110 HTTP/UUID servidor e aceites A/B/C37 preservados. As correções estão preparadas em cópia isolada, não no Apache ativo.
SQL confirma 288 tabelas, duas colunas nullable, uma instalação/auditoria e duas edições do país com snapshots cifrados null→PT→MZ recuperáveis. Fixtures org/vínculo/conta só QA e depois da instalação. Nenhum 030/040/190. Flag off/on conserva país/versão/proveniência. Backup/restauro **2026-10-11T07:44:43+00:00**, ativo READ ONLY para clone QA:288 tabelas/31 sequências/282 ficheiros/zero ausentes/2 envelopes MFA originais recuperados. Correspondência de código ativo 36 e candidata nova 162 explicitada; validade<=24h revalidada antes da ativação.
**Pronto para revisão e autorização, não ativado.** Proposta concreta de HTTPS **https://portal-investidor.test** com certificado/chain/SAN/chave separados da QA, ainda não confiados ou instalados no ativo; vhost Apache e APP_URL/cookie/HTTPS e reversão preparados. `httpd -t` passou somente em cópia privada, sem reload. O âmbito proposto inclui as três fontes corrigidas, bundle, HTTPS, somente 050000 e flag COUNTRY02. Nenhuma organização/representação real é inventada; escrita real exige cadastro/vínculo legítimos. Stop antes do POST se backup/TLS/hash/alvo/prévia divergir. Não inclui 030/040/190, cartografia, perfis, ofertas, SLA ou 25 UUID.
25 chamadas UUID em 14 componentes permanecem no backlog por rota/perfil/ação e evidência: inferências de HTTP distinguidas de falhas reproduzidas. Prioridade para simulador público/autoguardar/calcular e 040000 ao confirmar; outros ramos só se instalados/habilitados/autorizados. [Backlog legível](../../../../outputs/investmoz-country02-https-20261011/uuid-backlog.md). [Revisão, critérios, pacote, certificados públicos e reversão](../../../../outputs/investmoz-country02-https-20261011/REVER-CANDIDATA.md).
Na mesma matriz, somente AUD-COUNTRY-02 passa de com falha para implementado mas não ativado; AUD-OPS-01 continua parcial. Os 3393 requisitos/6845 referências continuam com 7 encerrados e 3386 abertos, sem ampliação indevida dos fechos. Os textos anteriores permanecem como histórico.
<!-- country-https-qa-20261011:end -->
<!-- country-c110-http-qa-20261011:begin -->
## C110 corrigido em QA; C111 e ativação pendentes
**C110 corrigido e demonstrado exclusivamente em QA.** Código `54fb610eb9da`, entrega `d28d687c321b`, manifesto de produção `d172b5c4f1a1`. O servidor emite a chave da operação e preserva-a na sessão após erro, F5 e repetição, vinculada a gestor, alvo, migração e revisão. Apenas dois ficheiros de aplicação mudaram na cópia preparada; os ficheiros servidos pelo Apache e a base ativa não foram alterados.
Chromium em **http://country02-qa.test:18103**, sem atribuir confiança artificial à origem: `isSecureContext=false`, `randomUUID=undefined`, `subtle=undefined`. Prévia, confirmação, erro409 por prova expirada, recuperação da mesma chave, instalação a frio, replay e recusa de conteúdo alterado demonstrados. SQL confirma uma auditoria, uma migration, duas colunas opcionais e zero tabelas, organizações ou vínculos criados pela instalação. 38 ativos conferidos e 390 px sem extravasamento. Consultas aos formulários partilhados 020000/030000 fizeram apenas GET. Nenhum ensaio A/B/C37 foi repetido.
Inventário: 30 dependências dos consumidores COUNTRY02, uma chamada UUID anterior removida e zero remanescentes. 25 ocorrências noutros percursos foram identificadas, sem ativação ou correção por arrasto. Backup/restauro de **2026-10-11T07:18:12+00:00**, alvo ativo READ ONLY para clone QA:288 tabelas, 31 sequências, 282 itens, zero ausentes e dois envelopes MFA originais recuperados. Os 282 itens incluem os ativos conservados após reversão; as 295 tabelas históricas eram de outro alvo QA com 030000/040000.
**C111 é condição de paragem da ativação:** `/investidor/profile` lança `Unable to encrypt history` no hostname HTTP. A cifragem do histórico e `private,no-store` permanecem habilitados. É necessário demonstrar transporte seguro na origem final ou solução equivalente que não retenha dados privados no histórico. Não se desabilitou a proteção nem se mudou HTTPS, certificados ou trust store. A documentação oficial [Inertia](https://inertiajs.com/docs/v2/security/history-encryption) confirma a dependência de `crypto.subtle` em contexto seguro.
COUNTRY02 continua não ativo e a nova candidata tem `activation_ready=false`. A autorização registada nomeava c68ceef9d4a3/36f7722ce5a5 e não foi usada para aplicar d28d687c321b/54fb610eb9da. Resolver C111, fixar/rever a revisão correspondente e revalidar o backup/alvo/prévia antes de qualquer nova aplicação. A/B e C37 preservados; ofertas, perfis e SLA permanecem separados.
[Pacote, critérios e evidências](../../../../outputs/investmoz-country02-c110-20261011/REVER-CANDIDATA.md). Os blocos anteriores continuam como histórico de versões. Somente AUD-COUNTRY-02 e AUD-OPS-01 foram complementados; estados globais e restantes células preservados.
<!-- country-c110-http-qa-20261011:end -->
<!-- country-activation-20261011:begin -->
## COUNTRY02 autorizado — execução interrompida por C110
**Ativação COUNTRY02 interrompida antes do POST.** A autorização exclusiva da entrega `c68ceef9d4a3`, código `36f7722ce5a5`, foi recebida. Backup/restauro de 06:09:56 UTC revalidado às 06:50 UTC: alvo `investemoz:5432`, chave estável, código, bundle e dados das 288 tabelas correspondentes. As 22 fontes, 157 ficheiros do bundle e 187 entradas do ZIP foram conferidas.
**C110:** no endereço ativo HTTP `portal-investidor.test`, Chromium informa `isSecureContext=false` e `crypto.randomUUID` indisponível. O componente compilado do instalador chama esse método ao inicializar e lança `TypeError: crypto.randomUUID is not a function`. O ensaio anterior em HTTP `127.0.0.1` não cobria esta diferença. A prova atual é de inicialização isolada do componente com propriedades de ensaio. A prévia autenticada não foi obtida e não houve POST nem login de gestor.
O bundle foi disponibilizado com a flag desabilitada e depois revertido atomicamente para o manifesto anterior `75352185c2a85`, conservando os ativos antigos e novos. Leitura final de 06:53:28 UTC: 050000 e as duas colunas continuam ausentes, nenhum evento de instalação, zero alterações de dados de negócio, contas ou representações. Mantêm-se 13 utilizadores, zero organizações/vínculos, 79 migrations e 126 eventos de auditoria. Apenas duas sessões de visita foram criadas. Todas as flags permanecem desabilitadas.
**Próxima ação:** corrigir a inicialização de UUID em QA com alternativa criptográfica `getRandomValues` ou UUID do servidor, mantendo MFA, CSRF e idempotência. Ensaiar num hostname HTTP equivalente que não seja loopback, recompilar e fixar uma nova revisão. Revalidar a prova e a prévia autenticada dessa entrega antes de nova aplicação autorizada. A autorização recebida para hashes exatos não abrange uma entrega substituta. Dados reais de organizações e representação permanecem fora desta operação.
Só os requisitos AUD-COUNTRY-02 e AUD-OPS-01 receberam novas evidências. COUNTRY02 passou de implementado mas não ativado para com falha de compatibilidade C110. A matriz mantém 3.393 requisitos e linhas, 6.845 ocorrências de origem e 3.386 requisitos abertos: 3.234 parciais, 145 não implementados, 5 dependentes de decisão, 1 implementado mas não ativado, 1 com falha e 7 concluídos. A/B e C37 continuam encerrados no âmbito QA aceito; nenhum outro pacote foi ativado.
Este resultado prevalece sobre os retratos anteriores, conservados como histórico. [Relatório e recibos sanitizados](../../../../outputs/investmoz-country02-activation-20261011/resultado.md).
<!-- country-activation-20261011:end -->
<!-- country-production-final-20261011:begin -->
## Plano final delimitado COUNTRY02 — 2026-10-11T06:21:38.798206+00:00
**Pacote COUNTRY02 pronto para revisão, sem ativação autorizada.** Código `36f7722ce5a51abc6a246116afcab22ebc8167fa3d06e493920ad18c7afbfca8` substitui `84a0e4a33dbf`; entrega `c68ceef9d4a3bc10da7bf269c1261a7b1edece3c1e114d6fef8cc60ca9f4403c`; produção `de6d702f4e2cd5e618cc822da84a041f4519af4a76f9dcb288fafa88819fabe0`. A/B e C37 QA18 mantêm os fechos aceites, sem novos ensaios dessas contas/cenários. Zero escritas na base ativa. Este é o retrato vigente destes critérios; as secções datadas seguintes conservam os estados anteriores como histórico.
A alteração necessária foi C109: o listener Fortify só registava MFA na sessão quando040000 estava disponível, enquanto o instalador exigia esse registo. Agora só um challenge válido regista a prova recente, independentemente do módulo opcional. Um código inválido mantém a sessão não autenticada; logout elimina a prova. `AppServiceProvider.php` passou a integrar o fingerprint, de21para22ficheiros; não se alteraram papéis nem representações.
Compilação de produção em cópia isolada com configuraçãoVite original, rotasWayfinder geradas naQAguardada, URLs `/build/` e título público `VITE_APP_NAME=InvestMoz`; `APP_NAME=Laravel` e `.env` ativos preservados.157ativos fixados;39carregados noChromium conferidos byte/hash, sem errosJS; país salvo/recuperado em nova sessão e390px sem extravasamento. Ensaio final usa sessões`database`, como o ativo; cookies/alvo/cache/runtimeQA ficam isolados. Plataforma ativa inspecionada semHTTP: ApachecarregaPHP8.5.11 ePDOpgSQL/mbstring/openssl/zip, compatível com o lock mínimo8.4.1. Não se aplicou configuração nem se reiniciou o servidor ativo.
A função SQL do serviço ativo foi inspecionada em transação READ ONLY: permissões de alteração de organizations, ledger, auditoria e leituras necessárias disponíveis; nenhum grant foi atribuído. O dump conserva ownership/ACL; o restauro QA usa deliberadamente --no-owner --no-privileges. Este ensaio prova dados/estrutura/runtime, sem afirmar uma alteração ou recuperação de privilégios ativos. A captura incluída pertence ao ensaio final com sessões database; o recibo anterior com sessões file conserva bytes/hash e prova a instalação visual a frio pela sequência UI/rede/auditoria, não pela captura atual.
Backup `2026-10-11T06:09:56+00:00`: origem `investemoz:5432` READONLY; restauro `country_candidate_20261011_060946_test:55441`; **288tabelas,31sequências,154ficheiros/ativos,0ausentes,2envelopesMFAoriginais recuperados**. Comparação de tabelas/valores e sequências a frio; hashes/extracção dos arquivos; chave efetiva preservada. Bundle e revisão ligados à prova. Clone do ensaio visual e clone final têm o mesmo snapshot de origem; não se confundem fixtures posteriores com dados ativos. Os157ativos do novo bundle são outra contagem, não os154itens do backup.
QA295 tem exatamente sete tabelas adicionais:030000 cria`opportunity_documents`,`opportunity_images`,`opportunity_location_drafts`;040000 cria`portal_profile_requests`,`portal_role_assignments`,`portal_security_approvals`,`portal_superuser_pair`. Nenhuma tabela doativo em falta.190000/050000 acrescentam colunas, não explicam essas sete tabelas. As295tabelas/103ficheiros históricos eramQA com fixtures; o backup atual inclui originais+runtime+bundle anterior, com âmbito diferente.
Ativo:0organizações/0memberships;2gestores existentes verificados comMFA configurado, nenhum escolhido. **Não é preciso inventar dados reais para instalar ou habilitar a extensão.** Reutilização do mestre requer uma organização legítima comUUID/nome/tipo/origem e membership autorizado para o utilizador; roleadmin/manager/officer pode editar,viewer consultar. PaísISO e referência podem ser preenchidos depois peloPUTautorizado; a cópia para empresa é explícita e preserva versões anteriores. Empresa privada declarada não cria organização/vínculo. Não foi encontradoCRUDgeral de criação de organizações/atribuição de representação: esse onboarding é uma frente posterior autorizada e não uma funcionalidade afirmada como existente. Sem dados legítimos, a interface apresenta o estado vazio controlado já ensaiado.
Provas locais e pacote de revisão: [manifesto](../../../../outputs/investmoz-country02-candidate-20261011/manifesto-candidata.json), [guia e critérios](../../../../outputs/investmoz-country02-candidate-20261011/REVER-CANDIDATA.md), [matriz existente](matriz-requisitos.csv). Estes caminhos são relativos ao repositório; os recibos sanitizados estão também no pacote de revisão.
### Ação autenticada e efeitos — somente após autorização
1. Rever e autorizar a entrega `c68ceef9d4a3bc10da7bf269c1261a7b1edece3c1e114d6fef8cc60ca9f4403c`. Revalidar código22fontes, produção157ativos, alvo`investemoz:5432`, schema/flags/runtime e prova de backup com idade máxima24h. Se mudar qualquer componente/alvo ou houver divergência, renovar a prova antes de aplicar; não substituir readiness por um testeunitário.
2. Com a flag COUNTRY02 ainda desabilitada, verificar e acrescentar os novos ativos imutáveis em`public/build`sem remover ativos anteriores. Colisão de nome exige hash igual; nunca sobrescrever bytes diferentes. Preparar`manifest.json.new`e conferirSHA`de6d702f4e2cd5e618cc822da84a041f4519af4a76f9dcb288fafa88819fabe0`; substituir`manifest.json`por operação atómica com cópia do anterior. NoWindowsusar`System.IO.File.Replace`em ficheiros no mesmo volume, com caminhos previamente verificados dentro do workspace. Não extrair o pacote inteiro sobre alterações locais. Manter ativos antigos para páginas abertas e reversão.
3. Gestor existente entra com email verificado eMFA concluído nos últimos15min. URL configurado do ativo: **`http://portal-investidor.test/management/opportunity-resources-install/organization-country`**. Não foi feito loginHTTPativo nesta preparação. GETapresenta prévia/planohash/dependências e contagens;installedfalse,consistenttrue,readytrue é preparação, não instalação.
4. FormulárioPOSTna mesma rota, protegido por sessão/CSRF: `hash` da prévia atual, `confirm=true`, novo`idempotency_key`UUID, `reason`20–1000caracteres (revisão/motivo). Aplicar **apenas**`2026_10_10_050000_extend_organization_country`seausente, via mecanismo autenticado existente. Não usar migrateglobal. Esperado:installedtrue,changedtrue,new_columns2,new_tables0,new_organizations0,flags_changedfalse;1registro de migration e auditoria da operação. Repetir o mesmoUUID devolve o recibo anterior semDDL/auditoria duplicados;novoUUID após instalação é consulta idempotente comchangedfalse e auditoria própria.
5. Disponibilizar apenas`PORTAL_ORGANIZATION_COUNTRY_ENABLED=true`; preservar todas as outras flagsfalse, chave/cipher, consentimentos, classificações, URLs e dados. A configuração ativa não está em cache; não gerar cache global por arrasto. Atualizar somente o runtime alvo e confirmar a flag efetiva.
6. Confirmar manifesto/código/schema/flag e perfil mestre disponível; a conta sem representação deve manter estado vazio controlado. Nenhuma conta/org/vínculoQA entra no ativo;0alterações de privilégios. Conferir preservação dos valores anteriores/auditoria. Dados reais só pelo fluxo/ação posteriormente autorizados. O fechoQA não é uma demonstração doativo.
**Sucesso objetivo:** hashes da candidata correspondentes,050000ledger+2colunascoerentes,0tabelas/contas/org/memberships novos por instalação, auditreceipt/UUIDcorretos, flagcountrytrue e outrasflagsinalteradas, assets200 com hashes fixados, interface do perfil sem500/422 inesperado, vazio controlado quando não há representação; histórico/submissões originais preservados. Aprovação não implica divulgação, cálculo,CRMexterno ou decisão externa.
**Reversão:** em caso de erro de compatibilidade, autorização indevida, perda/mistura de dados, manifesto divergente ou falha do consumidor, pôr somente a flagcountryfalse e restaurar atomicamente o manifesto anteriorSHA`75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94`; manter ativos antigos/novos,2colunas,ledger,valores/proveniência/histórico,auditoria e chave. Não fazer down/drop/reset/key:generate nem retirar privilégios. Recuperação de dados, se realmente necessária, usa o restauro isolado verificado e autorização específica; não sobrescrever alterações legítimas posteriores ao snapshot.
**Fora da candidata:**030000→040000→2026_10_09_190000 continua a sequência das outras frentes, sem repetição nem ativação por arrasto. Ofertas, competências funcionais modulares eSLA/calendário/nomeações continuam decisões separadas;workflow/Response integral/cartografia/derivadas/acessibilidade integral/dispositivos reais mantêm os critérios restantes do backlog. MercadoFinanceiro continua privado.
<!-- country-production-final-20261011:end -->
<!-- qa-revision-20261011:begin -->
## Candidata delimitada COUNTRY02 e sequência reconciliada — 11/10/2026
**Somente preparação; ativação fora da autorização.** A/B e C37 conservam fecho. CAND-COUNTRY02-20261011 fixa21fontes com hash `84a0e4a33dbfa8d727a190b2cd6280c23751ec15d5b1c2d436b415ff7ed7528e` e manifestoQA `b75b06da1f6790eed063b7a98ffe0e7f6a22099e564f8e902e9698dbd7503840`. O bundle ativo não foi alterado. Manifesto sanitizado em `outputs/investmoz-country02-candidate-20261011/manifesto-candidata.json`; dumps,originais,configuração,chave e credenciais ficam exclusivamente privados.
**Inclui:** país de constituição no mestreorganizations existente com fonte/versão/auditoria; reutilização explícita em empresas privadas/submissões sem reescrever valores históricos; memberships/policies existentes; prévia/instalação autenticada050000 e reversão por flag. **Exclui:** workflow/Response/módulos/ofertas/SLA,importação/publicação cartográfica,expansão/divulgação do legado,percurso190000,QAfixtures/contas/configuração/dados,acessibilidade integral e dispositivos reais. Essas frentes continuam na matriz e não bloqueiam o país quando as suas dependências próprias estiverem resolvidas.
### Aceitação objetiva da candidata
1. Os21hashes,composer/configuração estável e manifesto preparado correspondem à revisão fixada. Bundle de produção compilado em diretório separado, com caminhos de serviço e hashes conferidos; **ainda pendente**, não trocar o build ativo durante preparação.
2. Prévia GET `/management/opportunity-resources-install/organization-country` por gestor autorizado existente/verificado apresenta o alvo certo,050000ausente ou instalado,dependências/schema/ledger consistentes,hash esperado e prova de restauro fresca até24h. Não gerar chave nem desativarMFA.
3. POST no mesmoURL exige sessãoMFA e versão/chaveidempotência: instala apenas050000quando ausente; acrescenta2colunas/0tabelas/0contas/0organizações,regista auditoria,recusa alvo/hash/desfasamento e repetição não duplicaDDL/dados. Clone correspondente demonstrou a política autenticada; fixtureMFA do clone não é ensaio visual novo.
4. Com organização/representação autorizadas no cadastro existente: UI→PUTmestre→fonte/versão/audit→nova sessão/profile→cópia explícita emempresa/submissão→recuperação. Históricos conservados; viewer/estranho/revogação/Auditor com papéis acumulados sem edição. Provas QA já ligadas; não copiarfixture ao ativo. **Ativo contém0organizações**, logo a origem e habilitação dos dados reais permanecem dependência concreta.
5. O módulo mantém residência/constituição/origem separadas. Desativar `organization_country_enabled` retira disponibilização mas mantém2colunas,metadata,histórico e cópias anteriores. Clone comprovou consumidorprofile sem030000/040000/190000.
6. Falhas de hash,alvo,schema/ledger,MFA/permissão,duplicação,perda/regravação de histórico ou consumidor sem dados recuperáveis suspendem o corte. Sucesso por API ou `ready=true` não substitui provas nem aprovação de ativação.
### Ordem exata preparada, ainda não executada no ativo
1. Preparar/rever bundle de produção fora do diretório servido; comparar manifesto,fixar caminhos e plano de troca. Confirmar esta candidata e excluir as flags das funcionalidades parciais.
2. Conferir base/configuração efetiva somenteporleitura,instalações/colunas,organizations/memberships e elegibilidade do ator. Se mudou alvo/hash/source/runtime/prova>24h, renovar snapshot/restauro antes de aplicar; não usar backup de outra revisão.
3. Obter autorização separada para a ação ativa e para os dados/representações reais necessários. Não designar pessoas nem retirar privilégios automaticamente.
4. Ator autenticado comMFA abre a prévia,revê correspondência/impacto e aplica **apenas050000seausente**. Não executar `migrate`global nem030000/040000/190000por arrasto. Repetição consultada como instalada, sem reinstalar.
5. Habilitar só a flag do país, com configuração/cache efetivos consistentes; disponibilizar bundle fixado; manter flags dos módulos parciais no estado anterior. Cadastro real/representações pelo mecanismo existente e fontes autorizadas; sem cópia deQA.
6. Conferir consumo do mestre/cópia/histórico/permissões e auditoria no ambiente disponibilizado. Qualquer falha prevista aciona reversão abaixo. A autorização atual não executa este passo ativo.
**Sequência das outras frentes preservada:**030000(recursos)→040000(perfis/bootstrap)→2026_10_09_190000(percurso).190000continua necessária,ausente no ativo,não substituída;COUNTRY02não a exige.030/040/190 têm instalação/readiness próprios e fingerprints devem incorporar as novas fontes; provas antigas não são automaticamente atuais. Importação cartográfica autenticada e publicação de camadas ficam depois das dependências correspondentes,como ações separadas,com contagens da prévia. Não repetir instalações já presentes nem ativar cálculos por importação/publicação.
### Restauro correspondente e reversão
Backup renovado `2026-10-11T00:37:08+00:00` doativoREADONLY; clone `country_candidate_20261011_003659_test:55441`;288tabelas comparadas linha/hash,154ficheiros/ativos restaurados e0ausentes; chave/configuração efetiva recuperada permitiu desencriptar2MFAoriginais sem revelarsegredos. Compatibilidadecold050000/consumidorprofile/repetição/reversãoflag confirmadas no cloneQA; originais privados intactos. DumpSHA `86244e6b3712c24a65d99880d028b37c109eac1ca66f5719f0a950030ce04a1f`; archiveSHA `4eec3dfb7277144f07846378dc7ea81920f1ded004b3a34aea36792cc990758d`. Hashes identificam o arquivo privado, não disponibilizam os seus conteúdos.
Reversão normal: desabilitar flag país,restabelecer configuração/cache correspondente e bundle anterior verificado; conservar2colunas,país/histórico/proveniência/cópias/audit_events. **Não executar down/drop/limpeza nemkey:generate.** Recuperação de dados se necessária requer plano específico/autorização ativa e ensaio prévio no clone; snapshot comprovado não autoriza sobrescrever alterações legítimas posteriores. Preservar chave/configuração e autenticação/MFA. O plano reversível mantém as instalações aditivas e os dados disponíveis para correção posterior.
Estado: código preparado+QA demonstrada no escopo incluído+backup/restauro correspondente; **produçãoassetspendente/ativação não autorizada/não instalada no ativo**.
<!-- qa-revision-20261011:end -->
<!-- qa-next-consumers-activation-20261010:begin -->
## Incremento delimitado e extensão050000 — 2026-10-10T22:29:22.300559+00:00
**Revisão QA do incremento`fc61d9621f510d760a77999c0b4eaab12b9a5619e972326a796f979d25b79d55`; não é autorização/candidata global de ativação.** `next-final-scope-qa.json` liga fontes/build/recibos/SQL. Leitura ativa21:23:40UTC READ ONLY/ROLLBACK:030000/040000/2026_10_09_190000/050000 ausentes; organizações=0, colunas país ausentes; manifesto ativo intacto. **Backup/restauro ativo não foi renovado.** Não transportar fixtures, contas, designações ou grants QA.
| Ordem / componente | Dependências e efeito | Contagem prevista / reversão |
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 Código/build compatíveis | Fixar candidata global, completar critérios restantesP0/P1, conferir configurações/flags, schema ativo READ ONLY e fingerprints atuais. Consumidor do mestre devolve estado controlado se050000 ausente; não presume organizações preenchidas. | Código/build; conservar revisão anterior e alterações locais. Reverter hunks/bundle conhecido, sem reset ou apagar dados/histórico. |
| 2 Backup/restauro/compatibilidade | Dump ativo e acervo privado/originais/permissões/chave estável, restauro em clone QA fresco ligado à candidata; verificar hash/extração/URLs/perfis/reversão. Provas históricas têm data/fingerprint próprio, insuficientes para este código. | Contagens reais devem sair da prévia do clone/ativo. Não declarar ready a partir de teste unitário com readiness simulado. |
| 3 030000 → 040000 → **2026_10_09_190000_prepare_investor_path** | Recursos privados→perfis/políticas→extensão do percurso. 09/190000 continua necessária e ausente; não substituída pelo Balcão07/190000. Prévia/aplicação autenticadas, somente ausentes após dependências/provas atuais. | QA já instalada: não repetir. Contagens ativas serão fixadas na prévia correspondente; não escolher os dois titulares reais nem remover privilégios ativos. Preservar cinco fases/19etapas e entidades/IDs/URLs. |
| 4 **2026_10_10_050000_extend_organization_country** | Extensão independente do mestre organizations; depende de organizations/memberships/audit_events e código compatível. Auth `/management/opportunity-resources-install/organization-country`, titular autorizado/MFA para aplicar, hash/prova atual/UUID/reason, lock/idempotência/auditoria; incoerêncialedger/schema409. Não requer nem substitui190000, não muda flags/cálculos/publicação. | Ativo: **2colunas opcionais,0tabelas,0organizações,0contas/grants**. QA já instalada; no repetirDDL. Não apagar colunas/histórico no down. Desabilitar/reverter consumidor preserva os dados; restauro verificado somente no clone e depois numa ação autorizada se necessário. |
| 5 Dados/representações do mestre | Ativo organizations=0: usar acervo/cadastros/importação autorizada e memberships existentes. País registado com fonte/versionamento; cópia explícita, anteriores preservados. Fonte oficial aceite não pede recertificação; declaração do representante não afirma decisão externa. | Não inventar dados/vínculos nem ligar por nome. Prévia futura determina organizações/associações efetivas. Cadastros ausentes não são preenchidos pela migration. |
| 6 Importação cartográfica / divulgação | Prévia/correspondências/hash/idempotência/auditoria/reversão por lote, preservando408associações e173pendentes; Mandie/Guro ambíguo. Publicar camadas/artigos/oportunidades é ação separada. Direitos externos/documentos privados continuam separados da aprovação interna/release restrito. | Nenhuma importação deste lote. Não atribuir limite do pai à localidade/parcelas. Scans realClamD comprovam só ficheiros/derivadas identificados; outras operações mantêm pendência específica. |
| 7 Disponibilização do percurso | Após instalações/dados/provas por consumidor, manter acesso direto, cinco fases19etapas e contextos retornados ao dossier. C99/C101 usam tasks existentes; C102 não cria outro contrato. | Código; tarefas antigas, razões completas, publicações/cópias anteriores preservadas. A/B/C37QA fechados não certificam automaticamente o ativo. |
Instalador050000: ensaio isolado a frio/idempotência/auditoria/MFA/dependências/recuperação de incoerência testa políticas e mecanismo. **Não é ensaio de restauro do ativo.** `ready=true` indica somente preparação correspondente; instalado e resultado funcional continuam critérios diferentes. Bootstrap/substituição/recuperação dos titulares040000 conservam provas QA e exigem designação real para habilitação ativa; nada foi alterado no ativo.
Candidata global fica pendente dos critérios do [backlog](backlog.md) e das verificações do clone. Autorização atual cobre somente implementação/testes QA. Não regenerar chaves, desativar MFA, remover cadastros/relações ou mudar valores históricos para simular sucesso.
<!-- qa-next-consumers-activation-20261010:end -->
<!-- qa-consumers-activation-20261010:begin -->
## C91–C96 — revisão do incremento, sem ativação — 2026-10-10T22:50:21.145493+02:00
**Código e build QA preparados; nove recibos visuais, leitura SQL e regressões ligadas em `consumer-final-scope-qa.json`. Candidata global ainda não fixada.** Zero migrations/tabelas/contas novas neste lote; QA já tem os recursos necessários e não recebeu reinstalação. Novas fixtures QA não entram numa futura instalação ativa. A/B e C37 permanecem aceites no seu âmbito, sem repetição.
| Alteração | Efeito | Instalação / reversão |
| --------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| C91 controlador/componente de impressão | País/origem recuperados independentemente e caracteres reparados | Código, sem migration; revertê-lo não altera o pedido ou os originais |
| C92 layout/CSS de impressão | PDF sem menus, com quebra de secções; restantes páginas mantêm layout | Código/build; conservar ficheiros e hashes anteriores como histórico |
| C93 adaptador canónico | Campos ambientais passam a reutilizar definição existente no editor e validação | Contrato já existente; sem ativar cálculo ou aprovação externa. A versão nova de oportunidade52 é apenas QA |
| C94 recursos em leitura | Separadores consultáveis por quem tem autorização, mutações continuam bloqueadas | Código/build, políticas do servidor preservadas; não publica ficheiros |
| C95/C96 rótulos | Nome acessível próprio do sector e descrição legível no corredor | Código/build, sem alteração de significado ou dados |
Sequência futura, ainda sem execução ativa:
1. Completar os critérios restantes por consumidor/perfil; fixar revisão candidata global e hashes de fontes, builds/configuração e recibos. O snapshot deste incremento não substitui essa candidata global.
2. Consultar o ativo por leitura para instalação/schema/flags/configurações reais. O manifesto ativo permanece `75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94`. Não transformar o retrato histórico de instalações em nova consulta nem em autorização de escrita.
3. Renovar backup e demonstrar restauro num clone QA fresco associado ao ativo e à candidata: base, ficheiros privados/originais, hashes, permissões, chave/configuração estável, compatibilidade e reversão. Backup/restauro anteriormente reportado conserva data e âmbito; não foi renovado neste lote.
4. Disponibilizar código/build compatíveis com flags controladas. Prévia/aplicação autenticadas **030000→040000→2026_10_09_190000_prepare_investor_path**, apenas instalações ausentes e após dependências. Recursos versionados→perfis/políticas→extensão do percurso; 09/190000 não é substituída por Balcão07/190000. Não repetir QA nem gerar identidades/grants/titulares reais. Contagens finais dependem da prévia da base candidata, não de `ready=true`.
5. Importação cartográfica separada: prévia, correspondências inequívocas, preservação de408 associações, hash, idempotência, auditoria e reversão por lote.173 pendentes e Mandie/Guro ambíguo não foram resolvidos pelo ensaio visual. Publicação de camadas/conteúdos/catálogo é outra ação; uma ficha publicada não divulga originais restritos. Scans ClamAV deste lote provam apenas os ficheiros/derivadas identificados; outros scans/operações mantêm pendência específica.
6. Disponibilizar percurso/consumidores após verificações correspondentes. Ação ativa e designação/recuperação dos dois titulares continuam fora da autorização QA atual.
Reversão do incremento por hunks e bundle de revisão conhecida, preservando alterações locais, revisões, protocolos, originais, consentimentos, recursos e auditoria. Não fazer reset do repositório, apagar fixtures/histórico para simular sucesso, regenerar a chave ou desfazer MFA. Compatibilidade/reversão global devem ser demonstradas no clone correspondente antes de corte futuro.
<!-- qa-consumers-activation-20261010:end -->
<!-- qa-ab-countries-activation-20261010:begin -->
## Lote A/B e países C88–C90 — preparação, não ativação
QA demonstrada: A/B internos, países/origem por quatro formulários, recuperação de perfil/negócio/fundiário, filtros/estatística positiva e página de entrada. **0migrations,0tabelas novas,0contas novas neste lote.** Dados QA: reutilização do pedidoA existente com revisão/auditoria, quatro intakes países e um intake C90; não transferir fixtures para ativo. Resultados/drafts/tarefas A/B e originais preservados.
1. Fixar revisão candidata global depois dos critérios restantes por consumidor/perfil. Registar hashes das fontes/builds e dos recibos associados; fingerprint040 atual `27eef96c6e914039258c2c54cc16aca8324e0d3f77653720d9eddd7e79c57a2c` é de âmbito próprio e não substitui fingerprint/revisão global do percurso.
2. Consultar ativo somente por leitura para diferenças reais de schema/flags/config/dados e instalações ausentes. O manifesto ativo `75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94` continua intacto. Provas de backup/restauro anteriores conservam data/âmbito; não habilitam automaticamente a revisão nova.
3. Renovar backup/restauro ligado à candidata e ao ativo lido, testar extração/restauro dos ficheiros e permissões, compatibilidade e aplicação/reversão num cloneQA fresco. Só depois preparar a ação autenticada ativa, ainda fora da autorização.
4. Instalações necessárias continuam **recursos030000→perfis040000→percurso2026_10_09_190000**; não confundir190000 com Balcão07/190000. QA já instalada, não repetir. Antes do corte, prévias determinam contagens ausentes; não transportar identidades sintéticas nem escolher titulares reais. Bootstrap/designações continuam operações próprias.
5. Disponibilizar correções C88–C90 por código/build/config da candidata. Importação cartográfica por prévia/correspondências/hash/aplicação idempotente é outra ação, com173 pendências anteriores e ambiguidade Mandie/Guro preservadas; publicação das camadas/conteúdos e catálogo público é outra ação. `ready=true` indica preparação dentro do mecanismo, não instalação ou conclusão visual.
Compatibilidade/reversão do lote: usa description/source_page/eventos/revisions existentes, sem SQL de migração. Reverter somente os hunks/build deste incremento para revisão conhecida, preservando dados novos, revisões e auditoria; não fazer reset do repositório com alterações locais. Não reescrever/regredir descrições ou origens históricas. O texto reutilizado continua campo canónico; ações futuras devem reenviar versão atual. Reversão funcional global ainda deve ser ensaiada com a candidata/clone, sem declarar concluída por testes unitários. ClamD real anterior permanece separado das derivadas/operações não verificadas. C37 não será repetido para ativação deste lote.
<!-- qa-ab-countries-activation-20261010:end -->
<!-- qa-territory-resource-activation-20261010:begin -->
## C86/C87 — efeito e reversão, sem instalação nova
Recursos030000, perfis040000 e percurso09/190000 continuam instalados emQA; não repetir. Este lote altera validação cruzada país/hierarquia, preenchimento/conferência e legenda do componente existente; **0 migrations,0 tabelas e0 novas contas**. Dois recursos de contexto criados apenas emQA não serão transferidos ao ativo.
@@ -10,6 +404,7 @@ Compatibilidade: schema/IDs/JSON existentes preservados; registos contraditório
<!-- qa-territory-resource-activation-20261010:end -->
<!-- c37-manual-close-20261010:begin -->
## C37 encerrado — autenticação QA18 — 2026-10-10T20:26:29.902032+02:00
**Confirmação manual expressa do responsável registada. C37 está encerrado exclusivamente no âmbito da autenticação QA18.** Login → MFA → redirecionamento → sessão autenticada → atualização → logout → nova sessão/recuperação estão ligados às provas anteriores, sem repetir ensaios nem alterar conta, chave ou MFA. O logout manual de 20:17:15 foi confirmado pelo responsável e pelo rastreio: POST302→/, autenticação e estado persistido vazios.
@@ -21,6 +416,7 @@ O fecho **não encerra A/B, auditoria integral, móvel/acessibilidade integral,
<!-- c37-manual-close-20261010:end -->
<!-- qa-logout-activation-20261010:begin -->
## Incremento C85 — revisão QA, sem ativação
Menus de sessão adicionados ao fingerprint; preparação anterior ligada ao hash antigo preservada. Checagens e backup/restauro QA renovados em 2026-10-10T18:19:43+00:00 para o código atual: 295 tabelas/103 ficheiros em `profile_restore_20261010_181928_test:55441`; nenhum novo recurso, migração, titular ou grant necessário para o botão. Bundle ativo permaneceu com SHA256 `75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94`.
@@ -30,6 +426,7 @@ Correção futura: disponibilizar componente/build compatíveis, após revisão
<!-- qa-logout-activation-20261010:end -->
<!-- qa-visual-activation-20261010:begin -->
## Ativação preparada, sem execução no ativo — 2026-10-10T17:57:54.604301+00:00
Leitura ativa `investemoz:5432`: flags de dashboard/perfis/percurso desligadas; migrações 030000, 040000 e **2026_10_09_190000_prepare_investor_path** ausentes. A extensão 09/190000 continua necessária e não foi substituída pelo Balcão 07/190000. As três já estão instaladas na QA; não repetir.
@@ -49,6 +446,7 @@ Leitura ativa `investemoz:5432`: flags de dashboard/perfis/percurso desligadas;
# Plano consolidado de ativação — lote 3
<!-- qa-c71-sectors-result-20261010:begin -->
## Preparação atual após recuperação e lote setorial — 2026-10-10T16:23:25.695297+00:00
C71 corrigido emQA: comparação integral e backup/restauro renovado 2026-10-10T16: 22:44+00:00 (295 tabelas/103 ficheiros), em `profile_restore_20261010_162229_test:55441`. Esta prova não é backup do ativo nem fixa candidata. C37/QA18,A/B,móvel/acessibilidade/outros consumidores e decisões próprias permanecem pendentes.
@@ -68,6 +466,7 @@ As secções abaixo preservam a evolução anterior; referências aC71aberto ou
<!-- qa-c71-sectors-result-20261010:end -->
<!-- legacy-manual-sectors-20261010:begin -->
## Complemento após confirmação manual — preparação QA
O relato manual do piloto confirma somente a sequência registada em AUD-LEG-03/04/06/07. C37/QA18, A/B, outros perfis, móvel/acessibilidade e cobertura integral permanecem pendentes. C71 continua a impedir novas aplicações QA e a fixação de candidata.
@@ -78,6 +477,7 @@ Sequência global030000 →040000 →09/190000 preservada, sem repetir instalaç
<!-- legacy-manual-sectors-20261010:end -->
<!-- qa-legacy-browser-20261010:begin -->
## Atualização após a prova visual do piloto
O piloto legado foi demonstrado no Chromium QA com Promotor QA21; C37/QA18, CRUD de oportunidades no dashboard e A/B completos continuam pendentes. Não fixar uma revisão candidata global apenas por esta prova. A identificação “InvesteMoz QA” é compilada somente no build QA; não transferir esse rótulo automaticamente para produção.
@@ -90,6 +490,7 @@ C71 é agora pré-condição técnica: recuperar o cluster QA e renovar backup/r
<!-- qa-legacy-browser-20261010:end -->
<!-- qa-legacy-20261010:begin -->
## Histórico — complemento legado anterior ao ensaio Chromium
Preservar **030000→040000→190000**, verificar ledger/schema/dependências no alvo antesde aplicar; não repetir instalações. Leitura editorial usa a biblioteca existente; associação ao dossier exige Balcão+190000. Perfismodulares não são pré-condição da leitura pública.
@@ -100,74 +501,78 @@ Contagem prevista: **1 artigo +1 imagem**, **3 associações**, **0 oportunidade
<!-- qa-legacy-20261010:end -->
<!-- qa-response-20261010:begin -->
**Preparação da futura ativação.** o restauro reportado é QA. Para uma futura ativação, conferir a identidade, schema, dados e configuração efetivos da base ativa para a revisão candidata, capturar hashes/manifesto dessa revisão e provar o seu backup/restauro. As provas QA ou `ready=true` não substituem essa ligação. Sequência 030000 → 040000 → 190000; C37, QA21 e A/B visual pendentes, candidata não fixada.
<!-- qa-response-20261010:end -->
<!-- qa-installation-cartography-20261010:begin -->
## Sequência reconciliada — preparada, não executada no ativo
**030000 → 040000 → 190000** mantém-se. QA já tem as três; **não repetir instalações QA**. No ativo lido READ ONLY, as três extensões estão ausentes; Balcão07/190000 eorientação08/120000 estão instalados. A extensão **09/190000 não foi substituída**: faltam ledger,duascolunas e definição19etapas. Fonte:dashboard-active-readonly.json eopportunity-semantic-environment-qa.json.
| Ordem | Ação futura, efeito econtagem prevista | Dependência / reversão |
| --- | --- | --- |
| 0 | Demonstração visual de C37, QA21 e A/B e correções → fixar candidata, hashes, manifesto e configuração → backup da base + originais + runtime e chave estável → restauro emQA nova, tabelas/bytes/acessos comparados. | QA backup deste lote não é backup ativo nem candidata definitiva. Ativação continua fora da autorização. |
| 1 | Disponibilizar código/Composer/build compatíveis, flagsfalse eURLs preservadas. | Não retirar privilégios reais ou migraridentidades automaticamente. Reverter flags/build/código compatível preservando dados novos. |
| 2 —030 | GETprévia→POST `/management/opportunity-resources-install`, hash/confirm/MFA/provas atuais, sóse ausente/coerente. **três coleções+metadado cifra;zero documentos importados/publicados.** | Base020/documentos existentes. Não drop apósuso; restaurar/reconciliar backup em vez de apagar originais. |
| 3 —040 | GETprévia→POST `/management/profile-install`; **quatro tabelas + uma coluna em users + três em opportunities,zero contas, atribuições ou flags.** BootstrapPOST `/management/profile-install/bootstrap` é **separado**:duas contas explicitamente designadas; um terceiro gestor com MFA aprova. | Instalador exige020+030/schema/organização/auditoria, hash ebackup/restauro atuais. Idempotência eDDL/ledger/auditoria atómicos. Schema parcial bloqueia aplicação; down apenassemqualqueruso/contexto/revisão/histórico. Recuperação deMFA simultânea exigeD-R1,sembootstraprepetido. |
| 4 —09/190 | GETprévia→POST `/management/balcao-install`, sómigraçãofaltante: **duas colunas + uma definição publicada de 19 etapas / cinco fases; zero dossiers automáticos.** | BaseBalcão/orientação jáinstaladas: não repetir. SemdepDDLde040,masordem operacional preservada. Template eversões usados imutáveis; reverterdisponibilização,preservar snapshots/roteiros. |
| 5 —cartografia | GETprévia→POST `/management/territory-geometry-import`, níveis1→2→3 ehash/idempotência. **408 correspondências candidatas** se cadastro/hash coincidem:11/133/264;ativo0na leitura. **173 pendentes** não importadas. | Fontes/hash/pai/nome/código vinculados;resultado/contagem medida no alvo,semfusões ougeometrias inventadas. Reversão só lotesnovos nãoalterados/usados,postos→distritos→províncias comaudit;seFK/uso,preservar/reconciliar,nãoforçar. |
| 6 —disponibilização | Aprovar perfis/reconciliação depermissões reais econfiguração; habilitar navegação/editores/percurso porincremento comprovado. **zero fixtures QA no ativo.** | I1–I3 não concluídos semA/B/interface. Contratos4categorias eSLA sóapósdecisão própria. Importação não ativa cálculo fiscal. |
| 7 —publicação | Revisão dedivulgação eação do Publicador por versão; **camadas cartográficas públicas são ação separada** daimportação. | Aprovaçãointerna≠acessorestrito≠catálogopúblico≠decisãoexterna. Desabilitar publicação/flags antes derestauro;preservar originais,consentimentos eauditoria. |
| Ordem | Ação futura, efeito econtagem prevista | Dependência / reversão |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Demonstração visual de C37, QA21 e A/B e correções → fixar candidata, hashes, manifesto e configuração → backup da base + originais + runtime e chave estável → restauro emQA nova, tabelas/bytes/acessos comparados. | QA backup deste lote não é backup ativo nem candidata definitiva. Ativação continua fora da autorização. |
| 1 | Disponibilizar código/Composer/build compatíveis, flagsfalse eURLs preservadas. | Não retirar privilégios reais ou migraridentidades automaticamente. Reverter flags/build/código compatível preservando dados novos. |
| 2 —030 | GETprévia→POST `/management/opportunity-resources-install`, hash/confirm/MFA/provas atuais, sóse ausente/coerente. **três coleções+metadado cifra;zero documentos importados/publicados.** | Base020/documentos existentes. Não drop apósuso; restaurar/reconciliar backup em vez de apagar originais. |
| 3 —040 | GETprévia→POST `/management/profile-install`; **quatro tabelas + uma coluna em users + três em opportunities,zero contas, atribuições ou flags.** BootstrapPOST `/management/profile-install/bootstrap` é **separado**:duas contas explicitamente designadas; um terceiro gestor com MFA aprova. | Instalador exige020+030/schema/organização/auditoria, hash ebackup/restauro atuais. Idempotência eDDL/ledger/auditoria atómicos. Schema parcial bloqueia aplicação; down apenassemqualqueruso/contexto/revisão/histórico. Recuperação deMFA simultânea exigeD-R1,sembootstraprepetido. |
| 4 —09/190 | GETprévia→POST `/management/balcao-install`, sómigraçãofaltante: **duas colunas + uma definição publicada de 19 etapas / cinco fases; zero dossiers automáticos.** | BaseBalcão/orientação jáinstaladas: não repetir. SemdepDDLde040,masordem operacional preservada. Template eversões usados imutáveis; reverterdisponibilização,preservar snapshots/roteiros. |
| 5 —cartografia | GETprévia→POST `/management/territory-geometry-import`, níveis1→2→3 ehash/idempotência. **408 correspondências candidatas** se cadastro/hash coincidem:11/133/264;ativo0na leitura. **173 pendentes** não importadas. | Fontes/hash/pai/nome/código vinculados;resultado/contagem medida no alvo,semfusões ougeometrias inventadas. Reversão só lotesnovos nãoalterados/usados,postos→distritos→províncias comaudit;seFK/uso,preservar/reconciliar,nãoforçar. |
| 6 —disponibilização | Aprovar perfis/reconciliação depermissões reais econfiguração; habilitar navegação/editores/percurso porincremento comprovado. **zero fixtures QA no ativo.** | I1–I3 não concluídos semA/B/interface. Contratos4categorias eSLA sóapósdecisão própria. Importação não ativa cálculo fiscal. |
| 7 —publicação | Revisão dedivulgação eação do Publicador por versão; **camadas cartográficas públicas são ação separada** daimportação. | Aprovaçãointerna≠acessorestrito≠catálogopúblico≠decisãoexterna. Desabilitar publicação/flags antes derestauro;preservar originais,consentimentos eauditoria. |
Sharedcode/fingerprint muda:renovar provas da revisão ealvo;ready=true não instala,não escolhe titulares,não publica enão disponibiliza percurso. Guarda ativa/QA conferida antes decada escrita futura. A prova040 emschema vazio foi isolada; no servidorQA jáusado sóoperação sem alterações, auditada.
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Ativação reconciliada: 030000, 040000 e **09/190000** — nenhuma execução no ativo
A omissão de **2026_10_09_190000_prepare_investor_path** na sequência anterior foi um erro documental; a extensão **continua necessária e não foi substituída**. Não confundir com **2026_10_07_190000_create_internal_virtual_desk**, que já está instalada no ativo.
| Recurso | QA restaurada:55441 | Ativo investemoz:5432, READ ONLY | Evidência |
| --- | --- | --- | --- |
| Gestão020000 | Instalada | Instalada | Ledger/schema anteriores preservados |
| Balcão07/190000 e orientação08/120000 | Instalados | Ambos no ledger | Leitura efetiva das migrações, sem boot de sessão ativa |
| Recursos09/030000 | Instalada | Ausente | Tabelas e ledger; não repetirQA |
| Perfis10/040000 | Instalada | Ausente | Tabelas/verificaçãoQA; nunca instalada no ativo neste trabalho |
| Percurso09/190000 | **Ledger + duas colunas + definição publicada** | **Ledger ausente; duas colunas ausentes; nenhuma definição** | `dashboard-active-readonly.json`, `opportunity-semantic-environment-qa.json` |
| Recurso | QA restaurada:55441 | Ativo investemoz:5432, READ ONLY | Evidência |
| ------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| Gestão020000 | Instalada | Instalada | Ledger/schema anteriores preservados |
| Balcão07/190000 e orientação08/120000 | Instalados | Ambos no ledger | Leitura efetiva das migrações, sem boot de sessão ativa |
| Recursos09/030000 | Instalada | Ausente | Tabelas e ledger; não repetirQA |
| Perfis10/040000 | Instalada | Ausente | Tabelas/verificaçãoQA; nunca instalada no ativo neste trabalho |
| Percurso09/190000 | **Ledger + duas colunas + definição publicada** | **Ledger ausente; duas colunas ausentes; nenhuma definição** | `dashboard-active-readonly.json`, `opportunity-semantic-environment-qa.json` |
DefiniçãoQA `61000919-0000-4000-8000-000000000001`, publicada, SHA256 **e0acbc723cd3def7e415b2ef7a0173add08387c3cedabac9bb7b86409e4d25bf**. Duas colunas: `investor_journeys.path_definition_id` e `journey_steps.path_detail`. Mantém cinco fases e rastreabilidade das19etapas; não renumera/reescreve os roteiros existentes. Recurso preparado/definição publicada não demonstra A/B na interface.
Dependências verificadas no código: **030000** usa oportunidades/documentos existentes e cria três coleções de recursos; **040000** acrescenta quatro tabelas de autorização/auditoria, uma coluna de revisão em users e três colunas em opportunities, preservando identidades/histórico; não usa as colunas de190000. **190000** usa investor_journeys/journey_steps/questionnaire_versions e depende da baseBalcão/orientação incluída no instalador. Não existe dependência DDL entre030/040 e190; disponibilizar o workflow requer020+030+040 e tasks/catalogue existentes; disponibilizar o percurso integrado requer190 e as capacidades instaladas/configuradas. Os fingerprints incluem código comum de perfis: alterar o código invalida provas antigas de readiness, sem converter isso numa dependência de schema.
| Ordem futura | Ação concreta e efeito / contagem esperada | Dependência e reversão |
| --- | --- | --- |
| 0 | Incorporar visualC37/Promotor21/A-B; corrigir falhas e fixar revisão/manifesta/configuração. Renovar dumpDB+ficheirosoriginaisprivados+chaveestável e restauroverificado numa novaQA. | Candidata ainda não fixada; provas antigas não são backup dessa revisão. Nunca key:generate indiscriminado. |
| 1 | Disponibilizar código/Composer/bundle após aprovação de ativação, flagsfalse. | Nesta análise só buildQA foi atualizado; manifestativo preservado. Reversão para código/build anteriores e flagsfalse; assegurar compatibilidade de leitura. |
| 2 | **030000**, se ledger/schema realmente ausentes: préviaGET e aplicaçãoPOST autenticada `/management/opportunity-resources-install` com hash/confirm. | Três coleções resource e metadado de cifra; **zero documentos/dados publicados/importados**. Base020/documentos existentes. Downgrade destructive recusado se originais cifrados usados. |
| 3 | **040000**, se ausente: instalar quatro tabelas/colunas através de mecanismo autenticado e bootstrap/recuperação da dupla, ainda por implementar paraativo. | Não substituir por migrateglobal/configmanual para contornar guarda. **Zero contas/grants QA** noativo. Titulares/reconciliação de permissões reais precisam de decisão explícita. Código independente de190. |
| 4 | **09/190000**, se ausente: préviaGET e aplicaçãoPOST autenticada `/management/balcao-install`; instalador seleciona só migrações faltantes. | BaseBalcão07/190000 e orientação08/120000 jáconstamdoativo: não repetir. **Duas colunas + uma definição publicada**, se não existir equivalente; **zero dossiers/journeys criados automaticamente**. Versões publicadas imutáveis. |
| 5 | Configurar catálogos/responsabilidades reais e instalar apenas contratos modulares aprovados; comparar IDs/citações/versões. | A autoridade sintética QA3e1ff315… e atores21–31 não são dados deativação. Sem alteração automática de valores legados. |
| 6 | Importação cartográfica autenticada privada `/management/territory-geometry-import`: prévia/correspondências/hash→aplicação idempotente→auditoria. | QA393=11províncias+128distritos+254postos; ativo0naúltimaleitura. **393 candidatas inequívocas**, sujeitas à prévia da revisão e aos mesmos IDs;188pendentes(31/157), sem criar geometrias falsas. Contagem final deve ser medida no alvo. Reversão por lote/metadados e histórico, sem apagar cadastros. |
| 7 | Ativar flags de perfis/oportunidades e percurso separadamente, testar navegação completa e permissões. | 030/040 antesdoscontratos/workflow;190antesdodisponibilizarpercurso; C37/visual/A-B não encerrados. Preparação paralela e acesso direto continuam. |
| 8 | **Publicar camadas, oportunidades ou documentos como ações separadas e explícitas**. | Nenhuma instalação/importação publica automaticamente; publicação não ativa cálculo fiscal. Usar decisões/evidências/hash atuais e autorização de divulgação. |
| Ordem futura | Ação concreta e efeito / contagem esperada | Dependência e reversão |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Incorporar visualC37/Promotor21/A-B; corrigir falhas e fixar revisão/manifesta/configuração. Renovar dumpDB+ficheirosoriginaisprivados+chaveestável e restauroverificado numa novaQA. | Candidata ainda não fixada; provas antigas não são backup dessa revisão. Nunca key:generate indiscriminado. |
| 1 | Disponibilizar código/Composer/bundle após aprovação de ativação, flagsfalse. | Nesta análise só buildQA foi atualizado; manifestativo preservado. Reversão para código/build anteriores e flagsfalse; assegurar compatibilidade de leitura. |
| 2 | **030000**, se ledger/schema realmente ausentes: préviaGET e aplicaçãoPOST autenticada `/management/opportunity-resources-install` com hash/confirm. | Três coleções resource e metadado de cifra; **zero documentos/dados publicados/importados**. Base020/documentos existentes. Downgrade destructive recusado se originais cifrados usados. |
| 3 | **040000**, se ausente: instalar quatro tabelas/colunas através de mecanismo autenticado e bootstrap/recuperação da dupla, ainda por implementar paraativo. | Não substituir por migrateglobal/configmanual para contornar guarda. **Zero contas/grants QA** noativo. Titulares/reconciliação de permissões reais precisam de decisão explícita. Código independente de190. |
| 4 | **09/190000**, se ausente: préviaGET e aplicaçãoPOST autenticada `/management/balcao-install`; instalador seleciona só migrações faltantes. | BaseBalcão07/190000 e orientação08/120000 jáconstamdoativo: não repetir. **Duas colunas + uma definição publicada**, se não existir equivalente; **zero dossiers/journeys criados automaticamente**. Versões publicadas imutáveis. |
| 5 | Configurar catálogos/responsabilidades reais e instalar apenas contratos modulares aprovados; comparar IDs/citações/versões. | A autoridade sintética QA3e1ff315… e atores21–31 não são dados deativação. Sem alteração automática de valores legados. |
| 6 | Importação cartográfica autenticada privada `/management/territory-geometry-import`: prévia/correspondências/hash→aplicação idempotente→auditoria. | QA393=11províncias+128distritos+254postos; ativo0naúltimaleitura. **393 candidatas inequívocas**, sujeitas à prévia da revisão e aos mesmos IDs;188pendentes(31/157), sem criar geometrias falsas. Contagem final deve ser medida no alvo. Reversão por lote/metadados e histórico, sem apagar cadastros. |
| 7 | Ativar flags de perfis/oportunidades e percurso separadamente, testar navegação completa e permissões. | 030/040 antesdoscontratos/workflow;190antesdodisponibilizarpercurso; C37/visual/A-B não encerrados. Preparação paralela e acesso direto continuam. |
| 8 | **Publicar camadas, oportunidades ou documentos como ações separadas e explícitas**. | Nenhuma instalação/importação publica automaticamente; publicação não ativa cálculo fiscal. Usar decisões/evidências/hash atuais e autorização de divulgação. |
Reversão: desativarflags/voltarbundle compatível e conservar originais/auditoria. Migrações usadas não devem ser eliminadas por rollback genérico;190recusadownquandohápercurso,030recusacomcifrados,040preservaperfil/oportunidade. Quando necessária reversão de dados, usar o restauroverificado da candidata com reconciliação das escritas posteriores. **ready=true é preparação; não instalação, ativação nem aceitação funcional.**
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Sequência reconciliada de disponibilização futura — não executada
Leitura ativa de 10/10: PostgreSQL `investemoz:5432`, transação READ ONLY, seis oportunidades publicadas; 020000 instalada, 030000/040000/percurso ausentes, flags desativadas, zero geometrias. Build ativo preservado. A revisão candidata **não está fixada**; `ready=true` e fingerprints anteriores não autorizam nem demonstram instalação.
| Ordem | Ação e efeito previsto | Dependência / reversão |
| --- | --- | --- |
| 0 | Incorporar visual C37/C43/A/B e workflow, corrigir falhas; fixar revisão, configuração e manifestos. Renovar backup DB + ficheiros privados/originais + chave estável e provar restauro numa nova QA isolada. | Provas anteriores preservadas, sem as apresentar como restauro desta revisão. Não gerar nova chave. |
| 1 | Disponibilizar código e dependências compatíveis, flags desligadas. Composer adiciona `opis/json-schema 2.4.1`, `opis/string 2.1.0`, `opis/uri 1.1.0`; zero atualizações/remoções preexistentes. | Não importar contas, classificações, contactos ou documentos sintéticos QA. Reverter código/assets compatíveis, preservando payloads/histórico. |
| 2 | Não repetir 020000. Se 030000 continuar ausente, usar prévia/aplicação autenticada `/management/opportunity-resources-install`: três tabelas, uma coluna documental, uma função e três triggers previstos. | Backup/restauro confirmado; hashes/contagens verificados no estado real; não publica nem habilita o percurso. |
| 3 | Preparar e testar o mecanismo autenticado 040000: quatro tabelas, uma coluna de utilizador, três de oportunidade, uma função e dois triggers previstos; dupla inicial/substituição independente. | Aplicação atual demonstrada exclusivamente QA. Instalação/bootstrap ativo autenticado ainda pendente; titulares reais não definidos. Não remover privilégios ativos automaticamente. |
| 4 | Configurar referências/contactos/hierarquia, perfis/tipos/representação, responsabilidades e MFA; quatro contratos modulares apenas após aprovação da versão. | Reutilizar dados mestres reais. As referências sintéticas de ensaio não resolvem cadastros ativos vazios. SLA permanece indeterminado até política aprovada. |
| 5 | Importação cartográfica autenticada, privada e idempotente; se ativo permanecer zero e correspondências iguais, até **393 = 11 províncias + 128 distritos + 254 postos**. Esperados 581 = 11/159/411; pendentes 188 = 0/31/157, nomes no relatório de correspondências. | Prévia → correspondências inequívocas → scan/hash → aplicar → auditoria; nenhuma localização/conta/perímetro de projeto inventado. Reversão pelo lote preserva origem/uso/histórico. **Publicação de camadas é ação separada.** |
| 6 | Disponibilizar flags/assets/navegação aprovados e o percurso I1–I3 pela instalação existente, sem repetir ações já presentes. Publicar cada oportunidade separadamente, com aprovação/hash/prévia/âmbito. | Cinco fases/19 etapas preservadas, dossier privado separado. Voltar flags a false limita disponibilização; manter guardas de confidencialidade para novos dados. Não executar down destrutivo após uso. |
| Ordem | Ação e efeito previsto | Dependência / reversão |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Incorporar visual C37/C43/A/B e workflow, corrigir falhas; fixar revisão, configuração e manifestos. Renovar backup DB + ficheiros privados/originais + chave estável e provar restauro numa nova QA isolada. | Provas anteriores preservadas, sem as apresentar como restauro desta revisão. Não gerar nova chave. |
| 1 | Disponibilizar código e dependências compatíveis, flags desligadas. Composer adiciona `opis/json-schema 2.4.1`, `opis/string 2.1.0`, `opis/uri 1.1.0`; zero atualizações/remoções preexistentes. | Não importar contas, classificações, contactos ou documentos sintéticos QA. Reverter código/assets compatíveis, preservando payloads/histórico. |
| 2 | Não repetir 020000. Se 030000 continuar ausente, usar prévia/aplicação autenticada `/management/opportunity-resources-install`: três tabelas, uma coluna documental, uma função e três triggers previstos. | Backup/restauro confirmado; hashes/contagens verificados no estado real; não publica nem habilita o percurso. |
| 3 | Preparar e testar o mecanismo autenticado 040000: quatro tabelas, uma coluna de utilizador, três de oportunidade, uma função e dois triggers previstos; dupla inicial/substituição independente. | Aplicação atual demonstrada exclusivamente QA. Instalação/bootstrap ativo autenticado ainda pendente; titulares reais não definidos. Não remover privilégios ativos automaticamente. |
| 4 | Configurar referências/contactos/hierarquia, perfis/tipos/representação, responsabilidades e MFA; quatro contratos modulares apenas após aprovação da versão. | Reutilizar dados mestres reais. As referências sintéticas de ensaio não resolvem cadastros ativos vazios. SLA permanece indeterminado até política aprovada. |
| 5 | Importação cartográfica autenticada, privada e idempotente; se ativo permanecer zero e correspondências iguais, até **393 = 11 províncias + 128 distritos + 254 postos**. Esperados 581 = 11/159/411; pendentes 188 = 0/31/157, nomes no relatório de correspondências. | Prévia → correspondências inequívocas → scan/hash → aplicar → auditoria; nenhuma localização/conta/perímetro de projeto inventado. Reversão pelo lote preserva origem/uso/histórico. **Publicação de camadas é ação separada.** |
| 6 | Disponibilizar flags/assets/navegação aprovados e o percurso I1–I3 pela instalação existente, sem repetir ações já presentes. Publicar cada oportunidade separadamente, com aprovação/hash/prévia/âmbito. | Cinco fases/19 etapas preservadas, dossier privado separado. Voltar flags a false limita disponibilização; manter guardas de confidencialidade para novos dados. Não executar down destrutivo após uso. |
Após uso, reverter por configuração compatível, suspensão/arquivo autorizado ou compensação auditada; não eliminar decisões, documentos, consentimentos, relações ou originais. Restauro global exige reconciliar alterações posteriores ao backup. Este plano não contém aprovação de ativação nem declaração de instalação ativa.
@@ -175,6 +580,7 @@ Após uso, reverter por configuração compatível, suspensão/arquivo autorizad
<!-- qa-workflow-20261010:end -->
<!-- qa-profiles-v1-20261010:begin -->
## Sequência consolidada: instalações, disponibilização e reversão — 10/10/2026
Preparação exclusivamente em QA. Nenhuma ativação autorizada e nenhuma revisão candidata fixada. As provas `ready` anteriores são históricas: os fingerprints incluem agora as regras de perfis, portanto não comprovam esta revisão nem instalação funcional.
@@ -205,6 +611,7 @@ Manifesto QA `22947d5c47487137b9e37138f29322d99181c7d0cb0bc655dba67fd2e444ae80`;
> Registos anteriores preservados como histórico. Os estados correntes são os da matriz e do bloco mais recente acima; uma entrega posterior não altera retroativamente a evidência anterior.
<!-- qa-dashboard-20261010:begin -->
## Sequência adicional C43/C44 —10/10/2026
Preparação apenas; nenhuma ativação autorizada/executada. Fingerprints correntes: percurso `580e6619937e7acd382415fa446524dd0b5de5162aea3ff51115cdbbf822f67f`, recursos `bfb2eab205de521e746e86097684bc5f93883d7553f23a7bf96ec7c481869cf1`, cartografia `8e042c65d94b810aa03e9b2a9fe5f1bc10269bc1d1631d006fa1058dc2fc46e8`. Provasready anteriores ficam históricas; nenhuma candidata final.
@@ -222,20 +629,21 @@ Plano detalhado anterior conservado abaixo; aplicação documental ativa autenti
<!-- qa-dashboard-20261010:end -->
<!-- qa-independent-20261010:begin -->
## Sequência corrente reconciliada — 10/10/2026
Plano preparado para futura autorização; nenhuma ação ativa executada. Revisão não candidata: percurso `daace78d4e0999984dab2561d60778878eb901cd88adeaf539a1a674f88c6767`, cartografia `8e042c65d94b810aa03e9b2a9fe5f1bc10269bc1d1631d006fa1058dc2fc46e8`, recursos `3b576d542bb742afb753958d53647421e9a26d77ee680273c9e85d8a1fad285e`. `ready=true` antigo representa outra preparação e não instalação/conclusão.
| Ordem | Ação futura | Dependência/efeito previsto | Reversão |
| --- | --- | --- | --- |
|0|Concluir critérios visuaisA/B, C37 e consumidores; corrigir falhas e fixar commit/assets/fingerprints.|Provas de API/persistência não substituem interface. Não há candidata final agora.|Corrigir/revalidar só critérios afetados; preservar provas anteriores.|
|1|Renovar backup de DB+ficheiros privados/chaves/originais/metadados e restaurar em nova QA loopback*_test:55441.|Guarda antes da escrita; comparar schema/IDs/relações/hashes/classificações/RLS/ficheiros. 288 tabelas/5 ficheiros são histórico09/10, não contagem a forçar. Provas de reversão/compatibilidade da candidata.|Nunca sobrescrever escritas posteriores sem reconciliação. Restauro ativo permanece fora desta autorização.|
|2|Disponibilizar código/assets/configuração mantendo INVESTOR_PATH_ENABLED=false e TERRITORY_GEOMETRY_IMPORT_ENABLED=false.|Correções países/documentos/seletores não criam nem reclassificam dados por deploy. ClamD/GD somente nas operações binárias afetadas.|Rollback de código compatível preservando payloads novos/originais. CLI documents:import-batch --apply continua recusado no ativo.|
|3|Gestor ativo autorizado: GET/POST /management/opportunity-resources-install **somente se030000ausente**.|Prévia/backup/hash/autorização atuais;3 tabelas de associação+1coluna documents+função/3triggers;0 documentos/recursos/geometrias criados automaticamente. Não repetir instalações básicas.|Down somente vazio; após uso preservar dados/originais e desligar disponibilização em vez de apagar.|
|4|GET/POST /management/balcao-install somente para migrations pendentes, prevista190000.|2 colunas+1 definição imutável;0 conversões/dossiers/etapas automáticas. Prova A/Bvisual atual exigida. 19 etapas/5fases e roteiros legados preservados.|Down recusa após uso; desabilitar flag mantendo definição/dossiers/história.|
|5|Habilitar INVESTOR_PATH_ENABLED em ação separada, após schema e aceitação.|Mostra percurso;19 etapas somente ao criar dossier novo; ferramentas diretas/URLs/IDs permanecem.|Flagfalse, sem apagar dossier/resultados/documentos/tarefas/consentimentos.|
|6|Preparar prova específica cartográfica vinculada ao fingerprint/alvo/backuprestaurado/UI; habilitar rota separadamente; gestor/MFA GET /management/territory-geometry-import?level=1 → POST, depois2, depois3.|Cada prévia deve conservar exemplar/hash/scan/crosswalk/pai/conflitos. **Se ativo continuar0 e mesmas correspondências únicas:393=11+128+254 novas internas**,0 geo_locations/locais/perímetros de investimento. 31/157 pendentes de fora. QA 393inclui32novas e361preservadas; replay 0 novas. Scan vencido exige renovar prova por bytes, sem reabrir aceitação oficial.|POST /management/territory-geometry-import/{batch}/reverse com MFA/razão/idempotência; **postos→distritos→províncias**. Recusa descendentes ativos da edição mesmo sem FK, uso/alteração/publicação; só exclusão lógica de novos intactos não usados. Preservar reutilizados/catalogue/hash/histórico.|
|7|Divulgar camadas por consumidor/âmbito autorizado em ação separada.|Importador não publica. Limites administrativos não são DUAT/perímetro do investimento; não transformar internal em public para passar ensaio. Mecanismo de divulgação de limites administrativos continua a concretizar conforme política existente.|Retirar camada/autorização sem eliminar geometrias/originais/relações.|
| Ordem | Ação futura | Dependência/efeito previsto | Reversão |
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 0 | Concluir critérios visuaisA/B, C37 e consumidores; corrigir falhas e fixar commit/assets/fingerprints. | Provas de API/persistência não substituem interface. Não há candidata final agora. | Corrigir/revalidar só critérios afetados; preservar provas anteriores. |
| 1 | Renovar backup de DB+ficheiros privados/chaves/originais/metadados e restaurar em nova QA loopback*_test:55441. | Guarda antes da escrita; comparar schema/IDs/relações/hashes/classificações/RLS/ficheiros. 288 tabelas/5 ficheiros são histórico09/10, não contagem a forçar. Provas de reversão/compatibilidade da candidata. | Nunca sobrescrever escritas posteriores sem reconciliação. Restauro ativo permanece fora desta autorização. |
| 2 | Disponibilizar código/assets/configuração mantendo INVESTOR_PATH_ENABLED=false e TERRITORY_GEOMETRY_IMPORT_ENABLED=false. | Correções países/documentos/seletores não criam nem reclassificam dados por deploy. ClamD/GD somente nas operações binárias afetadas. | Rollback de código compatível preservando payloads novos/originais. CLI documents:import-batch --apply continua recusado no ativo. |
| 3 | Gestor ativo autorizado: GET/POST /management/opportunity-resources-install **somente se030000ausente**. | Prévia/backup/hash/autorização atuais;3 tabelas de associação+1coluna documents+função/3triggers;0 documentos/recursos/geometrias criados automaticamente. Não repetir instalações básicas. | Down somente vazio; após uso preservar dados/originais e desligar disponibilização em vez de apagar. |
| 4 | GET/POST /management/balcao-install somente para migrations pendentes, prevista190000. | 2 colunas+1 definição imutável;0 conversões/dossiers/etapas automáticas. Prova A/Bvisual atual exigida. 19 etapas/5fases e roteiros legados preservados. | Down recusa após uso; desabilitar flag mantendo definição/dossiers/história. |
| 5 | Habilitar INVESTOR_PATH_ENABLED em ação separada, após schema e aceitação. | Mostra percurso;19 etapas somente ao criar dossier novo; ferramentas diretas/URLs/IDs permanecem. | Flagfalse, sem apagar dossier/resultados/documentos/tarefas/consentimentos. |
| 6 | Preparar prova específica cartográfica vinculada ao fingerprint/alvo/backuprestaurado/UI; habilitar rota separadamente; gestor/MFA GET /management/territory-geometry-import?level=1 → POST, depois2, depois3. | Cada prévia deve conservar exemplar/hash/scan/crosswalk/pai/conflitos. **Se ativo continuar0 e mesmas correspondências únicas:393=11+128+254 novas internas**,0 geo_locations/locais/perímetros de investimento. 31/157 pendentes de fora. QA 393inclui32novas e361preservadas; replay 0 novas. Scan vencido exige renovar prova por bytes, sem reabrir aceitação oficial. | POST /management/territory-geometry-import/{batch}/reverse com MFA/razão/idempotência; **postos→distritos→províncias**. Recusa descendentes ativos da edição mesmo sem FK, uso/alteração/publicação; só exclusão lógica de novos intactos não usados. Preservar reutilizados/catalogue/hash/histórico. |
| 7 | Divulgar camadas por consumidor/âmbito autorizado em ação separada. | Importador não publica. Limites administrativos não são DUAT/perímetro do investimento; não transformar internal em public para passar ensaio. Mecanismo de divulgação de limites administrativos continua a concretizar conforme política existente. | Retirar camada/autorização sem eliminar geometrias/originais/relações. |
Aplicação documental em lote no ativo exige mecanismo autenticado próprio, ainda pendente; o comando existente serve prévia e ensaio isoladoQA. Não adicionar esse lote à sequência ativa como se nomear --actor autenticasse. Schema/workflow especializado preparado não integra estas migrations nem é ativado por elas; sua futura revisão deve ter provas e plano próprios no mesmo backlog.
@@ -248,14 +656,14 @@ ClamD real e tipos/derivadas já demonstrados mantêm suas provas; arranque apó
O pedido de reabertura referia a conta esperada18. A captura manual21:22–21:24UTC demonstra que foi selecionada a conta13 restaurada. O MFA foi alcançado, mas a autenticação nunca se completou. Causa concreta: credenciais MFA da conta13 cifradas pela chave de origem, incompatíveis com a chave estávelQA; a conta18 sintética não foi desafiada nessa tentativa. Nenhuma chave, MFA ou conta13 foi alterada para contornar o problema.
| UTC09/10 | Pedido | Resultado observado |
|---|---|---|
|21:22:10|GET/investimentos|302/login; sessão convidada guardada, destino pretendido /investimentos.|
|21:22:11|GET/login|200; mesmo cookie/sessão, sem autenticação.|
|21:22:44|POST/login|302/two-factor-challenge; login.id=13, não18.|
|21:22:44|GET/two-factor-challenge|200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador.|
|21:23:04|POST/two-factor-challenge|Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada.|
|21:23:04|GET/login|200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado.|
| UTC09/10 | Pedido | Resultado observado |
| -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| 21:22:10 | GET/investimentos | 302/login; sessão convidada guardada, destino pretendido /investimentos. |
| 21:22:11 | GET/login | 200; mesmo cookie/sessão, sem autenticação. |
| 21:22:44 | POST/login | 302/two-factor-challenge; login.id=13, não18. |
| 21:22:44 | GET/two-factor-challenge | 200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador. |
| 21:23:04 | POST/two-factor-challenge | Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada. |
| 21:23:04 | GET/login | 200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado. |
Primeiro desvio do ensaio: POST/login desafia13. Primeira falha técnica: POST/two-factor-challenge às21:23:04 (trace ec68d040a3291cb8, referência26e15b04-07b8-4211-a2a0-7f70509e03f6). Não se tratou de código MFA rejeitado pelo verificador nem de perda após autenticação. Os dois campos cifrados (secret/recovery) são incompatíveis; como nenhum corpo foi retido, não se afirma qual modalidade de entrada foi usada nesta tentativa. Não foram observados conflitos de cookies, mudança de chave/guard ou redirecionamento para outra origem.
@@ -294,16 +702,16 @@ Reversão do lote: POST `/management/territory-geometry-import/{batch}/reverse`,
Plano preparado, **não executado**. A/B HTTP/nova sessão real passaram; interface ainda pendente. Por isso não renovar o backup final como se a demonstração visual estivesse concluída nem considerar pronta a ativação. A revisão atual alterou fingerprints: percurso `ba3781ad7af15b02c3021e69081f4129a2a19339fd740094d39e913f3657977c`; recursos `2d3b517a4b37af385b1f128a0d2be2dd17b82eeee9f23b2429132d9b7360311d`. Provas anteriores preservadas e insuficientes para esses hashes. `activation_ready=false`.
| Ordem | Ação exata futura | Dependência/efeito esperado | Verificação e reversão |
| --- | --- | --- | --- |
| 0 | Concluir roteiro QA A/B e consumidores; fixar revisão/assets/hashes | Interface com nova sessão/perfis/resultados; nenhuma mistura. Não usar contagem global como substituto. | Registar cada critério na mesma matriz; se mudar código relevante, repetir respetiva demonstração. |
| 1 | Renovar dump + ficheiros privados e restaurar numa nova base loopback*_test:55441; ensaiar compatibilidade/reversão sobre essa cópia | Origem ativa apenas READ ONLY; destino QA com guarda. Usar mecanismos de backup existentes, incluindo tools/desk-activation-backup.php; preservar prova antiga antes de substituir. Comparar schema, contagens, hashes por tabela, ficheiros/chave privada, órfãos/relações/RLS.288tabelas/5ficheiros são baseline histórico, não contagem a forçar. | Repetir ensaio vazio e recusa depois de uso; gerar provas para ambos os fingerprints sem fabricar true nem copiar flags visuais de outra versão. Não renovar/aplicar no ativo agora. |
| 2 | Disponibilizar correções/assets desta revisão, mantendo INVESTOR_PATH_ENABLED=false | Países/origem/filtros/maturidade/C27; sem reclassificar valores legados, sem novo dado por deploy. | Confirmar assets servidos; rollback de código compatível preserva novos payloads/histórico. |
| 3 | Conta ativa autorizada: GET `/management/opportunity-resources-install`, confirmar prévia atual, depois POST nessa rota **somente se030000 estiver ausente** | `2026_10_09_030000_extend_opportunity_resources`:3tabelas de associação existentes no desenho,1coluna em documents,1função/3triggers,1migration/evento;0recursos/documentos/localizações novos automaticamente. Backup/restauro/compatibilidade/hash/permissões. | Ler ledger/evento/autor/hash e comparar dados/classificações/relações/originais. Não repetir instalação como ensaio. Down só sem recursos/originais cifrados; após uso preservação/exportação antes de recuperação. |
| 4 | GET `/management/balcao-install`, conferir apenas migration190000 pendente; POST autenticado pela mesma rota |2colunas nas entidades atuais +1definição publicada imutável +ledger/evento.0conversões de journeys antigos,0dossiers/etapas/tarefas criados. `pathQaVerified` exige API e A/B visual dessa revisão. Não repetir migrations básicas do Balcão/Bolsa/gestão já instaladas. | Schema/definição/ledger/evento/hash; instalação não habilita percurso. Down recusa após uso; preservar definição/história/RLS. |
| 5 | Em ação de configuração/deploy separada, habilitar INVESTOR_PATH_ENABLED e atualizar configuração servida | Só depois de schema instalado e QA visual da versão. Mostra `/investimentos`/painel; instancia19etapas apenas ao criar novo dossier, sem renumerar roteiros. | Confirmar rotas/layout/perfis/recuperação. Reversão imediata: desligar flag preservando dossiers, drafts, resultados, documentos, consentimentos, tarefas e eventos; ferramentas diretas mantidas. |
| 6 | Prévia/aplicação **cartográfica autenticada**, lote oficial privado, em geo_geometries existentes | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`; mecanismo preparado e demonstrado em QA. **Não existe prova ativa válida desta revisão agora**. Depende de prévia/hash/original/scan/dedup/conflitos. Se base continuar0 e todas as correspondências permanecerem inequívocas:361=9+120+232novos;0geo_locations/pontos/perímetros de investimento.2/39/179ficam de fora. | Guardar lote/origem/edição/IDs/autor/eventos; replay0novos. Não apontar portal-audit-geometry-qa.php ao ativo. Reverter acesso/arquivar apenas lote novo sem uso; preservar originais/relações/história. |
| 7 | Disponibilizar camadas por consumidor/âmbito autorizado, ato separado de importar | Fonte aceite não é divulgação automática; edição2019/atualidade jurídica/administrativo vs implantação explícitos. Limites internos não podem aparecer publicamente para tornar o teste verde. | Conferir cada mapa/selector/perfil. Retirar camada/autorização sem apagar geometria ou histórico. |
| Ordem | Ação exata futura | Dependência/efeito esperado | Verificação e reversão |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Concluir roteiro QA A/B e consumidores; fixar revisão/assets/hashes | Interface com nova sessão/perfis/resultados; nenhuma mistura. Não usar contagem global como substituto. | Registar cada critério na mesma matriz; se mudar código relevante, repetir respetiva demonstração. |
| 1 | Renovar dump + ficheiros privados e restaurar numa nova base loopback*_test:55441; ensaiar compatibilidade/reversão sobre essa cópia | Origem ativa apenas READ ONLY; destino QA com guarda. Usar mecanismos de backup existentes, incluindo tools/desk-activation-backup.php; preservar prova antiga antes de substituir. Comparar schema, contagens, hashes por tabela, ficheiros/chave privada, órfãos/relações/RLS.288tabelas/5ficheiros são baseline histórico, não contagem a forçar. | Repetir ensaio vazio e recusa depois de uso; gerar provas para ambos os fingerprints sem fabricar true nem copiar flags visuais de outra versão. Não renovar/aplicar no ativo agora. |
| 2 | Disponibilizar correções/assets desta revisão, mantendo INVESTOR_PATH_ENABLED=false | Países/origem/filtros/maturidade/C27; sem reclassificar valores legados, sem novo dado por deploy. | Confirmar assets servidos; rollback de código compatível preserva novos payloads/histórico. |
| 3 | Conta ativa autorizada: GET `/management/opportunity-resources-install`, confirmar prévia atual, depois POST nessa rota **somente se030000 estiver ausente** | `2026_10_09_030000_extend_opportunity_resources`:3tabelas de associação existentes no desenho,1coluna em documents,1função/3triggers,1migration/evento;0recursos/documentos/localizações novos automaticamente. Backup/restauro/compatibilidade/hash/permissões. | Ler ledger/evento/autor/hash e comparar dados/classificações/relações/originais. Não repetir instalação como ensaio. Down só sem recursos/originais cifrados; após uso preservação/exportação antes de recuperação. |
| 4 | GET `/management/balcao-install`, conferir apenas migration190000 pendente; POST autenticado pela mesma rota | 2colunas nas entidades atuais +1definição publicada imutável +ledger/evento.0conversões de journeys antigos,0dossiers/etapas/tarefas criados. `pathQaVerified` exige API e A/B visual dessa revisão. Não repetir migrations básicas do Balcão/Bolsa/gestão já instaladas. | Schema/definição/ledger/evento/hash; instalação não habilita percurso. Down recusa após uso; preservar definição/história/RLS. |
| 5 | Em ação de configuração/deploy separada, habilitar INVESTOR_PATH_ENABLED e atualizar configuração servida | Só depois de schema instalado e QA visual da versão. Mostra `/investimentos`/painel; instancia19etapas apenas ao criar novo dossier, sem renumerar roteiros. | Confirmar rotas/layout/perfis/recuperação. Reversão imediata: desligar flag preservando dossiers, drafts, resultados, documentos, consentimentos, tarefas e eventos; ferramentas diretas mantidas. |
| 6 | Prévia/aplicação **cartográfica autenticada**, lote oficial privado, em geo_geometries existentes | C30: GET/POST `/management/territory-geometry-import`, POST `/{batch}/reverse`; mecanismo preparado e demonstrado em QA. **Não existe prova ativa válida desta revisão agora**. Depende de prévia/hash/original/scan/dedup/conflitos. Se base continuar0 e todas as correspondências permanecerem inequívocas:361=9+120+232novos;0geo_locations/pontos/perímetros de investimento.2/39/179ficam de fora. | Guardar lote/origem/edição/IDs/autor/eventos; replay0novos. Não apontar portal-audit-geometry-qa.php ao ativo. Reverter acesso/arquivar apenas lote novo sem uso; preservar originais/relações/história. |
| 7 | Disponibilizar camadas por consumidor/âmbito autorizado, ato separado de importar | Fonte aceite não é divulgação automática; edição2019/atualidade jurídica/administrativo vs implantação explícitos. Limites internos não podem aparecer publicamente para tornar o teste verde. | Conferir cada mapa/selector/perfil. Retirar camada/autorização sem apagar geometria ou histórico. |
ClamD é requisito de scan/reabertura/download/publicação dos binários afetados; arranque/assinaturas e cada derivada têm provas próprias. GD/WebP depende do PHP web. Não bloquear metadados, países, estatísticas ou preparação independente por estes itens. Nenhum cálculo fiscal ativado por importação/publicação.
@@ -1,346 +1,346 @@
{
"kind": "capability_map_not_a_parallel_requirement_matrix",
"source_sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"runtime_read_only_capture": "2026-10-09T19:03:32+00:00",
"stage_count": 19,
"phase_count": 5,
"structural_implementation_approved": true,
"active_writes": 0,
"stages": [
{
"stage_id": "S01",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 22,
"text": "Sistematizar a ideia: identificar o problema ou oportunidade, definir a proposta de valor, os promotores e a localização preliminar."
},
"diagram_mapping": "bloco 1",
"capabilities": "Draft do simulador, dossier Balcão, perfil, planejamento",
"applicability_dependencies_result": "Sempre; título/objetivo mínimos para guardar, proposta/promotores/localização preliminar quando conhecidos",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-SIM-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S02",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 23,
"text": "Realizar a análise preliminar: avaliar o mercado, a viabilidade técnica, o impacto económico e social e os principais riscos."
},
"diagram_mapping": "bloco 2",
"capabilities": "Plano empresarial, riscos, cenários financeiros, biblioteca",
"applicability_dependencies_result": "Sempre; evidências e pressupostos separados, valores ausentes indeterminados",
"audit_requirement_refs": "AUD-SIM-02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S03",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 24,
"text": "Decidir sobre a viabilidade da ideia: se não for viável, reformular ou arquivar e regressar à sistematização; se for viável, avançar para a estruturação."
},
"diagram_mapping": "losango ideia viável",
"capabilities": "Readiness e orientação explicável",
"applicability_dependencies_result": "Decisão do promotor com fundamentos; prosseguir/reformular/arquivar. Sem score automático, aprovação pública ou bloqueio da preparação",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-DASH-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S04",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 25,
"text": "Estruturar o investimento: preparar o plano de negócios, o modelo financeiro, o cronograma, a governação e a forma jurídica."
},
"diagram_mapping": "bloco 3",
"capabilities": "Plano, equipa, marcos e snapshots",
"applicability_dependencies_result": "Sempre; consolidar estratégia, finanças, calendário e forma jurídica, sem reintroduzir dados conhecidos",
"audit_requirement_refs": "AUD-DESK-02, AUD-SIM-01/02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S05",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 26,
"text": "Constituir e registar a entidade: obter o NUIT, efectuar o registo comercial, abrir a conta bancária e concluir os cadastros laboral e fiscal aplicáveis."
},
"diagram_mapping": "bloco 4",
"capabilities": "Declarações empresariais e Balcão E1–E9",
"applicability_dependencies_result": "Conforme entidade/tipo de investimento; registo/NUIT são atos externos, dados declarados não os provam; entidade existente reutilizada",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S06",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 27,
"text": "Preparar o processo de investimento: reunir a memória descritiva, o orçamento, as fontes de financiamento, os estudos e os comprovativos."
},
"diagram_mapping": "bloco 5",
"capabilities": "`desk_cases`, documentos e revisões, investment submission",
"applicability_dependencies_result": "Preparação paralela à constituição; atos de envio exigem somente os campos/documentos do serviço aplicável",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01/02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S07",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 28,
"text": "Submeter o projecto: solicitar as autorizações de investimento e os incentivos aplicáveis."
},
"diagram_mapping": "bloco 6",
"capabilities": "Serviço project-preparation, protocolo, recibo, revisão",
"applicability_dependencies_result": "Apenas quando aplicável e após revisão/consentimento; pedido interno não equivale a envio ou aprovação APIEX/incentivo",
"audit_requirement_refs": "AUD-DESK-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S08",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 29,
"text": "Executar o licenciamento prévio e integrado: tratar, conforme a aplicabilidade, das licenças ambiental, sectorial e de construção, bem como das autorizações de segurança, trabalho, fiscais e municipais necessárias antes da implementação. A licença de operação deve permanecer condicionada às inspecções e aos testes posteriores."
},
"diagram_mapping": "bloco 7",
"capabilities": "Etapas documentais Balcão, fontes, documentos e validade",
"applicability_dependencies_result": "Regras por atividade/localização; preparar em paralelo; cada submissão depende do seu contrato. Operação fica em S17",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S09",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 30,
"text": "Decidir sobre a necessidade de terra: se o projecto não necessitar de terra, avançar para o financiamento; se necessitar, activar o subpercurso de terra."
},
"diagram_mapping": "losango terra",
"capabilities": "Perguntas de localização e assistência fundiária",
"applicability_dependencies_result": "Sim/não/por determinar com fundamento e histórico. Não depende de licença já aprovada para responder",
"audit_requirement_refs": "AUD-LAND-01, AUD-GEO-02, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S10",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 31,
"text": "Regularizar a terra: identificar a área, verificar a compatibilidade territorial, realizar a consulta comunitária e o levantamento, tramitar o DUAT, a cessão ou o arrendamento e efectuar o registo aplicável."
},
"diagram_mapping": "blocos 8–10",
"capabilities": "LandAssistance, seletores, mapas, anexos",
"applicability_dependencies_result": "Só se S09=sim; área, compatibilidade, consulta/levantamento/título/registo conforme regra oficial. Geometria não é DUAT nem prova de disponibilidade",
"audit_requirement_refs": "AUD-LAND-01, AUD-GEO-01/02/03, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S11",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 32,
"text": "Confirmar a regularização: se as licenças e a terra não estiverem regularizadas, corrigir as pendências e regressar às etapas correspondentes; se estiverem regularizadas, prosseguir."
},
"diagram_mapping": "losango licenças e terra",
"capabilities": "Evidência e revisão documental separadas",
"applicability_dependencies_result": "Verificar requisitos efetivamente aplicáveis; devolver pendências a S08/S10. Ato condiciona execução, não bloqueia S02/S04 ou preparação financeira",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S12",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 33,
"text": "Decidir sobre a necessidade de financiamento: se o projecto necessitar de financiamento externo, activar a estruturação financeira, a due diligence, a negociação, a aprovação, o fecho e o desembolso; se não necessitar, registar a fonte de capital próprio e avançar directamente para a implementação, desde que as restantes condições estejam cumpridas."
},
"diagram_mapping": "bloco 11 e condição do texto",
"capabilities": "Fontes de fundos, plano, simulador, parceiros",
"applicability_dependencies_result": "Sim/não/por determinar. Sem financiamento externo: guardar fonte/capital próprio; não afirmar disponibilidade sem evidência",
"audit_requirement_refs": "AUD-SIM-01/02, AUD-PART-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S13",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 34,
"text": "Realizar a due diligence e a negociação: validar os aspectos jurídicos, técnicos, financeiros e operacionais e negociar as condições."
},
"diagram_mapping": "bloco 12",
"capabilities": "Sala de parceria, documentos, tarefas, cenários",
"applicability_dependencies_result": "Ramo de financiamento externo; preparação paralela a terra. Não dispensa outras diligências aplicáveis fora desse ramo",
"audit_requirement_refs": "AUD-PART-01, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S14",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 35,
"text": "Decidir sobre o financiamento: se não for aprovado, rever a estrutura financeira e as garantias e regressar à estruturação do financiamento; se for aprovado, concluir o fecho financeiro."
},
"diagram_mapping": "losango aprovado",
"capabilities": "Marcos/parcerias e registo assistido",
"applicability_dependencies_result": "Resultado do financiador, com referência/documento/data; recusa regressa à estrutura sem apagar propostas anteriores",
"audit_requirement_refs": "AUD-PART-01, AUD-DESK-02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S15",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 36,
"text": "Concluir o fecho financeiro e o desembolso: cumprir as condições precedentes, formalizar os contratos e disponibilizar os fundos."
},
"diagram_mapping": "bloco 13",
"capabilities": "Marcos, documentos e obrigações declaradas",
"applicability_dependencies_result": "Se financiamento externo; aprovação não comprova contrato, condições cumpridas ou desembolso",
"audit_requirement_refs": "AUD-PART-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S16",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 37,
"text": "Implementar o projecto: executar aquisições, contratações, obras e instalação dos equipamentos."
},
"diagram_mapping": "bloco 14",
"capabilities": "ProjectPlanning, tarefas, marcos, aftercare",
"applicability_dependencies_result": "Planejar sempre; executar apenas requisitos prévios aplicáveis cumpridos, com motivo específico e evidência",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-CRM-01, AUD-DASH-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S17",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 38,
"text": "Realizar inspecções e testes: verificar a conformidade e obter a licença de operação."
},
"diagram_mapping": "bloco 15",
"capabilities": "Documentos, resultados e tarefas",
"applicability_dependencies_result": "Conforme atividade; inspeção e emissão são externas, checklist concluída não é licença",
"audit_requirement_refs": "AUD-DESK-02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S18",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 39,
"text": "Iniciar a operação: colocar o investimento em funcionamento após o cumprimento dos requisitos aplicáveis."
},
"diagram_mapping": "bloco 16",
"capabilities": "Marcos de execução e acompanhamento",
"applicability_dependencies_result": "Cumprir exigências aplicáveis de S17 e anteriores; guardar data/decisão declarada/evidências, sem assumir legalidade por clique",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-CRM-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S19",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 40,
"text": "Monitorar continuamente: acompanhar a conformidade fiscal, laboral, ambiental e regulatória, a validade das licenças, os indicadores e as auditorias."
},
"diagram_mapping": "bloco 17",
"capabilities": "Aftercare, tarefas, validade documental, audit_events",
"applicability_dependencies_result": "Operação ativa; conformidade, renovações, indicadores e medidas corretivas. É recorrente, não fica definitivamente concluída por preencher",
"audit_requirement_refs": "AUD-CRM-01, AUD-DASH-01, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
"kind": "capability_map_not_a_parallel_requirement_matrix",
"source_sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"runtime_read_only_capture": "2026-10-09T19:03:32+00:00",
"stage_count": 19,
"phase_count": 5,
"structural_implementation_approved": true,
"active_writes": 0,
"stages": [
{
"stage_id": "S01",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 22,
"text": "Sistematizar a ideia: identificar o problema ou oportunidade, definir a proposta de valor, os promotores e a localização preliminar."
},
"diagram_mapping": "bloco 1",
"capabilities": "Draft do simulador, dossier Balcão, perfil, planejamento",
"applicability_dependencies_result": "Sempre; título/objetivo mínimos para guardar, proposta/promotores/localização preliminar quando conhecidos",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-SIM-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S02",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 23,
"text": "Realizar a análise preliminar: avaliar o mercado, a viabilidade técnica, o impacto económico e social e os principais riscos."
},
"diagram_mapping": "bloco 2",
"capabilities": "Plano empresarial, riscos, cenários financeiros, biblioteca",
"applicability_dependencies_result": "Sempre; evidências e pressupostos separados, valores ausentes indeterminados",
"audit_requirement_refs": "AUD-SIM-02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S03",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 24,
"text": "Decidir sobre a viabilidade da ideia: se não for viável, reformular ou arquivar e regressar à sistematização; se for viável, avançar para a estruturação."
},
"diagram_mapping": "losango ideia viável",
"capabilities": "Readiness e orientação explicável",
"applicability_dependencies_result": "Decisão do promotor com fundamentos; prosseguir/reformular/arquivar. Sem score automático, aprovação pública ou bloqueio da preparação",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-DASH-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S04",
"phase": 1,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 25,
"text": "Estruturar o investimento: preparar o plano de negócios, o modelo financeiro, o cronograma, a governação e a forma jurídica."
},
"diagram_mapping": "bloco 3",
"capabilities": "Plano, equipa, marcos e snapshots",
"applicability_dependencies_result": "Sempre; consolidar estratégia, finanças, calendário e forma jurídica, sem reintroduzir dados conhecidos",
"audit_requirement_refs": "AUD-DESK-02, AUD-SIM-01/02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S05",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 26,
"text": "Constituir e registar a entidade: obter o NUIT, efectuar o registo comercial, abrir a conta bancária e concluir os cadastros laboral e fiscal aplicáveis."
},
"diagram_mapping": "bloco 4",
"capabilities": "Declarações empresariais e Balcão E1–E9",
"applicability_dependencies_result": "Conforme entidade/tipo de investimento; registo/NUIT são atos externos, dados declarados não os provam; entidade existente reutilizada",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S06",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 27,
"text": "Preparar o processo de investimento: reunir a memória descritiva, o orçamento, as fontes de financiamento, os estudos e os comprovativos."
},
"diagram_mapping": "bloco 5",
"capabilities": "`desk_cases`, documentos e revisões, investment submission",
"applicability_dependencies_result": "Preparação paralela à constituição; atos de envio exigem somente os campos/documentos do serviço aplicável",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01/02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S07",
"phase": 2,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 28,
"text": "Submeter o projecto: solicitar as autorizações de investimento e os incentivos aplicáveis."
},
"diagram_mapping": "bloco 6",
"capabilities": "Serviço project-preparation, protocolo, recibo, revisão",
"applicability_dependencies_result": "Apenas quando aplicável e após revisão/consentimento; pedido interno não equivale a envio ou aprovação APIEX/incentivo",
"audit_requirement_refs": "AUD-DESK-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S08",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 29,
"text": "Executar o licenciamento prévio e integrado: tratar, conforme a aplicabilidade, das licenças ambiental, sectorial e de construção, bem como das autorizações de segurança, trabalho, fiscais e municipais necessárias antes da implementação. A licença de operação deve permanecer condicionada às inspecções e aos testes posteriores."
},
"diagram_mapping": "bloco 7",
"capabilities": "Etapas documentais Balcão, fontes, documentos e validade",
"applicability_dependencies_result": "Regras por atividade/localização; preparar em paralelo; cada submissão depende do seu contrato. Operação fica em S17",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S09",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 30,
"text": "Decidir sobre a necessidade de terra: se o projecto não necessitar de terra, avançar para o financiamento; se necessitar, activar o subpercurso de terra."
},
"diagram_mapping": "losango terra",
"capabilities": "Perguntas de localização e assistência fundiária",
"applicability_dependencies_result": "Sim/não/por determinar com fundamento e histórico. Não depende de licença já aprovada para responder",
"audit_requirement_refs": "AUD-LAND-01, AUD-GEO-02, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S10",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 31,
"text": "Regularizar a terra: identificar a área, verificar a compatibilidade territorial, realizar a consulta comunitária e o levantamento, tramitar o DUAT, a cessão ou o arrendamento e efectuar o registo aplicável."
},
"diagram_mapping": "blocos 8–10",
"capabilities": "LandAssistance, seletores, mapas, anexos",
"applicability_dependencies_result": "Só se S09=sim; área, compatibilidade, consulta/levantamento/título/registo conforme regra oficial. Geometria não é DUAT nem prova de disponibilidade",
"audit_requirement_refs": "AUD-LAND-01, AUD-GEO-01/02/03, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S11",
"phase": 3,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 32,
"text": "Confirmar a regularização: se as licenças e a terra não estiverem regularizadas, corrigir as pendências e regressar às etapas correspondentes; se estiverem regularizadas, prosseguir."
},
"diagram_mapping": "losango licenças e terra",
"capabilities": "Evidência e revisão documental separadas",
"applicability_dependencies_result": "Verificar requisitos efetivamente aplicáveis; devolver pendências a S08/S10. Ato condiciona execução, não bloqueia S02/S04 ou preparação financeira",
"audit_requirement_refs": "AUD-DESK-01/02, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S12",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 33,
"text": "Decidir sobre a necessidade de financiamento: se o projecto necessitar de financiamento externo, activar a estruturação financeira, a due diligence, a negociação, a aprovação, o fecho e o desembolso; se não necessitar, registar a fonte de capital próprio e avançar directamente para a implementação, desde que as restantes condições estejam cumpridas."
},
"diagram_mapping": "bloco 11 e condição do texto",
"capabilities": "Fontes de fundos, plano, simulador, parceiros",
"applicability_dependencies_result": "Sim/não/por determinar. Sem financiamento externo: guardar fonte/capital próprio; não afirmar disponibilidade sem evidência",
"audit_requirement_refs": "AUD-SIM-01/02, AUD-PART-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S13",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 34,
"text": "Realizar a due diligence e a negociação: validar os aspectos jurídicos, técnicos, financeiros e operacionais e negociar as condições."
},
"diagram_mapping": "bloco 12",
"capabilities": "Sala de parceria, documentos, tarefas, cenários",
"applicability_dependencies_result": "Ramo de financiamento externo; preparação paralela a terra. Não dispensa outras diligências aplicáveis fora desse ramo",
"audit_requirement_refs": "AUD-PART-01, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S14",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 35,
"text": "Decidir sobre o financiamento: se não for aprovado, rever a estrutura financeira e as garantias e regressar à estruturação do financiamento; se for aprovado, concluir o fecho financeiro."
},
"diagram_mapping": "losango aprovado",
"capabilities": "Marcos/parcerias e registo assistido",
"applicability_dependencies_result": "Resultado do financiador, com referência/documento/data; recusa regressa à estrutura sem apagar propostas anteriores",
"audit_requirement_refs": "AUD-PART-01, AUD-DESK-02",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S15",
"phase": 4,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 36,
"text": "Concluir o fecho financeiro e o desembolso: cumprir as condições precedentes, formalizar os contratos e disponibilizar os fundos."
},
"diagram_mapping": "bloco 13",
"capabilities": "Marcos, documentos e obrigações declaradas",
"applicability_dependencies_result": "Se financiamento externo; aprovação não comprova contrato, condições cumpridas ou desembolso",
"audit_requirement_refs": "AUD-PART-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S16",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 37,
"text": "Implementar o projecto: executar aquisições, contratações, obras e instalação dos equipamentos."
},
"diagram_mapping": "bloco 14",
"capabilities": "ProjectPlanning, tarefas, marcos, aftercare",
"applicability_dependencies_result": "Planejar sempre; executar apenas requisitos prévios aplicáveis cumpridos, com motivo específico e evidência",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-CRM-01, AUD-DASH-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S17",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 38,
"text": "Realizar inspecções e testes: verificar a conformidade e obter a licença de operação."
},
"diagram_mapping": "bloco 15",
"capabilities": "Documentos, resultados e tarefas",
"applicability_dependencies_result": "Conforme atividade; inspeção e emissão são externas, checklist concluída não é licença",
"audit_requirement_refs": "AUD-DESK-02, AUD-LIB-01, AUD-GUIDE-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S18",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 39,
"text": "Iniciar a operação: colocar o investimento em funcionamento após o cumprimento dos requisitos aplicáveis."
},
"diagram_mapping": "bloco 16",
"capabilities": "Marcos de execução e acompanhamento",
"applicability_dependencies_result": "Cumprir exigências aplicáveis de S17 e anteriores; guardar data/decisão declarada/evidências, sem assumir legalidade por clique",
"audit_requirement_refs": "AUD-GUIDE-01, AUD-CRM-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
},
{
"stage_id": "S19",
"phase": 5,
"source": {
"sha256": "aa13c53138ec15cd808de43d9dc2fc6808da86943d09d3352c9dd0944bdae364",
"part": "word/document.xml",
"paragraph": 40,
"text": "Monitorar continuamente: acompanhar a conformidade fiscal, laboral, ambiental e regulatória, a validade das licenças, os indicadores e as auditorias."
},
"diagram_mapping": "bloco 17",
"capabilities": "Aftercare, tarefas, validade documental, audit_events",
"applicability_dependencies_result": "Operação ativa; conformidade, renovações, indicadores e medidas corretivas. É recorrente, não fica definitivamente concluída por preencher",
"audit_requirement_refs": "AUD-CRM-01, AUD-DASH-01, AUD-LIB-01",
"proposed": true,
"runtime_definition_prepared": true,
"integrated_ui_demonstrated": false
}
],
"qa_scenarios": {
"A": {
"land_needed": false,
"external_funding_needed": false,
"status": "api_persistence_demonstrated_integrated_ui_pending"
},
"B": {
"land_needed": true,
"external_funding_needed": true,
"status": "api_persistence_demonstrated_integrated_ui_pending"
}
}
],
"qa_scenarios": {
"A": {
"land_needed": false,
"external_funding_needed": false,
"status": "api_persistence_demonstrated_integrated_ui_pending"
},
"B": {
"land_needed": true,
"external_funding_needed": true,
"status": "api_persistence_demonstrated_integrated_ui_pending"
}
}
}
}
@@ -1,20 +1,37 @@
# Perfis modulares e SLA — propostas para decisão
## Reconciliação vigente — 11/10/2026
As frases históricas «aceites como primeira versão QA» e «experimento autorizado» abaixo descrevem o código e ensaios realizados; **não registam uma aprovação funcional dos quatro módulos ou do SLA**. A autorização de integração do legado não os aprovou. As modalidades experimentais continuam limitadas a QA e ficam excluídas da candidata COUNTRY02. Não alterar as anotações de snapshots anteriormente assinados: a Response identifica a reconciliação atual e preserva a versão histórica.
| Decisão concreta necessária | Regra proposta e fundamento | Efeito da decisão |
| --- | --- | --- |
| D-M1: aprovar os quatro contratos e a competência de cada revisão? | Aprovação funcional por competências técnica/jurídica/editorial; dupla de superutilizadores administra a segurança, sem obrigação de ambos aprovarem o produto. | Permite configurar os perfis funcionais; não designa pessoas nem altera privilégios ativos. |
| D-F1: financiamento cobre procura apenas, ou também ofertas de financiadores? | Percursos separados `seeking_funding` e `funding_offer`. Oferta exige capacidade, instrumento, elegibilidade e evidências; a regra pedido ≤ necessidade do projeto aplica-se apenas à procura. | Oferta permanece experimental até decisão; não implica crédito aprovado ou compromisso externo. |
| D-SUP1: fornecimento admite pedido de compra e oferta de fornecedor? | Separar `purchase_request` e `supply_offer`, respetivamente objeto/quantidade/aceitação do comprador e capacidade/condições do fornecedor. | Define contratos e competências de revisão próprios; uma oferta não vira pedido de compra. |
| D-M2: admitir intenção/chamada de concessão autorizada? | Rótulo explícito de preparação; ato competente obrigatório só quando se apresenta um direito atribuído. | Evita bloquear a preparação; não inventa atribuição nem dispensa o ato no caso aplicável. |
| D-M3/D-S1: aceitar condições indicativas e entidades sem histórico? | Cenário, fonte e data para propostas; declaração de ausência e projeções identificadas em vez de demonstrações inexistentes. Compromissos assumidos exigem evidência própria. | Escolha explícita de contrato/versionamento; valores históricos preservados. |
| D-M4: quais subtipos e competências aprovar em «outros»? | Rascunho incompleto guardável; submissão exige subtipo configurado e aprovado. | A ideia pode avançar enquanto a classificação aguarda; fixture QA não aprova subtipo real. |
| SLA: aprovar prazos internos, calendário, responsáveis, suplentes, pausas e escalamento? | Prazos abaixo são propostas internas. Pausar apenas a tarefa afetada com motivo/data; tarefa independente continua. Espera externa separada. Escalar ao coordenador designado; incidente crítico exige resposta imediata, distinto de triagem comum em um dia útil. | Só após calendário/nomeações configura-se compromisso operacional; nunca prazo de entidade externa. |
| D-R1: quem responde pela recuperação dos dois titulares? | Procedimento sintético testado em QA; habilitação ativa exige designação formal. | Não escolhe titulares reais nem retira privilégios automaticamente. |
D-S2 é trabalho executável já autorizado: conservar assinaturas originais, comparar o âmbito de cada parecer e reabrir apenas revisões afetadas. O ensaio `revision-materiality-chromium-20261011.json` demonstra título editorial sem reabertura e preço com reabertura exclusiva de `property_review`; aprovação final independente é sempre renovada. Permanecem os exemplos visuais das outras categorias, condições de aprovação e automatismos ainda não demonstrados. O detalhe datado consta da mesma matriz e do relatório executivo.
10/10/2026. Complemento da matriz existente, sobretudo AUD-OP-04, PROFILE-22/28/31. O texto original abaixo fica preservado como proposta histórica; o ensaio técnico QA seguinte identifica as recomendações adotadas experimentalmente, sem decisão formal de ativação. Não designa pessoas reais nem constitui aprovação ativa ou aceitação visual.
## Recomendações ensaiadas tecnicamente em QA — decisões próprias pendentes
Fonte: resposta do responsável após leitura integral desta proposta, com recomendações D-M1–M4, D-S1/S2 e D-R1. A implementação e os ensaios sintéticos decorrem da autorização QA existente. As recomendações não são compromissos operacionais aprovados; a confirmação posterior sobre o legado refere-se somente ao legado e não decide perfis/SLA. O contrato original de 110 definições e os registos anteriores permanecem intactos. As extensões usam o adaptador e o JSON canónico já existentes, sem novas tabelas de identidade ou oportunidades.
| Decisão | Reconciliação vigente em QA | Pendência concreta |
| --- | --- | --- |
| D-M1 | Aceites os quatro contratos como primeira versão QA. Aprovação funcional por competência é separada da administração de segurança; revogada nesta proposta a obrigação de ambos os aprovadores funcionais serem superutilizadores. As atribuições técnicas/jurídicas/editoriais existentes continuam aplicáveis. | Cerimónia autenticada de aprovação/ativação de versões e correspondência final das competências funcionais/governança. A dupla de segurança não é alterada ou automaticamente designada para funções de produto. |
| D-M2 | Intenção/chamada pode ser disponibilizada com autorização de divulgação e rótulo explícito de preparação. Direito declarado atribuído exige o ato competente. | Demonstração visual e documentos reais específicos numa futura utilização autorizada; o exemplar sintético não é um ato oficial. |
| D-M3 | Condições propostas exigem cenário, fonte e data. Compromisso assumido exige documento; indicação de um valor não comprova financiamento assegurado ou contrato. | Demonstração visual de cada modalidade e dos respetivos rótulos. |
| D-M4 | Ideia sem subtipo aprovado continua guardável e desenvolvível; submissão exige classificação aprovada no servidor. | Classificação funcional dos subtipos reais. O subtipo `qa-test-subtype` é apenas uma fixture sintética de aceitação, não aprovação de um objeto real. |
| D-S1 | Ausência de histórico e projeções identificadas são aceites por extensão QA v2 explícita; não exigir nem inventar demonstrações inexistentes. | Demonstrar o percurso completo na interface e manter a escolha explícita da versão. |
| D-S2 | Obrigatoriedade por tipo e reabertura apenas das revisões afetadas por alterações substantivas. Correção ortográfica não deve reiniciar todas as revisões. | Implementar e demonstrar classificação/reutilização auditada por revisão. O comportamento anterior que invalida todas as revisões ao guardar ainda não é declarado corrigido por este lote. |
| D-R1 | Preparar e testar recuperação em QA com identidades sintéticas e segregação. | Habilitação ativa depende da designação formal das pessoas responsáveis; sem bypass, terceiro titular ou escolha de pessoas reais. |
| Decisão | Reconciliação vigente em QA | Pendência concreta |
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| D-M1 | Aceites os quatro contratos como primeira versão QA. Aprovação funcional por competência é separada da administração de segurança; revogada nesta proposta a obrigação de ambos os aprovadores funcionais serem superutilizadores. As atribuições técnicas/jurídicas/editoriais existentes continuam aplicáveis. | Cerimónia autenticada de aprovação/ativação de versões e correspondência final das competências funcionais/governança. A dupla de segurança não é alterada ou automaticamente designada para funções de produto. |
| D-M2 | Intenção/chamada pode ser disponibilizada com autorização de divulgação e rótulo explícito de preparação. Direito declarado atribuído exige o ato competente. | Demonstração visual e documentos reais específicos numa futura utilização autorizada; o exemplar sintético não é um ato oficial. |
| D-M3 | Condições propostas exigem cenário, fonte e data. Compromisso assumido exige documento; indicação de um valor não comprova financiamento assegurado ou contrato. | Demonstração visual de cada modalidade e dos respetivos rótulos. |
| D-M4 | Ideia sem subtipo aprovado continua guardável e desenvolvível; submissão exige classificação aprovada no servidor. | Classificação funcional dos subtipos reais. O subtipo `qa-test-subtype` é apenas uma fixture sintética de aceitação, não aprovação de um objeto real. |
| D-S1 | Ausência de histórico e projeções identificadas são aceites por extensão QA v2 explícita; não exigir nem inventar demonstrações inexistentes. | Demonstrar o percurso completo na interface e manter a escolha explícita da versão. |
| D-S2 | Obrigatoriedade por tipo e reabertura apenas das revisões afetadas por alterações substantivas. Correção ortográfica não deve reiniciar todas as revisões. | Implementar e demonstrar classificação/reutilização auditada por revisão. O comportamento anterior que invalida todas as revisões ao guardar ainda não é declarado corrigido por este lote. |
| D-R1 | Preparar e testar recuperação em QA com identidades sintéticas e segregação. | Habilitação ativa depende da designação formal das pessoas responsáveis; sem bypass, terceiro titular ou escolha de pessoas reais. |
### Procura e oferta — contratos QA explícitos
@@ -45,38 +62,38 @@ Rascunho aceita campos incompletos; valida formato dos dados efetivamente preenc
## Quatro propostas de contrato
| Perfil proposto, ainda inativo | Regra concreta de submissão | Documentos e gates propostos | Fundamento e efeito |
| --- | --- | --- | --- |
| `concession-qa-proposal-v1` | Identificar objeto, entidade concedente, representante, regime/procedimento declarado, âmbito territorial ou digital, duração positiva com unidade, modelo de remuneração/obrigações e condições de participação. Se houver terra, usar módulo territorial e indicação das autorizações externas; se houver construção, declarar licenças aplicáveis. Datas de início/fim coerentes; não apresentar concessão ainda pretendida como direito atribuído. | Documento do objeto/procedimento e prova de representação; quando existentes, ato/contrato e título territorial. Gates `technical_review`, `legal_territorial_review`; decisão externa exigida somente quando a matriz de aplicabilidade do perfil a identificar. | §25.4 + campos comuns de promotor, localização, licenças, evidências e milestones. Se a decisão externa não existe, guardar preparação e marcar pendente; nunca fabricar autoridade, prazo ou direito. Publicar chamada/preparação só se o perfil aprovado distinguir claramente esse objeto de uma concessão atribuída. |
| `financing-qa-proposal-v1` | Identificar projeto/beneficiário e representação; instrumento pretendido, moeda, montante positivo, investimento total, financiamento assegurado, necessidade remanescente, finalidade, calendário de desembolso e cenário financeiro. Soma das rubricas = total; assegurado ≤ total; pedido ≤ necessidade. Se dívida: prazo positivo, periodicidade e condições indicativas; se capital: percentagem e direitos propostos; garantias só quando oferecidas/exigidas. | Estudo/plano financeiro e evidência do financiamento declarado assegurado; documentos da entidade e representação. Gates `technical_review`, `financial_review`, `legal_tax_due_diligence`. | Reutiliza investimento/financiamento, cenários, entidades e documentos existentes. Não calcula aprovação, elegibilidade regulatória ou score de sucesso; financiamento pretendido permanece distinto do assegurado. Condições e percentagens não são inventadas para campos vazios. |
| `supply-qa-proposal-v1` | Identificar comprador/requisitante, objeto e especificação, quantidade positiva, unidade, destino, calendário e critérios de aceitação. Preço total ou método de cotação explicitamente declarado; se valores preenchidos, moeda única e quantidade × preço reconciliada, distinguindo impostos declarados. Capacidade, licenças ou certificações só são obrigatórias quando o próprio perfil/procedimento as exigir. | Especificação/termos de referência e representação; licenças/certificados aplicáveis e prova de capacidade declarada. Gates `technical_review`, `legal_territorial_review`; financeiro quando pagamento antecipado/garantia for condição declarada. | Reutiliza produtos/inputs, mercados, país, milestones, contratos/licenças e evidências. Pedido de fornecimento não equivale a contrato celebrado. Não presume regime de contratação pública ou taxas fiscais pela categoria. |
| `other-qa-proposal-v1` | Exigir descrição do subtipo, finalidade, destinatários, resultado esperado, dados/documentos aplicáveis e indicação dos riscos. Promotor não escolhe livremente requisitos/gates para dispensar controlos: coordenação funcional aprova um subtipo e versão antes da submissão. Bloquear uso de “outros” para contornar concessão, terra, financiamento ou negócios existentes. | Documento que define objeto e representação; mínimos e gates declarados no subtipo aprovado. Base `technical_review` + `legal_territorial_review`, dispensas só fundamentadas no perfil aprovado. | §25.4 exige perfil ativo, não uma categoria sem regras. O rascunho livre é recuperável; a publicação aguarda classificação funcional explícita, sem criar um cadastro duplicado. |
| Perfil proposto, ainda inativo | Regra concreta de submissão | Documentos e gates propostos | Fundamento e efeito |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `concession-qa-proposal-v1` | Identificar objeto, entidade concedente, representante, regime/procedimento declarado, âmbito territorial ou digital, duração positiva com unidade, modelo de remuneração/obrigações e condições de participação. Se houver terra, usar módulo territorial e indicação das autorizações externas; se houver construção, declarar licenças aplicáveis. Datas de início/fim coerentes; não apresentar concessão ainda pretendida como direito atribuído. | Documento do objeto/procedimento e prova de representação; quando existentes, ato/contrato e título territorial. Gates `technical_review`, `legal_territorial_review`; decisão externa exigida somente quando a matriz de aplicabilidade do perfil a identificar. | §25.4 + campos comuns de promotor, localização, licenças, evidências e milestones. Se a decisão externa não existe, guardar preparação e marcar pendente; nunca fabricar autoridade, prazo ou direito. Publicar chamada/preparação só se o perfil aprovado distinguir claramente esse objeto de uma concessão atribuída. |
| `financing-qa-proposal-v1` | Identificar projeto/beneficiário e representação; instrumento pretendido, moeda, montante positivo, investimento total, financiamento assegurado, necessidade remanescente, finalidade, calendário de desembolso e cenário financeiro. Soma das rubricas = total; assegurado ≤ total; pedido ≤ necessidade. Se dívida: prazo positivo, periodicidade e condições indicativas; se capital: percentagem e direitos propostos; garantias só quando oferecidas/exigidas. | Estudo/plano financeiro e evidência do financiamento declarado assegurado; documentos da entidade e representação. Gates `technical_review`, `financial_review`, `legal_tax_due_diligence`. | Reutiliza investimento/financiamento, cenários, entidades e documentos existentes. Não calcula aprovação, elegibilidade regulatória ou score de sucesso; financiamento pretendido permanece distinto do assegurado. Condições e percentagens não são inventadas para campos vazios. |
| `supply-qa-proposal-v1` | Identificar comprador/requisitante, objeto e especificação, quantidade positiva, unidade, destino, calendário e critérios de aceitação. Preço total ou método de cotação explicitamente declarado; se valores preenchidos, moeda única e quantidade × preço reconciliada, distinguindo impostos declarados. Capacidade, licenças ou certificações só são obrigatórias quando o próprio perfil/procedimento as exigir. | Especificação/termos de referência e representação; licenças/certificados aplicáveis e prova de capacidade declarada. Gates `technical_review`, `legal_territorial_review`; financeiro quando pagamento antecipado/garantia for condição declarada. | Reutiliza produtos/inputs, mercados, país, milestones, contratos/licenças e evidências. Pedido de fornecimento não equivale a contrato celebrado. Não presume regime de contratação pública ou taxas fiscais pela categoria. |
| `other-qa-proposal-v1` | Exigir descrição do subtipo, finalidade, destinatários, resultado esperado, dados/documentos aplicáveis e indicação dos riscos. Promotor não escolhe livremente requisitos/gates para dispensar controlos: coordenação funcional aprova um subtipo e versão antes da submissão. Bloquear uso de “outros” para contornar concessão, terra, financiamento ou negócios existentes. | Documento que define objeto e representação; mínimos e gates declarados no subtipo aprovado. Base `technical_review` + `legal_territorial_review`, dispensas só fundamentadas no perfil aprovado. | §25.4 exige perfil ativo, não uma categoria sem regras. O rascunho livre é recuperável; a publicação aguarda classificação funcional explícita, sem criar um cadastro duplicado. |
Regras comuns propostas: referências documentais pertencem à mesma oportunidade, são recuperáveis e respeitam perfil/organização; ClamD e integridade por hash são necessários para disponibilizar binários. “Documento existente mas decisão externa pendente” difere de “documento obrigatório ausente”. Uma fonte oficial identificada continua aceite, sem segunda validação de autenticidade. A aplicação do seu âmbito e período continua rastreável.
## Correspondência de responsabilidades com papéis existentes
| Responsabilidade | Correspondência existente / proposta | Limite |
| --- | --- | --- |
| Coordenação da validação | `validator` + `validation_coordinator`, já permitido nas atribuições | Atribui revisão; não aprova o próprio processo nem substitui pareceres obrigatórios. |
| Revisão técnica e jurídica | `validator` + `technical_reviewer` / `legal_reviewer`, já permitidos | Cada tarefa requer atribuição, competência e independência; acumular papéis não dispensa impedimentos. |
| Coordenação editorial | `publisher` + `publication_coordinator`, já permitido | Atribui publicação a Publicador distinto e verifica âmbito; não transforma aprovação interna em decisão externa. |
| Instância de recurso interno | `validator` + `appeal_reviewer`, já permitido | Exige revisor independente das intervenções anteriores; não é instância de recurso legal externo. |
| Administrador funcional e governance owner | **Proposta D-M1:** os dois titulares distintos da dupla existente aprovam conjuntamente conteúdo e versão, com MFA e registo dos dois atos | Esta cerimónia de aprovação de perfil ainda não existe. Não criar outro papel ou escolher titulares reais; decisão funcional e disponibilização pública permanecem separadas. |
| Suporte operacional | Não existe responsabilidade `support` no contrato de atribuições atual. **Proposta:** coordenação da validação assume triagem; apoio do Balcão usa as permissões operacionais já existentes | Suporte não ganha revisão, aprovação, publicação ou acesso universal a documentos. Uma extensão de responsabilidades precisa de decisão explícita e teste. |
| Auditoria | `auditor`, já existente | Consulta/audita; não instala, aprova ou publica pela acumulação de papéis. |
| Responsabilidade | Correspondência existente / proposta | Limite |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Coordenação da validação | `validator` + `validation_coordinator`, já permitido nas atribuições | Atribui revisão; não aprova o próprio processo nem substitui pareceres obrigatórios. |
| Revisão técnica e jurídica | `validator` + `technical_reviewer` / `legal_reviewer`, já permitidos | Cada tarefa requer atribuição, competência e independência; acumular papéis não dispensa impedimentos. |
| Coordenação editorial | `publisher` + `publication_coordinator`, já permitido | Atribui publicação a Publicador distinto e verifica âmbito; não transforma aprovação interna em decisão externa. |
| Instância de recurso interno | `validator` + `appeal_reviewer`, já permitido | Exige revisor independente das intervenções anteriores; não é instância de recurso legal externo. |
| Administrador funcional e governance owner | **Proposta D-M1:** os dois titulares distintos da dupla existente aprovam conjuntamente conteúdo e versão, com MFA e registo dos dois atos | Esta cerimónia de aprovação de perfil ainda não existe. Não criar outro papel ou escolher titulares reais; decisão funcional e disponibilização pública permanecem separadas. |
| Suporte operacional | Não existe responsabilidade `support` no contrato de atribuições atual. **Proposta:** coordenação da validação assume triagem; apoio do Balcão usa as permissões operacionais já existentes | Suporte não ganha revisão, aprovação, publicação ou acesso universal a documentos. Uma extensão de responsabilidades precisa de decisão explícita e teste. |
| Auditoria | `auditor`, já existente | Consulta/audita; não instala, aprova ou publica pela acumulação de papéis. |
## Decisões a apreciar, sem bloquear trabalho independente
| Decisão | Regra proposta | Efeito se aprovada / alternativa |
| --- | --- | --- |
| D-M1 — Aprovar conteúdo das quatro versões e a correspondência de responsabilidades? | Aprovar a tabela como primeira versão; propor os dois titulares distintos da dupla existente como aprovadores conjuntos, nas funções de administração funcional e governance owner, com MFA, hash e data de cada ato. | Permite implementar a cerimónia de aprovação e ativação versionada, editores e gates. Até lá, os quatro rascunhos continuam recuperáveis e bloqueados para submissão. Não designa pessoas reais nem publica automaticamente. |
| D-M2 — Concessão antes de decisão externa? | Admitir uma ficha pública de chamada/intenção quando autorizada, rotulada como preparação; uma ficha de direito atribuído exige documento da decisão competente. | Evita confundir promoção com concessão legal. Se só se admitir direito já atribuído, gate externo permanece bloqueante para publicação. |
| D-M3 — Financiamento e fornecimento com preço/condições indicativos? | Admitir indicadores identificados como propostos, com fonte/cenário/data; não marcar contrato, financiamento assegurado ou compromisso. | Mantém preparação paralela; requer revisão editorial clara. Se se exigirem termos vinculativos, a publicação aguarda esses documentos. |
| D-M4 — “Outros” genérico? | Exigir subtipo aprovado; nenhum Promotor pode dispensar gates. | Reduz contorno de categorias. Coordenação classifica a preparação sem interromper ferramentas e tarefas independentes. |
| D-S1 — Entidade sem exercícios completos? | Nova versão explícita admite entidade recém-criada com declaração de inexistência de histórico e cenário/projeções separados; nunca demonstrações fictícias. | Reconciliar mínimo de um exercício do schema atual com regra dos períodos existentes; requer novo contrato/adaptador e teste, não alteração silenciosa do original. |
| D-S2 — Unidades/urbanismo/materialidade? | Unidades/rooms/floors obrigatórios apenas nos tipos do perfil aprovado; comparar limites urbanísticos apenas com limite declarado e documento/âmbito aplicável. Mudança de título, preço, objeto, direitos, localização, perfil ou evidência relevante exige nova revisão. | Não presume limite oficial ou unidade ausente. A configuração exata por tipo e as tolerâncias de materialidade permanecem uma decisão expressa. |
| D-R1 — Perda simultânea dos dois titulares? | Preparar cerimónia de recuperação por duas pessoas independentes formalmente designadas, com identidade/MFA recuperados por procedimento existente, motivo, alerta e substituição atómica auditada. Sem designação, não existe bypass de gestor, bootstrap repetido ou terceiro superutilizador. | A substituição normal da dupla já existe. A recuperação simultânea exige política e operadores designados antes de ser habilitada; backup do schema não resolve perda de MFA. |
| Decisão | Regra proposta | Efeito se aprovada / alternativa |
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| D-M1 — Aprovar conteúdo das quatro versões e a correspondência de responsabilidades? | Aprovar a tabela como primeira versão; propor os dois titulares distintos da dupla existente como aprovadores conjuntos, nas funções de administração funcional e governance owner, com MFA, hash e data de cada ato. | Permite implementar a cerimónia de aprovação e ativação versionada, editores e gates. Até lá, os quatro rascunhos continuam recuperáveis e bloqueados para submissão. Não designa pessoas reais nem publica automaticamente. |
| D-M2 — Concessão antes de decisão externa? | Admitir uma ficha pública de chamada/intenção quando autorizada, rotulada como preparação; uma ficha de direito atribuído exige documento da decisão competente. | Evita confundir promoção com concessão legal. Se só se admitir direito já atribuído, gate externo permanece bloqueante para publicação. |
| D-M3 — Financiamento e fornecimento com preço/condições indicativos? | Admitir indicadores identificados como propostos, com fonte/cenário/data; não marcar contrato, financiamento assegurado ou compromisso. | Mantém preparação paralela; requer revisão editorial clara. Se se exigirem termos vinculativos, a publicação aguarda esses documentos. |
| D-M4 — “Outros” genérico? | Exigir subtipo aprovado; nenhum Promotor pode dispensar gates. | Reduz contorno de categorias. Coordenação classifica a preparação sem interromper ferramentas e tarefas independentes. |
| D-S1 — Entidade sem exercícios completos? | Nova versão explícita admite entidade recém-criada com declaração de inexistência de histórico e cenário/projeções separados; nunca demonstrações fictícias. | Reconciliar mínimo de um exercício do schema atual com regra dos períodos existentes; requer novo contrato/adaptador e teste, não alteração silenciosa do original. |
| D-S2 — Unidades/urbanismo/materialidade? | Unidades/rooms/floors obrigatórios apenas nos tipos do perfil aprovado; comparar limites urbanísticos apenas com limite declarado e documento/âmbito aplicável. Mudança de título, preço, objeto, direitos, localização, perfil ou evidência relevante exige nova revisão. | Não presume limite oficial ou unidade ausente. A configuração exata por tipo e as tolerâncias de materialidade permanecem uma decisão expressa. |
| D-R1 — Perda simultânea dos dois titulares? | Preparar cerimónia de recuperação por duas pessoas independentes formalmente designadas, com identidade/MFA recuperados por procedimento existente, motivo, alerta e substituição atómica auditada. Sem designação, não existe bypass de gestor, bootstrap repetido ou terceiro superutilizador. | A substituição normal da dupla já existe. A recuperação simultânea exige política e operadores designados antes de ser habilitada; backup do schema não resolve perda de MFA. |
## SLA operacional proposto — não é prazo legal
@@ -84,17 +101,17 @@ Os prazos abaixo são **propostas de compromissos internos de atendimento do por
Versão proposta `opportunity-sla-proposal-20261010-v1`. **Nenhuma data `due_at` foi preenchida por esta proposta.** Dias úteis são uma configuração a aprovar, com fuso `Africa/Maputo`, calendário e feriados explicitamente registados; não inventar calendário oficial. Relógios por tarefa, não um prazo único que bloqueia todo o percurso.
| Tarefa | Prazo proposto | Responsável funcional | Início, pausa e escalamento propostos |
| --- | ---: | --- | --- |
| Triagem e atribuição | 2 dias úteis | Validador com responsabilidade de coordenação | Começa na submissão válida. Escalar à coordenação suplente formalmente designada ao vencer; não escolher automaticamente um Validador. |
| Revisão técnica | 10 dias úteis | Validador técnico atribuído e independente | Começa na atribuição; pode correr em paralelo com jurídico. Pedido fundamentado de informação pausa somente a tarefa afetada. |
| Revisão jurídico/territorial | 10 dias úteis | Validador com responsabilidade jurídica/territorial | Mesma regra; decisão externa tem estado e relógio separados, sem prazo externo inventado. |
| Parecer interno específico | 5 dias úteis | Destinatário explicitamente designado por competência | Começa quando o pedido e evidências estão acessíveis. Parecer não aprova automaticamente o gate. Escalar à coordenação da revisão ao vencer. |
| Correção pelo Promotor | 15 dias úteis | Promotor autor ou coeditor autorizado da organização | Começa na devolução com lista concreta. Ao vencer, lembrar e permitir pedido de extensão fundamentado; sem rejeição ou arquivo automático. |
| Revisão de correção | 5 dias úteis | Validador responsável pela revisão afetada | Começa na ressubmissão; gates não afetados podem ser reutilizados só com identidade/hash e regra material demonstrados. |
| Conferência editorial e publicação | 3 dias úteis | Coordenação editorial atribui; Publicador distinto executa | Começa após aprovação interna e evidências de divulgação. Impedimento documental suspende esta tarefa; não altera aprovação para decisão externa. |
| Admissibilidade e decisão de recurso interno | 2 + 10 dias úteis | Coordenação de recurso + Validador independente dos autores/revisores/decisores prévios | Relógios separados; motivo e evidências preservados. Sem recurso decidido pelo próprio autor/decisor, mesmo com múltiplos papéis. |
| Incidente / suspensão de acesso | 1 dia útil para triagem | Coordenação e suporte com responsabilidade expressa; decisão por papel autorizado | Triagem não dá a suporte poder de aprovação. Risco concreto pode justificar suspensão auditada; alerta e próxima ação visíveis. |
| Tarefa | Prazo proposto | Responsável funcional | Início, pausa e escalamento propostos |
| -------------------------------------------- | ----------------------: | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Triagem e atribuição | 2 dias úteis | Validador com responsabilidade de coordenação | Começa na submissão válida. Escalar à coordenação suplente formalmente designada ao vencer; não escolher automaticamente um Validador. |
| Revisão técnica | 10 dias úteis | Validador técnico atribuído e independente | Começa na atribuição; pode correr em paralelo com jurídico. Pedido fundamentado de informação pausa somente a tarefa afetada. |
| Revisão jurídico/territorial | 10 dias úteis | Validador com responsabilidade jurídica/territorial | Mesma regra; decisão externa tem estado e relógio separados, sem prazo externo inventado. |
| Parecer interno específico | 5 dias úteis | Destinatário explicitamente designado por competência | Começa quando o pedido e evidências estão acessíveis. Parecer não aprova automaticamente o gate. Escalar à coordenação da revisão ao vencer. |
| Correção pelo Promotor | 15 dias úteis | Promotor autor ou coeditor autorizado da organização | Começa na devolução com lista concreta. Ao vencer, lembrar e permitir pedido de extensão fundamentado; sem rejeição ou arquivo automático. |
| Revisão de correção | 5 dias úteis | Validador responsável pela revisão afetada | Começa na ressubmissão; gates não afetados podem ser reutilizados só com identidade/hash e regra material demonstrados. |
| Conferência editorial e publicação | 3 dias úteis | Coordenação editorial atribui; Publicador distinto executa | Começa após aprovação interna e evidências de divulgação. Impedimento documental suspende esta tarefa; não altera aprovação para decisão externa. |
| Admissibilidade e decisão de recurso interno | 2 + 10 dias úteis | Coordenação de recurso + Validador independente dos autores/revisores/decisores prévios | Relógios separados; motivo e evidências preservados. Sem recurso decidido pelo próprio autor/decisor, mesmo com múltiplos papéis. |
| Incidente / suspensão de acesso | 1 dia útil para triagem | Coordenação e suporte com responsabilidade expressa; decisão por papel autorizado | Triagem não dá a suporte poder de aprovação. Risco concreto pode justificar suspensão auditada; alerta e próxima ação visíveis. |
Proposta de alerta: um lembrete ao atingir 80% do prazo e escalamento ao vencer; tolerância operacional de 1 dia útil apenas para alerta, sem alterar vencimento nem aprovação. **Sem limite automático de ciclos**: ao terceiro ciclo, revisão pela coordenação da qualidade das exigências, com continuação fundamentada. Ausência de resposta não significa aprovação, rejeição ou arquivamento. Responsabilidade suplente não equivale a pessoa fictícia.
@@ -0,0 +1,34 @@
<!-- C132-contained-20261012 -->
## C132 contido no ativo — incidente ainda aberto
Autorização específica do responsável executada: apenas `config/inertia.php`, DevTools OFF desde 12/10 18:57:15 UTC. HTTP anónimo index/detalhe real/detalhe arbitrário **404**. Login **200** e confirmação manual de **login, MFA e dashboard**. C131 não aplicado; COUNTRY02, papéis, bundle, chave/cifra, A/B e C37 preservados.
276 diagnósticos em 279 ficheiros preservados restritamente. Cookies/passwords/tokens mascarados nos exemplares retidos, mas quatro sementes TOTP e 32 códigos de recuperação correspondentes às contas 14–17 foram expostos: renovados seletivamente, obrigatoriedade MFA preservada. Zero correspondências entre os valores retidos e as credenciais atuais. Backup/restauro do destino renovado antes da resposta às credenciais, 295 tabelas/31 sequências, clone isolado 55441. Restam entrega individual das novas entradas e delimitação histórica; **não declarar fecho do incidente**.
[Relatório de contenção, alcance, período, provas e medidas restantes](C132-incidente-contido.md). Os retratos anteriores de C132 exposto abaixo são histórico anterior à contenção, não o estado atual. A matriz existente mantém os IDs; AUD-PROFILE-26 passa a parcial, sem fecho da privacidade integral.
<!-- /C132-contained-20261012 -->
# Constrangimentos atuais — 12/10/2026
Registo de apoio à matriz existente; não cria requisitos ou backlog paralelo. Fonte permanente: AGENTS.md e decisões expressas Tempo. Estados e efeitos limitados ao critério indicado.
| Constrangimento | Origem identificada | Estado/evidência | Ação concreta e efeito |
|---|---|---|---|
| QA 18118 incompleta/194 tabelas |Escolha técnica de clone de onboarding, não exigência Tempo |QA 18445 completa 295/alinhada 25 fontes+159 recursos; snapshot anterior preservado |Usar HTTPS 18445 para auditoria ampla; não alterar QA 18118 nem ativo.|
| Credenciais de actor/ambiente trocadas no controlador de ensaio |Erro do harness, não falha do portal |Correspondência privada de password/MFA/ID 17 validada; provas HTTP17/21/24/25 passaram |Reutilizar fixtures corretas; não resetar MFA nem pedir funcionários.|
| C131 validação do valor antes de normalizar |Escolha de implementação |Corrigido QA, persistência/replay/nova sessão; ativo intacto |Disponibilizar delta após critérios dirigidos/autorização; sem schema/bundle novo.|
| C132 DevTools autoriza anónimo em local |Default técnico da biblioteca/configuração, não regra Tempo |QA demonstra 200→404. Ativo por GET anónimo: 445 metadados e detalhe com utilizador autenticado/cabeçalhos/corpos; só contagens/booleanos registados. Código/config ativos intactos, exposição não corrigida no destino |Desativação explícita preparada QA; manter diagnóstico privado e histórico, sem nova restrição de negócio.|
| Novo controlo do Chromium indisponível |Dependência externa do conector: apps[]/browsers[], pipe nativo falhou |API/persistência utilizáveis;35 recibos visuais antigos íntegros |Não afirmar inspeção nova nem repetir testes encerrados; observar só critérios restantes quando controlo disponível.|
| Janela MFA 900 s de PortalProfileAccess |Escolha técnica encontrada no código; v 1 exige MFA mas não 15 min |Não foi reproduzida falha nova por expiração neste lote |Documentar opções: manter janela com retorno claro à reautenticação, ou parametrizar duração pela Tempo; não criar requisito organizacional, nem desativar MFA por contorno.|
| Exigir comprovativos externos a funcionário interno |Escolha anterior sem fundamento, superada pela decisão Tempo |Correção/administração/designações/onboarding ativos já demonstrados |Não reabrir; Aurora atua no negócio do portal, promotor real/autorização de divulgação por oportunidade preservados.|
| Dupla bootstrap/independência |Especificação de perfis e designação explícita Tempo |Contas 2/13, pessoas distintas, bootstrap consumido; três operacionais ativos |Não exigirterceira pessoa nem repetircerimónia; independência de criação/revisão/publicação mantém-se.|
| Restauração pós-publicação versus draft eliminado |Decisão de negócio concreta ainda pendente |Proposta R-ARCHIVE/R-DRAFT, sem habilitação |Publicador com motivo→revisão não pública; draft privado regra própria; nunca republicar automaticamente.|
| Quatro módulos/ofertas/competências/SLA |Decisões ainda separadas; legado não as aprovou |Gates OFF; propostas documentadas |Decidir âmbito/procura-oferta/competência/calendário responsáveis; seisbase continuam independentes.|
| ACLdocumental individual de oportunidade |Capacidade não implementada, não requisito de promotor externo |Documentos seguem ACLda oportunidade; sala de parceria tem ACLprópria comprovada |Não incluir documentos que exijam subconjunto individual/externos até implementarconcessão/revogação porficheiro; não confundirpublicação de anúncio com abertura de originais.|
|173 geometrias ainda sem correspondência |Dados/edição/pai/código; fontes oficiais aceites |408 QA,0 ativo; Mandieambíguo, nomes na tabelaexistente |Só correspondências inequívocas; não inferir proximidade nem alterar cadastro. Publicação separada.|
| Manifestação de anúncio de negócio sem fixture publicada |Pré-condição real de dados QA |3 negócios QA/0 publicados |Preparar porworkflowexistente/autorizado; depoisorigem/estatística/replay; não promover estado direto.|
| País mestre Tempo NULL |Dado legítimo ainda não preenchido, não instalação faltante |Orgúnica existente; COUNTRY02 ON |Pessoaautorizada preenchepelo fluxoexistente; preserve snapshots anteriores; não inventar país/representação.|
| Estado fresco do worker não observável pela sessão |ACLdo Agendador/ficheiro NTFS: Access Denied, diferente de scanner |Scanner PING/VERSIONdemonstrados; taskmetadata não conclusiva; instalação anterior válida |Leitura elevada agrupada só quando indispensável; não concluirworkerinativo nem consumir filaativa. Primeiro processo legítimo separado das provas QA.|
|3062 linhas sem correspondência explícita com provas |Insuficiência de auditoria, não decisão humana/genérica nem ausência automática |Matriz conservaorigem/versões/estadoanterior; 248 campos já têmprovaexata |Continuar por contrato/rota/critério com a mesma prova para todos os critérios efetivamente cobertos; não exigir teste isolado por frase. Estimar alteração após localizar lacuna.|
As decisões sobre operador, contactos Tempo, funcionários e âmbitos já foram tomadas; não criar dependências sobre elas. Disponibilidade para consulta, situação jurídica e uso em cálculo continuam independentes; fonte oficial aceite não requer recertificação.
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,7 @@
# Ensaio manual de perfis v1 — QA exclusiva
<!-- qa-installation-cartography-20261010:begin -->
## Ensaio visual futuro deste lote — contas QA, sem credenciais
Servidor exclusivo **http://127.0.0.1:18097**. Para a instalação, usar o **Superutilizador sintético QA27** já designado na dupla27/30; obter credenciais eMFA somente no ficheiro privado local. **Promotor QA21 continua a conta do dashboard, não substituí-lo por27. C37/QA18 e A/B continuam pendentes; não é pedida nova tentativa agora.**
@@ -20,6 +21,7 @@ Este roteiro não declara os passos executados. Instalação ativa e publicaçã
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Ensaio visual preparado — permanece pendente conforme pedido
URL QA **http://127.0.0.1:18097/dashboard**. Conta **Promotor QA21**, MFA normal, credenciais/código obtidos apenas localmente. Não incluir cookies, cabeçalhos X-XSRF-TOKEN, segredos ou corpo do código em capturas. C37/conta18 é um ensaio independente e continua pendente.
@@ -37,6 +39,7 @@ Registar por ação URL/ator/ID/estado/API/persistência/resultado visível; ass
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Ensaio manual atual — Promotor QA e workflow
**URL inicial exato: http://127.0.0.1:18097/dashboard. Conta: Promotor QA — conta sintética 21.** Se necessário, o login normal é `/login`, com MFA Fortify. Credenciais e códigos permanecem exclusivamente no ficheiro privado local; não os copiar para a conversa. Conferir identificação QA/porta 18097; não usar `portal-investidor.test`.
@@ -65,19 +68,19 @@ Credenciais e material MFA ficam apenas no ficheiro local privado `storage/app/p
## Contas e estado atual
| Conta QA | Estado após os ensaios |
| --- | --- |
| 20 | Público, sem criação de oportunidades |
| 21 | Promotor da organização A; autor do rascunho 15 |
| 22 | Outro Promotor autorizado da organização A; coedição |
| 23 | Promotor da organização B; acesso à oportunidade 15 negado |
| 24 | Validador revogado; conta e login MFA preservados |
| 25 | Publicador; sem edição técnica ou aprovação de rascunho |
| 26 | Auditor; leitura e exportação de metadados |
| 27 e 30 | Os dois Superutilizadores atuais |
| 28 | Titular substituído; conta preservada, administração negada |
| 29 | Terceiro aprovador do bootstrap QA; não é Superutilizador |
| 31 | Promotor + Validador + Auditor; restrição de leitura prevalece |
| Conta QA | Estado após os ensaios |
| -------- | -------------------------------------------------------------- |
| 20 | Público, sem criação de oportunidades |
| 21 | Promotor da organização A; autor do rascunho 15 |
| 22 | Outro Promotor autorizado da organização A; coedição |
| 23 | Promotor da organização B; acesso à oportunidade 15 negado |
| 24 | Validador revogado; conta e login MFA preservados |
| 25 | Publicador; sem edição técnica ou aprovação de rascunho |
| 26 | Auditor; leitura e exportação de metadados |
| 27 e 30 | Os dois Superutilizadores atuais |
| 28 | Titular substituído; conta preservada, administração negada |
| 29 | Terceiro aprovador do bootstrap QA; não é Superutilizador |
| 31 | Promotor + Validador + Auditor; restrição de leitura prevalece |
## Primeiro ensaio: Promotor, recuperação e coedição
@@ -4,14 +4,14 @@
O pedido de reabertura referia a conta esperada18. A captura manual21:22–21:24UTC demonstra que foi selecionada a conta13 restaurada. O MFA foi alcançado, mas a autenticação nunca se completou. Causa concreta: credenciais MFA da conta13 cifradas pela chave de origem, incompatíveis com a chave estávelQA; a conta18 sintética não foi desafiada nessa tentativa. Nenhuma chave, MFA ou conta13 foi alterada para contornar o problema.
| UTC09/10 | Pedido | Resultado observado |
|---|---|---|
|21:22:10|GET/investimentos|302/login; sessão convidada guardada, destino pretendido /investimentos.|
|21:22:11|GET/login|200; mesmo cookie/sessão, sem autenticação.|
|21:22:44|POST/login|302/two-factor-challenge; login.id=13, não18.|
|21:22:44|GET/two-factor-challenge|200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador.|
|21:23:04|POST/two-factor-challenge|Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada.|
|21:23:04|GET/login|200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado.|
| UTC09/10 | Pedido | Resultado observado |
| -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| 21:22:10 | GET/investimentos | 302/login; sessão convidada guardada, destino pretendido /investimentos. |
| 21:22:11 | GET/login | 200; mesmo cookie/sessão, sem autenticação. |
| 21:22:44 | POST/login | 302/two-factor-challenge; login.id=13, não18. |
| 21:22:44 | GET/two-factor-challenge | 200; desafio13 recuperado da mesma sessão; ecrã confirmado pelo utilizador. |
| 21:23:04 | POST/two-factor-challenge | Falha de desencriptação; warning correlacionado conta13;302/login, invalidação intencional e nova sessão convidada. |
| 21:23:04 | GET/login | 200; cookie aceite corresponde à sessão regenerada; sem utilizador autenticado. |
Primeiro desvio do ensaio: POST/login desafia13. Primeira falha técnica: POST/two-factor-challenge às21:23:04 (trace ec68d040a3291cb8, referência26e15b04-07b8-4211-a2a0-7f70509e03f6). Não se tratou de código MFA rejeitado pelo verificador nem de perda após autenticação. Os dois campos cifrados (secret/recovery) são incompatíveis; como nenhum corpo foi retido, não se afirma qual modalidade de entrada foi usada nesta tentativa. Não foram observados conflitos de cookies, mudança de chave/guard ou redirecionamento para outra origem.
@@ -46,12 +46,12 @@ Base exclusiva: **http://127.0.0.1:18097**. Login: http://127.0.0.1:18097/login.
Usar as contas sintéticas já preparadas na máquina, exclusivamente nesta QA. O roteiro não exporta credenciais:
| Perfil | Utilização |
| --- | --- |
| Investidor QA | Criar e recuperar A/B |
| Gestão QA | Acompanhamento e operações documentais |
| Perfil | Utilização |
| ------------------------------ | ---------------------------------------- |
| Investidor QA | Criar e recuperar A/B |
| Gestão QA | Acompanhamento e operações documentais |
| Gestão cartográfica QA com MFA | Aplicação/reversão cartográfica com TOTP |
| Outra conta QA | Verificar ausência de acesso a A/B |
| Outra conta QA | Verificar ausência de acesso a A/B |
Não executar novamente `opportunity-resources-qa.php prepare`: a instalação já foi feita nesta cópia. A preparação idempotente das contas é `php tools/portal-investor-path-qa.php fixtures`, com guarda de destino antes de qualquer escrita. O PHP QA foi recuperado num processo separado com GD/WebP e OPcache desligado apenas nesse processo; a porta18096 anterior apresentou erro de arranque antes do cabeçalho QA e não deve ser usada. Se o servidor deixar de responder, iniciar no diretório do projeto, por terminal técnico: `php -d extension=gd -d opcache.enable=0 -S 127.0.0.1:18097 -t public tools/opportunity-resources-qa.php`. Não executar este comando sobre outra configuração ou trocar o router pelo servidor ativo.
@@ -66,38 +66,38 @@ Usar títulos novos, por exemplo `A visual QA 09-10` e `B visual QA 09-10`. Não
Estes dossiers de inspeção mantêm uma evidência inicial com orçamento incompatível e uma revisão posterior válida (C29); o alerta da primeira deve permanecer explícito. Para a aceitação de criação/interface, usar os projetos novos indicados acima. Na ferramenta, preencher também pelo menos uma linha sintética de receita100 e despesa50, além dos valores do passo4, para respeitar o contrato orçamental.
| Passo | Ação na interface | Resultado esperado e prova a guardar |
| --- | --- | --- |
| 1 | Entrar como investidor; abrir `/investimentos`. Escrever título A, marcar autorização de reutilização e clicar **Criar e guardar dossier**. Repetir para B voltando à lista. | Dois IDs diferentes, títulos recuperados, cinco fases e S01–S19 em cada ficha. POST seguido de GET; registar IDs e versões. Nenhum roteiro antigo renumerado. |
| 1a | Antes de decidir aplicabilidade, terminar sessão, fechar as janelas privadas e abrir uma nova sessão autenticada QA. Recuperar A/B pela lista e URLs anotadas. | Ambos existem com os mesmos IDs/títulos/versões e sem mistura de dados; só então continuar as decisões do passo2. |
| 2 | Em A, **Precisa de terra? Não**; financiamento externo **Não**; intenção de prosseguir; fundamento sintético. **Guardar decisões**. Em B, terra **Sim**, financiamento **Sim**, fundamento distinto; guardar. | A: S10 e S13–S15 dispensados apenas da preparação; S12 não dispensado. B: ramos aplicáveis. Texto não declara licença, dispensa legal ou financiamento aprovado. Nova versão recuperada após recarregar. |
| 3 | Em B, abrir S10 → **Registar avanço ou pendência**; selecionar espera externa, ação Preparar e fundamento `Aguarda informação do terreno`. Guardar. Abrir S02, preparar análise de mercado e guardar. | S10 permanece em espera; S02 avança sem bloquear. Em S18, tentar ação Operar sem S17: mensagem de dependência real; a opção Preparar continua possível. Não inventar decisão externa para desbloquear. |
| 4 | A → **Plano e simulador**; verificar `context=ID_A` na URL. Preencher título/resumo A; na ferramenta financeira, custos fixos1000, preço100, custo variável50, necessidade total100000, capital assegurado100000, moeda MZN. Aguardar confirmação de gravação; clicar **Guardar resultado financeiro e voltar ao dossier**. Repetir B com título/resumo B e capital assegurado30000. | URLs/drafts distintos. A mostra20 unidades e necessidade0; B20 unidades e necessidade70000. Resultados com IDs/draft/versão próprios. Texto identifica estimativa, não aprovação. Recarregar ficha conserva resultado. Gravação pendente/erro não deve produzir sucesso aparente. |
| 5 | Alternar A → B → A e voltar à ferramenta pelo link de cada dossier. Abrir também `/simulador-fiscal` diretamente. | A nunca recebe título, rascunho, resultado ou estado B. A ferramenta direta conserva acesso independente e não escolhe silenciosamente outro projeto. Guardar capturas e requisições `current?context=...`. |
| 6 | Terminar sessão pelo menu; fechar todas as janelas privadas. Abrir nova janela privada, entrar novamente e abrir `/investimentos`, depois A e B pelas URLs registadas. | Recuperação do servidor: títulos, aplicabilidade, drafts, resultados e estados iguais. Este passo exige nova sessão do navegador, não apenas atualizar página. Registar a nova entrada e os GETs sem guardar cookies/passwords nas evidências. |
| 7 | Em cada ficha → **Apoio no Balcão**; escolher serviço de preparação; **Preparar pedido com dados do dossier**. Abrir o rascunho ligado. Preencher campos ainda necessários, guardar e recarregar. | Um pedido por ação/chave; associação ao dossier correto. Título e descrição reutilizados da ideia correspondente; estado rascunho, sem submissão automática. País e origem são escolhidos conscientemente, não inferidos do contexto. |
| 8 | Em cada ficha → **Acompanhamento interno**: S02, título diferente por cenário, prazo futuro, marcar aceitação e **Guardar tarefa**. | Tarefa visível na própria ficha após GET, com responsável/prazo/versão; nenhuma transmissão externa. |
| 9 | Terminar sessão; entrar como gestor; abrir URLs A/B. Introduzir fundamento, **Assumir acompanhamento**, **Iniciar tarefa**, **Registar conclusão**. | Tarefa atribuída ao gestor e concluída, com versão/eventos. Gestor vê contexto necessário à gestão, mas não entradas/resultados financeiros privados do investidor. Conferência interna aparece com esse âmbito; ato externo sem documento/entidade/data/referência é rejeitado. |
| 10 | Entrar novamente como investidor. Abrir A/B e Balcão. | Conclusão recuperada; em B, S10 ainda aguarda informação. Próxima ação e pendências visíveis. Resultado financeiro e pedido de cada projeto continuam próprios. |
| 11 | Entrar como outra conta; tentar URLs A/B e URLs dos drafts copiadas da Rede. Abrir `/investimentos`. Em sessão terminada, tentar A. | Outra conta: dossiers403, drafts404 e lista sem A/B; sessão terminada exige login/401 na API. Nenhum conteúdo privado no erro. Na conta dona, pedido para recuperar draft A com `context=ID_B` deve403, sem alteração persistente. Esta última negativa é prova de API; registar separadamente da apresentação visual. |
| Passo | Ação na interface | Resultado esperado e prova a guardar |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | Entrar como investidor; abrir `/investimentos`. Escrever título A, marcar autorização de reutilização e clicar **Criar e guardar dossier**. Repetir para B voltando à lista. | Dois IDs diferentes, títulos recuperados, cinco fases e S01–S19 em cada ficha. POST seguido de GET; registar IDs e versões. Nenhum roteiro antigo renumerado. |
| 1a | Antes de decidir aplicabilidade, terminar sessão, fechar as janelas privadas e abrir uma nova sessão autenticada QA. Recuperar A/B pela lista e URLs anotadas. | Ambos existem com os mesmos IDs/títulos/versões e sem mistura de dados; só então continuar as decisões do passo2. |
| 2 | Em A, **Precisa de terra? Não**; financiamento externo **Não**; intenção de prosseguir; fundamento sintético. **Guardar decisões**. Em B, terra **Sim**, financiamento **Sim**, fundamento distinto; guardar. | A: S10 e S13–S15 dispensados apenas da preparação; S12 não dispensado. B: ramos aplicáveis. Texto não declara licença, dispensa legal ou financiamento aprovado. Nova versão recuperada após recarregar. |
| 3 | Em B, abrir S10 → **Registar avanço ou pendência**; selecionar espera externa, ação Preparar e fundamento `Aguarda informação do terreno`. Guardar. Abrir S02, preparar análise de mercado e guardar. | S10 permanece em espera; S02 avança sem bloquear. Em S18, tentar ação Operar sem S17: mensagem de dependência real; a opção Preparar continua possível. Não inventar decisão externa para desbloquear. |
| 4 | A → **Plano e simulador**; verificar `context=ID_A` na URL. Preencher título/resumo A; na ferramenta financeira, custos fixos1000, preço100, custo variável50, necessidade total100000, capital assegurado100000, moeda MZN. Aguardar confirmação de gravação; clicar **Guardar resultado financeiro e voltar ao dossier**. Repetir B com título/resumo B e capital assegurado30000. | URLs/drafts distintos. A mostra20 unidades e necessidade0; B20 unidades e necessidade70000. Resultados com IDs/draft/versão próprios. Texto identifica estimativa, não aprovação. Recarregar ficha conserva resultado. Gravação pendente/erro não deve produzir sucesso aparente. |
| 5 | Alternar A → B → A e voltar à ferramenta pelo link de cada dossier. Abrir também `/simulador-fiscal` diretamente. | A nunca recebe título, rascunho, resultado ou estado B. A ferramenta direta conserva acesso independente e não escolhe silenciosamente outro projeto. Guardar capturas e requisições `current?context=...`. |
| 6 | Terminar sessão pelo menu; fechar todas as janelas privadas. Abrir nova janela privada, entrar novamente e abrir `/investimentos`, depois A e B pelas URLs registadas. | Recuperação do servidor: títulos, aplicabilidade, drafts, resultados e estados iguais. Este passo exige nova sessão do navegador, não apenas atualizar página. Registar a nova entrada e os GETs sem guardar cookies/passwords nas evidências. |
| 7 | Em cada ficha → **Apoio no Balcão**; escolher serviço de preparação; **Preparar pedido com dados do dossier**. Abrir o rascunho ligado. Preencher campos ainda necessários, guardar e recarregar. | Um pedido por ação/chave; associação ao dossier correto. Título e descrição reutilizados da ideia correspondente; estado rascunho, sem submissão automática. País e origem são escolhidos conscientemente, não inferidos do contexto. |
| 8 | Em cada ficha → **Acompanhamento interno**: S02, título diferente por cenário, prazo futuro, marcar aceitação e **Guardar tarefa**. | Tarefa visível na própria ficha após GET, com responsável/prazo/versão; nenhuma transmissão externa. |
| 9 | Terminar sessão; entrar como gestor; abrir URLs A/B. Introduzir fundamento, **Assumir acompanhamento**, **Iniciar tarefa**, **Registar conclusão**. | Tarefa atribuída ao gestor e concluída, com versão/eventos. Gestor vê contexto necessário à gestão, mas não entradas/resultados financeiros privados do investidor. Conferência interna aparece com esse âmbito; ato externo sem documento/entidade/data/referência é rejeitado. |
| 10 | Entrar novamente como investidor. Abrir A/B e Balcão. | Conclusão recuperada; em B, S10 ainda aguarda informação. Próxima ação e pendências visíveis. Resultado financeiro e pedido de cada projeto continuam próprios. |
| 11 | Entrar como outra conta; tentar URLs A/B e URLs dos drafts copiadas da Rede. Abrir `/investimentos`. Em sessão terminada, tentar A. | Outra conta: dossiers403, drafts404 e lista sem A/B; sessão terminada exige login/401 na API. Nenhum conteúdo privado no erro. Na conta dona, pedido para recuperar draft A com `context=ID_B` deve403, sem alteração persistente. Esta última negativa é prova de API; registar separadamente da apresentação visual. |
## País/origem por formulário, filtros e estatísticas
Em cada linha aplicável escolher país **PT** e origem declarada **ZA**, guardar/submeter segundo o contrato, recarregar e recuperar noutra sessão. Nas estatísticas, ZA é origem; PT não é inferido como origem. Registar valor ISO enviado, valor persistido e valor apresentado. Não agregar dossier/rascunho como solicitação submetida.
| Formulário/URL | Campo/significado e prova esperada |
| --- | --- |
| `/manifestar-interesse` e manifestação da página `/` | País e origem distintos; recibo único; detalhe de gestão recupera ambos. |
| `/apoio`, `/formularios/investidor`, `/formularios/empresa`, `/parcerias` (formulário de apoio) | Executar separadamente support/investor/company/partnership. Cada pedido aparece uma vez em interests; filtro `country=PT&origin=ZA` e agregado ZA aumentam1. |
| `/investidor/profile` | Residência PT; empresa com país de constituição MZ. Não inferir origem de solicitação a partir destes campos. |
| `/investidor/manifestacoes` → criar/abrir ficha | Recuperar residência/constituição; declarar origem ZA. Rascunho fora das estatísticas; submissão gera interesse com origem explícita; ausência permanece Não informado. |
| `/carteira/{ID público}` → guardar → `/investidor` | Manifestação da jornada: país/origem recuperados, repetição não duplica interesse. Usar ID disponibilizado pela própria lista QA, não ID inventado. |
| `/negocios/{slug}/manifestar-interesse` | Dois campos de país/origem; recuperar no detalhe de gestão. Prova visual do formulário/filtro/estatística ainda pendente; API/persistência/estatística deste consumidor ensaiadas em continuation-business-journey-qa.xml. Usar slug da lista QA; falta de publicação é lacuna de cadastro, não sucesso. |
| `/investidor/negocios` → novo/editar | Wizard privado: gravar/reabrir PT/ZA, filtrar lista por ambos; rascunho não conta, após submissão apenas businesses ZA+1. ZZ rejeitado sem alterar versão; outro ator não recupera. |
| `/investidor/terra-duat/novo` | País PT/origem ZA e parcela territorial; guardar/reabrir; Solicitar apoio gera um interesse. Gestor: filtro PT/ZA e estatística interests ZA+1, repetição sem duplicação. |
| `/balcao-virtual/painel` → dossier → pedido | Executar os três serviços: preparação, alteração e acompanhamento. Guardar PT/ZA, submeter, gestor devolver autorizando apenas país/origem, corrigir MZ/PT e recuperar. Estatística desk deve mover ZA→PT; não contar draft/cancelado. |
| `/simulador-fiscal?context={ID}` | Residência fiscal PT e países de origem de fundos PT/ZA; guardar/reabrir. Estes não são origem de solicitação e não criam estatística nem cálculo fiscal por gravação. |
| `/management/interests?country=PT&origin=ZA`, `/management/crm/leads?origin=ZA`, depois `origin=PT`, `origin=unknown` | Tabela/filtros/URL/contagens coerentes, coleções interests/desk/businesses separadas; utilizador comum403. Comparar antes/depois de cada formulário, não só total geral. |
| Formulário/URL | Campo/significado e prova esperada |
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/manifestar-interesse` e manifestação da página `/` | País e origem distintos; recibo único; detalhe de gestão recupera ambos. |
| `/apoio`, `/formularios/investidor`, `/formularios/empresa`, `/parcerias` (formulário de apoio) | Executar separadamente support/investor/company/partnership. Cada pedido aparece uma vez em interests; filtro `country=PT&origin=ZA` e agregado ZA aumentam1. |
| `/investidor/profile` | Residência PT; empresa com país de constituição MZ. Não inferir origem de solicitação a partir destes campos. |
| `/investidor/manifestacoes` → criar/abrir ficha | Recuperar residência/constituição; declarar origem ZA. Rascunho fora das estatísticas; submissão gera interesse com origem explícita; ausência permanece Não informado. |
| `/carteira/{ID público}` → guardar → `/investidor` | Manifestação da jornada: país/origem recuperados, repetição não duplica interesse. Usar ID disponibilizado pela própria lista QA, não ID inventado. |
| `/negocios/{slug}/manifestar-interesse` | Dois campos de país/origem; recuperar no detalhe de gestão. Prova visual do formulário/filtro/estatística ainda pendente; API/persistência/estatística deste consumidor ensaiadas em continuation-business-journey-qa.xml. Usar slug da lista QA; falta de publicação é lacuna de cadastro, não sucesso. |
| `/investidor/negocios` → novo/editar | Wizard privado: gravar/reabrir PT/ZA, filtrar lista por ambos; rascunho não conta, após submissão apenas businesses ZA+1. ZZ rejeitado sem alterar versão; outro ator não recupera. |
| `/investidor/terra-duat/novo` | País PT/origem ZA e parcela territorial; guardar/reabrir; Solicitar apoio gera um interesse. Gestor: filtro PT/ZA e estatística interests ZA+1, repetição sem duplicação. |
| `/balcao-virtual/painel` → dossier → pedido | Executar os três serviços: preparação, alteração e acompanhamento. Guardar PT/ZA, submeter, gestor devolver autorizando apenas país/origem, corrigir MZ/PT e recuperar. Estatística desk deve mover ZA→PT; não contar draft/cancelado. |
| `/simulador-fiscal?context={ID}` | Residência fiscal PT e países de origem de fundos PT/ZA; guardar/reabrir. Estes não são origem de solicitação e não criam estatística nem cálculo fiscal por gravação. |
| `/management/interests?country=PT&origin=ZA`, `/management/crm/leads?origin=ZA`, depois `origin=PT`, `origin=unknown` | Tabela/filtros/URL/contagens coerentes, coleções interests/desk/businesses separadas; utilizador comum403. Comparar antes/depois de cada formulário, não só total geral. |
## Seletores e mapas por consumidor
@@ -107,11 +107,11 @@ Consumidores a percorrer individualmente: catálogo `/oportunidades`; negócio p
Exemplos de limites oficiais presentes nesta QA:
| Nível | Nome | ID |
| --- | --- | --- |
| Nível | Nome | ID |
| --------- | ------------ | ------------------------------------ |
| Província | Cabo Delgado | 059b02ca-7095-577a-8705-4d4c46896747 |
| Distrito | ALTO MOLOCUE | 909f9937-07c1-51a2-9d7a-e2f03d586d6d |
| Posto | 7 DE ABRIL | 661be5db-dea8-5243-a281-b87e07c97a68 |
| Distrito | ALTO MOLOCUE | 909f9937-07c1-51a2-9d7a-e2f03d586d6d |
| Posto | 7 DE ABRIL | 661be5db-dea8-5243-a281-b87e07c97a68 |
Os exemplos não formam uma única cadeia: escolher os respetivos pais pelo cadastro. No endpoint `/management/territory-geometries?territory_id={ID}`, o gestor recupera limite próprio e contexto; no público `/api/v1/investment/territory-geometries?territory_id={ID}` os limites privados não aparecem. Esperado visual: território cadastrado, disponibilidade própria e contexto ancestral separados. Não publicar geometrias reais para tornar o teste verde. Uma localidade sem polígono próprio pode apresentar contexto ancestral autorizado; não declarar polígono próprio.
@@ -0,0 +1,52 @@
# Opção B - tabela única dos critérios de saída
13/10/2026. Âmbito fixado em [ambito-B-aceitacao-QA.md](ambito-B-aceitacao-QA.md), SHA-256 `7583e2f85bed065efc0d8592bdfd304144de7b8b6d390230e2ee049e45422714`. Exclusivamente QA; ativação separada. A/B e C37 mantêm os fechos.
Esta é a vista consolidada da matriz existente, não outro inventário/backlog: cada linha agrupa critérios com prova efetivamente comum. As colunas não são estados exclusivos: um grupo pode ter trabalho executável e visual bloqueado ao mesmo tempo. “Concluído” refere-se apenas ao critério e ambiente explicitados. Os históricos anteriores estão preservados em `audit-history-before-B3-20261013/saldo-opcao-B.md`.
| Critério de saída / correspondência | Concluído e evidência | Trabalho ainda executável em QA | Bloqueado por C135 | Outra dependência concreta |
| --- | --- | --- | --- | --- |
| A/B: percurso integrado nos critérios aceites<br>AUD-DESK-02 | Fecho visual preservado: criação, outra sessão, aplicabilidade, resultado no dossier correto, Balcão e tarefa paralela; 320/390 px. Referência: execucao-percurso-i 1-i 3.md e fechos aceites. | Nenhum reensaio dos mesmos critérios. Variantes não cobertas estão na linha de compatibilidade do percurso. | Não para o fecho existente. | Nenhuma; cinco fases/19 etapas preservadas. |
| C37: autenticação QA18<br> | Confirmação manual e provas anteriores de login/MFA, sessão, logout e recuperação; fecho no âmbito QA18. | Nenhum; não foi alterada a autenticação. | Não para o fecho existente. | Nenhuma; não confundir com recuperação C132. |
| Dashboard, rascunho e coedição<br>AUD-PROFILE-06, AUD-PROFILE-07 | COEDIT-GEO/WF6: dashboard → Minhas oportunidades/Nova oportunidade; rascunho recuperável e coedição base. | Promotor/coeditor: /minhas-oportunidades/{id}/edit e /resources; verificar coedição durante correção e perda de acesso após revogação no âmbito certo. | Só apresentação/erros das variantes ainda sem prova. | Reutilizar contas sintéticas existentes; sem funcionários reais ou novas nomeações. |
| Workflow e independência transversal<br>AUD-OP-03, AUD-OP-04, AUD-PROFILE-28 | WF6/MAT6/LEASE54: criar → submeter → corrigir → rever/aprovar → publicar; autor/múltiplos papéis impedidos, suspensão/republicação 31 e recurso 34 em provas próprias. | Completar somente variantes abaixo em /workflow, Promotor 21/Validador 24/Publicador 25; manter revisão apenas do âmbito alterado e historial. | Visual das variantes novas e respetiva visibilidade/estado. | 030000/040000 instaladas no clone; sem 190000 para workflow isolado. Restauração e ACL individual fora de B. |
| Projeto de investimento — 30/52<br>AUD-OP-03, AUD-OP-04 | B3 API/SQL: PDF próprio sintético, scan/hash/cifra, licença aplicável → revisão jurídica → aprovação 24/publicação restrita 25 → outra sessão. Parecer técnico preservado. option-B3-project-workflow-HTTP.json e option-B3-final-QA.json. | Conferir os pressupostos e evidências do cenário que ainda não estejam cobertos por WF6/MAT6; não repetir a licença não aplicável ou B3. | Ver documento/estado/campos novos no editor e recuperar pela interface. | Licença ensaiada é sintética, sem ato real; a condição de scan foi resolvida na QA, ver linha documental. |
| Imobiliário — venda 31 e arrendamento 54<br>AUD-OP-03, AUD-OP-04 | LEASE54: renda 4500 MZN/mês e documentos preservados em correção/revisão/publicação/recuperação; venda 31 com suspensão/republicação próprias. | Reconciliar apenas compatibilidade dos documentos/estados dos ramos incluídos em /edit, /resources e /workflow; recuperar os valores sem reensaio completo 54. | Rótulos/controlos alterados ou sem prova. | Construção/ocupação/limites urbanísticos sem percurso completo permanecem variantes excluídas, não um bloqueio do ramo aceite. |
| Direitos sobre terra — 32<br>AUD-OP-03, AUD-OP-04, AUD-GEO-02 | C140/C141 API/SQL: unidade explícita, área 1100 sem conversão, rascunho incompleto 200/submissão 422, condição antiga reverificada, aprovação 24/publicação 25/recuperação; comunidade sintética B1. | Peças próprias da consulta/encargos e medição poligonal compatível; /edit, /resources, /response, perfis 21/24/25. Não usar o PDF genérico como ata/mapa concluídos. | Unidade, erros junto aos campos, condição e mapas novos. | Documento/geometry próprios do cenário; limite administrativo não comprova parcela/direito. Mandie/Guro continua ambíguo fora da correspondência inequívoca. |
| Venda de negócio — canónico 33 e consumidor C133<br>AUD-OP-03, AUD-OP-04, AUD-BIZ-01 | 33 API: exercício existente/materialidade e maturidade 7/8 pelo workflow público. C133: interesse individual/entidade, país/origem e persistência API/SQL, sem prova de publicação do anúncio. | Mandato, promotor real e divulgação autorizada; publicar pelo consumidor próprio /negocios/{slug}, verificar interesse e recuperação. Não usar 33 para fechar C133. | C134 e visual do anúncio/interesse/pesquisa próprios. | Preparar fundamento/documento sintético correspondente em QA. Ofertas e variante modular sem histórico continuam decisões separadas. |
| Parceria de negócio — 34<br>AUD-OP-03, AUD-OP-04 | B1 API: contribuição monetária/não monetária → revisão financeira/governação, outras assinaturas preservadas → aprovação/publicação/recuperação. | Conferir obrigações e documentos dos campos incluídos ainda sem prova própria, usando /edit, /resources e /workflow. | Apresentação dos campos/decisões novos. | Sala adicional/C137 fora de B; não é requisito para publicar o contrato ensaiado. |
| Franquia — 35/56<br>AUD-OP-02, AUD-OP-03, AUD-OP-04 | C136/FR-ROY-LIC56/B-FR-EXCLUSIVITY: taxa 1250, royalties 6%, documento próprio e exclusividade; revisões afetadas, aprovação 24/publicação restrita 25/nova sessão. | Conferir a evidência de titularidade/documentos do ramo incluído e coerência da visibilidade; /edit, /resources e /workflow. Reutilizar os ensaios de royalties/licença. | Taxa, royalties, licença, exclusividade, documento e visibilidade das variantes novas. | Não inferir licença/titularidade real dos documentos QA; divulgação mantém decisão própria do processo. |
| Response: compatibilidade incluída<br>AUD-OP-03, AUD-OP-04, OP-FIELD-location-area_value, OP-FIELD-location-area_unit, OP-FIELD-parcel-area | READ248/C140/C141: IDs/versões e campos de área/unidade recuperáveis no adaptador, option-B2-response-read-HTTP.json; normative_response_complete=false. | Verificar compatibilidade dos campos alterados com os consumidores da candidata delimitada; /minhas-oportunidades/{id}/response. Não migrar os endpoints normativos por omissão. | Resultado apresentado dos campos novos. | §27 normativo integral fora de B; não anunciar conformidade total nem transformar essa evolução em pré-condição artificial. |
| País mestre da organização<br>AUD-COUNTRY-03 | COUNTRY02 e provas de país de constituição/mestre anteriores válidas; residência e origem distinguem-se. | Titular/representante: /settings/profile e cadastro mestre; testar reutilização e snapshot antigo nas variantes ainda não cobertas, preservando origem. | Formulários novos/alterados: seleção, erro e resultado recuperado. | Em QA usar entidade sintética; não inferir país real da Tempo. Nenhuma representação real é criada para demonstrar. |
| Residência, país da entidade e origem por formulário<br>AUD-COUNTRY-03, AUD-COUNTRY-04, AUD-BIZ-01 | C133 API/SQL e C138 HTTP: residênciaPortugal/origemBR recuperadas, contexto territorial e mesmo recibo no replay; país de entidade tem ramo próprio. | Completar cobertura dos ramos pertinentes em /negocios/{slug}/manifestar-interesse e /investidor/terra-duat/{id}/editar, campo → gravação → outra sessão. | C134/C138: campos, validação, recuperação e diferença semântica visíveis. | Sem inferência por IP/residência; provar o consumidor correto, não generalizar o individual para entidades. |
| Filtros e estatísticas após submissão<br>AUD-STATS-01, AUD-DASH-01 | FILTERS e C138: filtroISO PT/origemBR e coleção de origem estável na repetição; C133 tem persistência própria. | Gestor no âmbito: /management/interests; filtros/coleções de cada consumidor incluído, submissão/replay e recuperação. Conferir denominadores e critérios aplicados à coleção. | Totais, filtros e mensagens após submissão nos consumidores novos. | Estatística global não recebe filtros da listagem por semelhança; necessitam correspondência explícita. |
| Seletores/recursos territoriais de oportunidades<br>AUD-GEO-02, AUD-GEO-03, AUD-FIELD-030 | COEDIT-GEO/TR4-QA56 e C140/C141: IDs/hierarquia recuperados, guarda incompleta e área/unidade, documentos/cadastro próprios. | Promotor/coeditor: /minhas-oportunidades/{id}/resources; troca de pai limpa filhos, guardar/recuperar e medição/compatibilidade da geometria de cada caso incluído. | Selecionar e apresentar limites, ausência de geometria, legenda e teclado. | Território cadastrado, geometria disponível e apresentação são critérios distintos; lacunas oficiais não se preenchem por invenção. |
| Mapa público, carteira e filtros<br>AUD-GEO-02, AUD-GEO-03 | Pesquisa/referências/cartografia API anteriores e maturidade 7/8 HTTP válidas; exportação pública tem prova própria CSV-PUBLIC. | Público: /oportunidades?view=map, /api/v 1/investment/map e /carteira/{id}; verificar geometria/filtros/contexto, exclusão de camada/documento interno. | Desenho, legenda, mapa vazio, foco/teclado e resultado filtrado. | Não depende de concluir todas as correspondências; usar só associações inequívocas disponíveis e explicitar as ausências. |
| Território dos consumidores do dossier/Balcão/fundiário<br>AUD-GEO-02, AUD-DESK-02 | A/B e C138 preservam contexto/IDs no dossier e apoio fundiário; não são provas de todos os mapas. | Titular/analista no âmbito: /investimentos/{id}, /investidor/terra-duat/{id}/editar e /balcao-virtual/dossiers/{id}; verificar os seletores/mapas ainda sem prova própria. | Limites/ausência de geometria e seleção/recuperação por consumidor. | Sem integração externa/decisão de terra simulada como real; preparação paralela mantém-se. |
| Originais, scan, derivadas e processamento<br>AUD-OP-02, AUD-SCAN-01 | DER-QA56/provas worker anteriores; B3: PDF específico cifrado, scan real/hash, quarentena 423, replay 409/bytes duplicados 422, um original e fila alheia intacta. | Completar peças/tipos documentais dos ramos incluídos e recovery próprios; /resources/documents e documentos do Balcão/fundiário. Não repetir todos os ensaios de worker. | Estados de quarentena/scan/derivadas e apresentação WebP/PDF nos componentes afetados. | ClamD QA13310: assinaturas expiradas foram atualizadas 28150→28152, limiar 48 h intacto. Disponível agora; freshness necessária a cada scan. B3 executou só o seu handler, não novo ensaio do worker supervisionado. |
| Acesso e recuperação documental<br>AUD-OP-02, AUD-PROFILE-07, AUD-PROFILE-17, AUD-PROFILE-26 | DOC-BOUNDARY/DER-QA56 e B3: Promotor/Validador/Publicador autorizados 200, outra organização 403/anónimo 401, mesmo PDF/hash noutra sessão. | Concluir tipos e perfis dos consumidores incluídos ainda não cobertos: /resources/.../download, preview de imagens, /balcao-virtual/dossiers/{id}/documentos/{documento} e fundiário /documentos/{anexo}. | Abrir original/derivada, apresentar erros e estados com o perfil correto. | ACL individual de oportunidades continua desligada; recibo TXT e impressão do browser não são PDF servidor etiquetado. Não disponibilizar fluxo que exponha conteúdo confidencial. |
| Compatibilidade do percurso além dos critérios A/B<br>AUD-DESK-02 | B-PATH-READY: 190000 existente, 5 fases/19 etapas/13 contextos, contexto privado alheio 403; A/B integrado já fechado. | Investidor: /investimentos/{id} → ferramentas/Balcão; apenas variantes/resultados/documentos alterados ou sem cobertura, noutra sessão e sem mistura de projetos. | Variantes novas: próxima ação, contexto/retorno e estados apresentados. | 190000 já instalado em QA; CRM externo não é dependência. Não renumerar roteiros ou acrescentar barreiras de preparação. |
| Acessibilidade dos comportamentos novos<br>AUD-UI-01, AUD-PROFILE-25 | A11 Y-OP e 320/390 px já válidos no seu âmbito; C140 prepara rótulo/ajuda/erro, build preservado. | Rever marcação e corrigir defeito concreto encontrado nos controles alterados; usar rotas acima, sem repetir telas intactas. | Teclado, foco, rótulos, erro junto ao campo, leitura dos estados e móvel dos controles novos. | Dispositivos reais e acessibilidade integral têm prova distinta fora deste fecho. Nenhuma observação nova por HTML/API. |
| Candidata delimitada e recuperação correspondente<br>AUD-UI-01, AUD-DESK-02 | Types/buildB2 e 157 recursos HTTPS/hash válidos. B3 não altera fontes/bundle do produto; originais/dados/permissões/configuração ativos preservados. | Concluir os critérios abertos desta tabela, curar o bundle do âmbitoB, fixar revisão/manifesto e renovar backup/restauro QA da revisão/acervo incluídos. | A demonstração integrada dos critérios novos é condição de saída; API/hash não substituem a interface. | Revisão final ainda não fixada. Backup/restauro do destino e ativação dependem do procedimento próprio, fora desta execução. |
## Esforço ligado aos critérios restantes
**25–43 horas permanece uma estimativa de trabalho restante**, face à faixa inicial 40–72. Não corresponde a horas efetivamente consumidas, percentagem de conclusão ou prazo garantido. Mantida após esta prova; não reduzir automaticamente pelo número de casos corrigidos. Correções 5–10 h, implementação já pedida 5–10 h e verificação 15–23 h, incluindo consolidação/recuperação QA final.
As parcelas, sem somar repetidamente as linhas da tabela: perfis/coedição 2–4 h; contratos das seis categorias/Response compatível 5–8 h; países/origem/filtros/estatísticas 4–7 h; mapas/seletores 4–7 h; documentos 4–7 h; acessibilidade dos controles novos 4–5 h; compatibilidade do percurso/consolidação 2–5 h. Correspondência por linha em `option-B3-exit-criteria.json`, com as faixas originais em `option-B2-remaining-effort.json`. As parcelas somam 25–43, sem sobreposição com os 20–38 h do complemento adiado ou 76–152 h de evolução distinta. Espera C135/suporte, incidente C132, dispositivos reais e ativação não entram na estimativa.
## Novo avanço executável e dependências
Projeto 30: licença aplicável e PDF próprio **sintéticos** passaram por envio/quarentena, scan real/hash/cifra, recuperação/permissões, reabertura apenas jurídica, aprovação 24/publicação 25 restrita e outra sessão.154 tarefas anteriores preservadas; 2 novas só de 30, sem prazos. Um recurso para os mesmos bytes. Falta a observação visual; não é licença externa real nem fecho de todas as regras jurídicas. Sem alteração do código do produto, não exigiu recompilação do bundleB2.
O scanner QA13310 respondia com assinaturas de 11/10, idade 48, 09 h, ultrapassando o limite existente 48 h. Foi atualizado só o diretório QA e recarregado só esse endpoint; versão 28152/data 13/10, saúde disponível, limite inalterado. A tentativa 423 foi preservada e retomada no mesmo documento, sem repetir upload. Executado só o handler do documento próprio, fila alheia intacta; provas anteriores do worker supervisionado não são substituídas. A dependência foi resolvida emQA; a atualidade das assinaturas continua necessária a cada scan. O scanner/serviços ativos não foram alterados.
C135 mantém o diagnóstico distinto: último registo 12/10 às 23:18 UTC+2, pipe nativo ausente/os error 2 antes de selecionar o portal. Não houve novo reset, contorno ou tentativa nesta execução. Suporte preparado, sem canal ligado para envio. Critérios visuais novos continuam abertos; não se transferem sucessivamente para o proprietário.
## Estado e próximos passos
Entrada QA: **https://portal-investidor.test:18445/dashboard**. Contas sintéticas e instruções privadas locais; nenhum segredo neste relatório. A tabela apresenta 22 grupos de critérios, 2 com fecho integral no seu âmbito(A/B e C37). Os demais têm coberturas parciais claramente descritas; a quantidade não é percentagem de conclusão de requisitos.
Próximo trabalho independente: coedição em correção/revogação, mandato/divulgação no consumidor correto de negócio, país mestre/snapshots e medições/mapas dos consumidores incluídos. Não ampliar B por variantes experimentais, legado/ofertas/SLA ou §27 integral. Candidata final não fixada; renovação correspondente de backup/restauro continua pendente. Fontes/configuração/bundle/COUNTRY02 ativos intactos.
**C132, separado:** a conta 15 confirmou recebido/MFA/dashboard.14–17 recuperadas, critério individual concluído, sessões tratadas pelas provas anteriores; nenhum reenvio/rotação/novo teste de sessões. Limites da investigação histórica mantêm o incidente aberto; esta recuperação não fecha a auditoria global.
@@ -0,0 +1,162 @@
# Incorporação e reconciliação de segmentar processos
O exemplar **segmentar processos v1.docx** foi conservado e importado privadamente na biblioteca QA existente. O responsável confirmou em 11/10/2026 a identidade binária entre `segmentar processos v1(3).docx` e o nome local `segmentar processos v1.docx`. O hash local coincide com o original já incorporado. Não houve nova importação, documento, requisito ou prova funcional por causa do nome. A ressalva anterior foi retirada; a confirmação e o retrato anterior ficam conservados no histórico. As pendências funcionais e a precedência das definições aprovadas permanecem. O sufixo de nome (3) não é uma versão funcional 3.
Original: `\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\segmentar processos v1.docx`. SHA-256 **bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5**, 104147 bytes. Propriedades OOXML: criador Osman Nala, revision 15, criação 2026-10-11T10:05:00Z, alteração 2026-10-11T12:29:00Z. São propriedades do exemplar, sem inferir aprovação, autoria certificada ou vigência jurídica.
907 parágrafos, 14 tabelas, 74 secções; 0 objetos/imagens incorporados, 0 alterações acompanhadas e notas/cabeçalhos/rodapés verificados estruturalmente. Referências usam `word/document.xml#pN` e tabela/linha/célula na extração; não foram inventados números de página. Não foi produzida nem editada uma versão DOCX.
**Mesma matriz:** 3393→3401 requisitos/linhas; 39 IDs anteriores complementados, 8 IDs novos apenas para pedidos sem correspondência direta. 327 blocos de pedido deste exemplar, 894 ligações acrescentadas, 7739 ocorrências totais. Estados: 3236 parcial; 152 não implementado; 5 dependente de decisão concreta; 1 implementado mas não ativado; 7 concluído e demonstrado. Nenhum estado/critério de aceitação anterior foi alterado. 327 blocos não significam 327 novos requisitos; relações de um bloco a vários requisitos são contadas separadamente.
## Evidência do acervo QA
QA: `https://portal-investidor.test:18445`, base `stability_consumers_20261011_084534_test:55441`, guarda antes de carregar os serviços e antes de qualquer escrita. Prévia sem mutação→importação existente por gestor QA17 autorizado→ClamD real/mesmo hash→repetição sem duplicação→recuperação dos mesmos bytes. Recurso 29/documento 589ed9ac-967e-439e-9dde-b0fb3996e546, revisão/auditoria de criação 1, classificação interna, published=false. Nenhuma conta, organização, representação, oportunidade, tabela ou regra criada por este lote.
Chromium/HTTPS reconhecido: gestão mostra o exemplar, clique no download devolve o hash original, nova sessão recupera; Promotor QA21 não autorizado recebe 403, download público 29 recebe 404. Não houve publicação ou cálculo. Recibos `segmentation-reconciliation-20261011/library-preview/apply/replay-qa.json` e `segmentation-library-chromium-20261011.json`. Estes ensaios comprovam o consumidor documental, não funcionalidades futuras descritas no DOCX.
<!-- segmentation-source-date-correction -->
**Datas e histórico:** o auxiliar de importação QA tinha utilizado a data de alteração OOXML como data de emissão. Esse preenchimento foi corrigido apenas neste recurso QA: `document_date` e `issued_on` ficam indeterminados, as datas OOXML permanecem na proveniência e a revisão inicial permanece recuperável. Foi acrescentada a revisão de metadados 2 e a respetiva auditoria; o original, o hash, o scan e a classificação privada não mudaram. A repetição posterior conservou as contagens e recuperou os mesmos bytes. Evidências: `source-date-correction-qa.json` e `library-replay-qa.json`. Não se atribui esta correção de preparação de dados ao funcionamento de autenticação ou ao código do portal.
## Aliases documentais para IDs existentes
| Referência no DOCX | ID na mesma matriz | Tratamento |
| --- | --- | --- |
| INV-001 | MASTER-1f0a4cde-0001, AUD-DESK-02 | Reutilizado/complementado |
| INV-002 | AUD-DESK-01, AUD-CRM-01 | Reutilizado/complementado |
| INV-003 | AUD-SIM-01, AUD-SIM-02 | Reutilizado/complementado |
| INV-004 | AUD-MARKET-01 | Acrescentado, sem correspondência direta |
| INV-005 | AUD-FUND-01 | Acrescentado, sem correspondência direta |
| INV-006 | AUD-OP-03, AUD-PROFILE-28 | Reutilizado/complementado |
| INV-007 | AUD-CHECKLIST-01, MASTER-9dee08d0-0049 | Reutilizado/complementado |
| INV-008 | AUD-ESTABLISHMENT-01 | Acrescentado, sem correspondência direta |
| INV-009 | AUD-PROFILE-11, AUD-PROFILE-19, AUD-PROFILE-21 | Reutilizado/complementado |
| INV-010 | MASTER-e1169a77-0018 | Reutilizado/complementado |
| SOC-001 | AUD-COMPANY-01 | Acrescentado, sem correspondência direta |
| SOC-002 | AUD-COMPANY-02 | Acrescentado, sem correspondência direta |
| CAP-001 | AUD-CAPITAL-01 | Acrescentado, sem correspondência direta |
| CAP-002 | AUD-CAPITAL-02 | Acrescentado, sem correspondência direta |
## Secção para requisito, estado e próxima ação
A extração completa conserva cada pedido e o seu locator. O ficheiro JSON de correspondência é uma projeção das referências acrescentadas à matriz, sem backlog independente. Estados abaixo são os do requisito completo; provas pontuais QA não são fechos globais.
| Secção/parágrafos do exemplar | Requisitos | Estado na matriz | Próxima ação |
| --- | --- | --- | --- |
| Frontispício / p1–4 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Regra de precedência e reconciliação / p5–6 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Resumo executivo / p7–8 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Decisões pendentes / p9–10 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 1. Objectivo e âmbito da actualização / p11–12 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 1.0 Enquadramento comercial geral / p13–15 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.0.1 Artigos do Código Comercial aplicáveis à actividade empresarial / p16–87 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.0.2 Ligação do Código Comercial aos requisitos existentes / p88–140 | AUD-CHECKLIST-01, AUD-COMPANY-01, AUD-COMPANY-02, AUD-CRM-01, AUD-DESK-01, AUD-DESK-02, AUD-ESTABLISHMENT-01, AUD-LIB-01, AUD-MARKET-01, AUD-SIM-02, MASTER-1f0a4cde-0001, MASTER-9dee08d0-0049 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.1 Fronteiras do produto mínimo viável / p141–142 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 1.2 Guia do investidor e jornada de implementação / p143–147 | AUD-CHECKLIST-01, AUD-DESK-02, MASTER-1f0a4cde-0001, MASTER-9dee08d0-0049 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.3 Simulador fiscal e componente contributiva / p148–151 | AUD-SIM-01, AUD-SIM-02 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 1.4 Investimento, capitalização e mercado de capitais / p152–155 | AUD-CAPITAL-01, AUD-CAPITAL-02, AUD-OP-03, AUD-PROFILE-28 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.5 Inteligência de mercado e financiamento / p156–158 | AUD-ESTABLISHMENT-01, AUD-FUND-01, AUD-MARKET-01 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.6 Licenciamento institucional / p159–161 | AUD-CHECKLIST-01, AUD-PROFILE-11, AUD-PROFILE-19, AUD-PROFILE-21, MASTER-9dee08d0-0049 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.7 Entidades a integrar nas checklists de licenciamento / p162–170 | AUD-CHECKLIST-01, AUD-PROFILE-11, AUD-PROFILE-19, AUD-PROFILE-21, MASTER-9dee08d0-0049 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 1.8 Matriz harmonizada de entidades e autorizações / p171–224 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite. |
| 1.8.1 Fonte legal do registo e licenciamento sob competência do INTIC / p225–234 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite. |
| 1.8.2 Fontes legais das demais entidades / p235–286 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite. |
| 1.8.3 Competências e actos ainda sem prova específica / p287–332 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite. |
| 1.8.4 Validação dos links oficiais e da vigência / p333–411 | AUD-CHECKLIST-01, AUD-LIB-01, AUD-SIM-02 | parcial | Conferir artigo/âmbito/período por regra; conservar acesso/alterações/redação separados, sem reabrir fonte aceite. |
| 2. Fases de desenvolvimento do update / p412–438 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 2.1 Requisitos transversais / p439–445 | AUD-OPS-03, AUD-UI-01, MASTER-e1169a77-0018 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 2.2 Governação, planeamento e releases / p446–446 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Matriz RACI / p447–448 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Cronograma, dependências e estimativas / p449–450 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Produto mínimo viável e releases / p451–455 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| Registo de riscos / p456–457 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3. Especificação funcional do update / p458–458 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.1 Perfis de utilizador / p459–465 | AUD-PROFILE-01, AUD-PROFILE-09, AUD-PROFILE-12 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.1.1 Identidade e representação organizacional / p466–467 | AUD-PROFILE-06, AUD-PROFILE-07, AUD-PROFILE-17, AUD-PROFILE-24 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.2 Jornada digital do investidor / p468–477 | AUD-CRM-01, AUD-DESK-01, AUD-DESK-02, MASTER-1f0a4cde-0001 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.2.1 Estados e transições dos processos / p478–479 | AUD-DESK-02, AUD-PROFILE-08, V2-12 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.2.2 Formulários dinâmicos / p480–481 | AUD-CHECKLIST-01, AUD-OP-02, AUD-PROFILE-25 | implementado mas não ativado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 3.2.3 Pesquisa, comparação e transparência / p482–483 | AUD-FUND-01, AUD-MARKET-01, AUD-OP-04 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 3.3 Módulos do update / p484–484 | AUD-OP-03, AUD-PROFILE-28 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 3.3.1 Categorias harmonizadas do mercado de oportunidades / p485–515 | AUD-OP-02, AUD-OP-03, AUD-PROFILE-28 | implementado mas não ativado, parcial | Reutilizar workflow de 6 categorias/contratos, evidências e segregação; ofertas/módulos permanecem separados. |
| 4. Arquitectura funcional e modelo de dados / p516–516 | AUD-OPS-03, AUD-GEO-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 4.1 Arquitectura recomendada / p517–523 | AUD-GEO-03, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 4.1.1 Atributos de qualidade e metas de serviço / p524–525 | AUD-GEO-03, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 4.2 Entidades principais / p526–557 | AUD-GEO-03, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 4.3 Regras de dados / p558–563 | AUD-ESTABLISHMENT-01, AUD-GEO-03, RF-CRM-001 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 4.4 Taxonomias, configuração e histórico / p564–565 | AUD-CHECKLIST-01, AUD-OPS-03, AUD-PROFILE-01 | concluído e demonstrado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 5. Integrações e serviços / p566–566 | AUD-DESK-02, AUD-SIM-02, AUD-OP-03 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 5.1 Catálogo mínimo de APIs / p567–595 | AUD-DESK-02, AUD-OP-03, AUD-SIM-02 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 5.2 Integrações institucionais / p596–601 | AUD-DESK-02, AUD-PROFILE-19, V2-12 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 5.3 Contrato técnico das APIs / p602–603 | AUD-OP-02, AUD-OPS-01 | implementado mas não ativado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 6. Checklist consolidado de requisitos e execução / p604–672 | AUD-CHECKLIST-01, AUD-CRM-01, AUD-DESK-01, AUD-DESK-02, AUD-ESTABLISHMENT-01, AUD-FUND-01, AUD-MARKET-01, AUD-OP-03, AUD-OPS-01, AUD-OPS-03, AUD-PROFILE-11, AUD-PROFILE-19, AUD-PROFILE-21, AUD-PROFILE-28, AUD-SIM-01, AUD-SIM-02, MASTER-1f0a4cde-0001, MASTER-9dee08d0-0049, MASTER-e1169a77-0018 | concluído e demonstrado, não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 6.1 Pedidos específicos ligados aos requisitos existentes / p673–751 | AUD-CAPITAL-01, AUD-CAPITAL-02, AUD-CHECKLIST-01, AUD-COMPANY-01, AUD-COMPANY-02, AUD-DESK-02, AUD-ESTABLISHMENT-01, AUD-FUND-01, AUD-MARKET-01, AUD-OP-03, AUD-PROFILE-11, AUD-PROFILE-19, AUD-PROFILE-21, AUD-PROFILE-28, AUD-SIM-01, AUD-SIM-02, MASTER-1f0a4cde-0001, MASTER-9dee08d0-0049, MASTER-e1169a77-0018 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 6.2 Catálogo harmonizado para controlo do checklist / p752–774 | AUD-CHECKLIST-01, AUD-OP-02, AUD-PROFILE-08 | implementado mas não ativado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 6.3 Divergências e regras de reconciliação / p775–785 | AUD-LIB-01, AUD-OP-03, AUD-PROFILE-01 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 6.3.1 Designações canónicas ainda a confirmar / p786–792 | AUD-CHECKLIST-01, AUD-LIB-01 | parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 6.4 Definição de pronto / p793–799 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 6.5 Matriz de rastreabilidade / p800–801 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 6.5.1 Campos mínimos da matriz de rastreabilidade / p802–803 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 7. Segurança, governação e conformidade / p804–811 | AUD-OPS-01, AUD-PROFILE-23, AUD-PROFILE-26 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 7.1 Privacidade desde a concepção / p812–813 | AUD-PROFILE-26, RF-CRM-011 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 7.2 Segurança de anexos e documentos / p814–815 | AUD-LIB-02, AUD-SCAN-01 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 7.3 Governação de conteúdo e dados / p816–835 | AUD-ESTABLISHMENT-01, AUD-LIB-01, AUD-SIM-02 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 8. Migração, testes e implantação / p836–836 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 8.1 Migração de dados / p837–843 | AUD-ESTABLISHMENT-01, AUD-LIB-02 | não implementado, parcial | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 8.2 Plano de testes / p844–851 | AUD-OPS-03, AUD-PROFILE-30, AUD-UI-01 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 8.3 Estratégia de implantação / p852–858 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 8.4 Suporte, operação e adopção / p859–861 | AUD-PROFILE-20, AUD-PROFILE-22 | não implementado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 8.5 Critérios quantitativos de Go/No-Go / p862–863 | AUD-OPS-01, AUD-OPS-03 | concluído e demonstrado, parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 8.6 Indicadores de sucesso / p864–871 | MASTER-e1169a77-0018 | parcial | Reutilizar as provas existentes; executar apenas a lacuna concreta da linha da matriz. |
| 9. Conteúdo funcional: guia para escolha da forma societária / p872–872 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.0 Validação e uso do conteúdo societário / p873–875 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.1 Enquadramento das empresas e sociedades comerciais / p876–879 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.2 Tipos de empresas e sociedades comerciais / p880–890 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.3 Estatutos e contratos sociais / p891–895 | AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.4 Funcionamento de uma sociedade empresarial / p896–897 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.5 Critérios para escolher o tipo de sociedade / p898–899 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.6 Vantagens e riscos de uma sociedade / p900–903 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
| 9.6.1 Riscos e limitações / p904–907 | AUD-COMPANY-01, AUD-COMPANY-02 | não implementado | Executar incremento específico abaixo; reutilizar cadastros/serviços e demonstrar consumidor próprio. |
## Incrementos executáveis
| Incremento | Requisitos | Reutilização/progresso | Critério restante |
| --- | --- | --- | --- |
| Workflow base | AUD-OP-03, AUD-PROFILE-28 | Candidata3d9d392e0a0f: seis ramos ensaiados, materialidade, condições, recursos, mapas/filtros e9 rotas de acessibilidade. Sem code/bundle novo nesta incorporação. | 030000→040000/permissões/ClamD/processamento; 190000 só para percurso integrado. Variantes semânticas/documentais/§27 e restauro continuam delimitadas no relatório da candidata. |
| Fiscal/contributivo | AUD-SIM-01, AUD-SIM-02 | SimulationFormDrafts, SimulationTaxParameterResolver/RuleGovernance/Execution e resultados/fontes existentes; provasA/B reutilizadas. | Fechar/recolher/reabrir preservando cenários; comparar/exportar com versões e memória. INSS e cada imposto exigem parâmetros/âmbito/período identificados; indeterminado em vez de zero. Não ativar regra fiscal pela importação. |
| Negócios similares/importação | AUD-MARKET-01, AUD-ESTABLISHMENT-01 | Cadastros e serviços ExistingBusiness/MNE, organizações e cartografia mestres. Dois XLSX já constam do inventário do diretório de origem. | Inspecionar folhas/colunas, IDs, cobertura, datas e conflitos; correspondência inequívoca, rejeições e carga QA idempotente. Não converter estabelecimento observado em oportunidade. Pesquisa por raio exige geometria/coordenada real. |
| Fundos | AUD-FUND-01 | Biblioteca e parceiros/entidades como fontes; RF-CLU-005 como requisito relacionado. | Catálogo com gestor/cobertura/datas/estado/elegibilidade e explicação de correspondência. Obter os conteúdos reais; não inventar fundos ou datas e não aprovar financiamento. |
| Societário/modelos | AUD-COMPANY-01, AUD-COMPANY-02 | Organização mestre, perfil/dossier e biblioteca/revisions/links. | Perguntas e alternativas com fontes/limites; distinguir sociedade/empresário/representação/consórcio. Localizar exemplares/URLs de modelos antes de afirmar disponibilidade; conferir a redação específica, sem segunda validação oficial. |
| Capitalização/Bolsa | AUD-CAPITAL-01, AUD-CAPITAL-02 | Biblioteca, conteúdo público, dossier e encaminhamento existentes. | Guias versionados com preparação/riscos/documentos; distinguir Bolsa/Banco de Moçambique/operador; segmentos e atos específicos. Ofertas e competências modulares não são aprovadas por esta incorporação. |
| Checklists configuráveis | AUD-CHECKLIST-01 | Catálogo config/document-requirements e requisitos/formulários/tarefas/documentos do Balcão. | Editor/preview/publicação de versões; três camadas independentes(comercial/registo/licença). Manter versão da submissão. Entidade/ato/artigo/canal concreto, sem regra/SLA inventados. |
| Indicadores de utilização | MASTER-e1169a77-0018 | Eventos/auditoria/filas/tarefas existentes; estatísticas de origem são outro consumidor. | Definir denominador/eventos/período/dimensões para abandono/conclusão/tempo; não inferir investidor único de solicitações nem taxa de sucesso de investimento. Metas/calendário/responsáveis permanecem decisão operacional. |
## Divergências preservadas
- Versão anterior `segmentar processos .docx`, SHA256 `fef1f3b0835ce5e2a47ee4e7127b665c741f63d4f73a3a819b88dce2a5801b54`: §1.3 dizia compra/venda de terra; §3 listava formas/relações societárias e interpretações de responsabilidade/quotas. O v1§1.4/3.3.1/6.3/9 restringe terra às modalidades admitidas, separa empresário/sociedades/representações/consórcio e pede redação pertinente. Originais e variantes preservados; nenhuma conversão de cadastros ou adoção dessas frases como regra.
- §2 organiza releasesF0–F4; não substitui as cinco fases/19 etapas nem renumeraE0… existentes. §3.2.1 não unifica estados de domínios.
- §3.1 usa perfis genéricos; seguemRBAC/ABAC/perfisv1 existentes. Entidade externa não recebe papel ou poder por figurar no documento. Coedição organizacional previamente aprovada e demonstrada preservada.
- §3.3.1 usa agrupamentos funcionais; investimento/imobiliário/fundiário/venda/parceria/franquia mantêm códigos e contratos. Concessão/fornecimento/procura ou oferta de capital não se tornam uma categoria base nova. As ofertas e competências modulares permanecem decisões separadas.
- §6 afirma gestão básica/modelos ativos: contraposição com leitura ativa atual e exemplares/URLs concretos requerida. Ativo tem COUNTRY02 e020/050, sem 030/040/190, 0 organizações/representações e0 geometrias; workflow ampliado deste lote éQA. “Sem demonstração suficiente” não é prova de ausência de código.
- §7p811 pede validação de conteúdo institucional antes de publicação: a aceitação oficial de 08/10 tem precedência sobre credibilidade/proveniência já aceites. Conferir artigo, âmbito, período, retificação, alteração ou revogação concreta continua necessário à aplicação; não exigir nova certificação genérica.
- §§2.2/4.1.1/7.3/8.4–8.5 propõem metas/calendário/responsáveis/SLA; não são compromissos aprovados nem prazos de entidade externa. Nenhuma nomeação realizada.
## Referências legais e regras
Referências dos §§1.0.2/1.8 estão ligadas aos requisitos de checklists, perfil, comparador, fiscalidade, capitalização e admissão pertinentes. O registo `legal-reference-links.json` separa acesso declarado, alterações/revogações declaradas e redação proposta pelo exemplar. Não atribui a esta execução a pesquisa que o documento relata; nem atribui artigo/competência a regra inexistente.
Regra fiscal/contributiva: usar SimulationTaxRuleGovernance/ParameterResolver existentes somente com fonte/artigo/período/parâmetros concretos; o vínculo documental não grava nem ativa uma versão no motor. Checklist: Código Comercial/obrigações gerais, registo/publicidade e regime setorial têm efeitos independentes. BVM: admissão, supervisão e patrocínio são competências distintas. Relações ainda sem artigo específico ficam pendentes e visíveis.
Verificação técnica adicional: o [PDF do Código do Mercado de Valores Mobiliários no Banco de Moçambique](https://www.bancomoc.mz/media/bvhi3j4e/decreto-lei-4_2009_24-de-julho_aprova-o-codigo-do-mercado-de-valores-mobiliarios.pdf) foi recuperado pela ferramenta web. Os URLs do BR 229 no INTIC e do regulamento de admissão na BVM não foram recuperados nessa tentativa. Isso não revoga a aceitação das fontes nem demonstra revogação/vigência. Nenhum artigo novo foi adotado no motor.
## Candidata e condições de disponibilização
Candidata de workflow **3d9d392e0a0f**, código **df6be252f1a0**, ZIP SHA256 **6366c49d44cdc4242f4f93da5f5c1a53f2292d9eb485f70ef2b4e9a9f88589e9** preservados: nenhuma alteração de código/bundle pelas referências deste documento. Relatório, manifesto e procedimento selados não foram sobrescritos. A importação documental é um incremento de dados privado QA posterior ao backup dessa candidata e fica fora do ZIP e do ensaio de restauro de 12:10:22 UTC. Renovar snapshot/restauro se este acervo for incluído num pacote futuro.
Dependências ativas continuam concretas: atualizar/manter assinaturas ClamD 3310, demonstrar worker supervisionado, designações/perfis/representações legítimos e backup/restauro/prévias correspondentes. Para o workflow: 020→030→040 somente se ausentes por ação autenticada; 190 só quando se disponibilizar o percurso integrado. Mapas ativos exigem ativação cartográfica separada. Não foram ativados 030/040/190, importações, legado, ofertas, módulos ou SLA.
COUNTRY02 ativo e fechos A/B/C37 conservados. Contenção futura do workflow desabilita apenas as suas flags, preservando HTTPS/cookie/cifra/COUNTRY02/schema/documentos/histórico. O original desta incorporação não é publicado; eventual retirada do recurso será lógica/auditada, sem apagar bytes. Restauro integral ou eliminação de dados ativos exige decisão própria. R-ARCHIVE/R-DRAFT continuam propostas; a incorporação não decide restauração de oportunidades.
## Identidade por bytes e localizações
Foram inventariadas 10 localizações no diretório de origem: 7 conjuntos de bytes novos e 3 já conhecidos. As 3 localizações de bytes existentes foram conservadas como aliases nas entradas originais, sem outro registo de catálogo ou importação. O inventário canónico passou de 597 para 604 entradas; o inventário do diretório conserva todos os caminhos e anexos. O controlo de integridade confirmou as 597 entradas anteriores e o histórico dos 3393 requisitos anteriores.
@@ -0,0 +1,382 @@
<!-- option-B3-exit-table-20261013 -->
## Opção B: tabela única dos critérios de saída
[Tabela atual: concluído/prova, trabalho executável, C135 e dependência concreta](saldo-opcao-B.md).22 grupos, sem novos IDs ou outro backlog; A/B/C37 preservados.25–43 h estimadas restantes (5–10 correções+5–10 implementação+15–23 verificação), não horas consumidas nem prazo garantido.
Projeto 30: PDF próprio/scan real/hash, licença aplicável sintética, revisão jurídica apenas, aprovação 24/publicação 25 restrita e outra sessão; visual ainda aberto. Scanner QA13310 tinha assinaturas >48 h; atualizado só emQA, limite intacto/fila alheia preservada. Sem delta de código do produto ou recompilação. Ativo intacto; candidata final não fixada.
C132 separado:14–17 confirmadas, recuperação individual concluída; investigação histórica/limites ainda abertos. Sem envio, rotação ou alteração ativa. As secções datadas abaixo preservam o histórico; para o estado atual usar esta tabela.
<!-- /option-B3-exit-table-20261013 -->
<!-- option-B2-saldo-20261013 -->
## Opção B: saldo atualizado, C140/C141 e critérios restantes
[Saldo por critério, consumidor, bloqueio e esforço](saldo-opcao-B.md). **Restam 25–43 h técnicas**, reestimativa da faixa 40–72, separadas em 5–10 correções, 5–10 implementação pedida e 15–23 verificação. Não é percentagem de conclusão nem tempo medido; espera C135/ativação/evolução fora. B continua sem candidata final.
C140: unidade explícita da parcela guardada/recuperada emQA, sem converter área 1100; apenas cadastral reabre. C141: preparação de área/unidade incompleta guardável; submissão 422→completar par→revisões/condição preexistente→aprovação 24/publicação 25 restrita→nova sessão.148 tarefas anteriores e originais/dossiers preservados; 6 tarefas novas próprias, sem prazos. Interface nova aberta por C135, separado das falhas do produto.
A/B e C37 preservados. C132 separado:14/16/17 confirmadas, apenas 15 pendente; nenhum segredo/envio/rotação/alteração ativa. Zero alterações do portal ativo.
<!-- /option-B2-saldo-20261013 -->
<!-- option-B-first-increment-20261013 -->
## Opção B em QA: âmbito fixado e critérios novos demonstrados
[Âmbito e aceitação fixados antes da execução](ambito-B-aceitacao-QA.md). [Resultados, acessos e critérios restantes](execucao-B-QA.md). A migração 190000 já existia neste clone; habilitou-se apenas a flag QA. C138 corrigiu a repetição fundiária, 409 → 202 com o mesmo recibo, país/origem e quatro IDs recuperáveis. C139 corrigiu maturidade 7/8 na publicação e pesquisa pública, sem converter os catálogos históricos.
Variantes de licença não aplicável (30), área/comunidade sintética (32), exercício financeiro (33), contribuições (34) e exclusividade (56) passaram por gravação, reabertura apenas dos pareceres afetados, revisão independente e recuperação noutra sessão. 33 foi publicado no catálogo público QA; os outros quatro têm visibilidade restrita. Consulta pendente continuou a impedir publicação apesar da aprovação interna. Originais e 132 tarefas anteriores preservados; 16 tarefas novas destes casos, sem prazos inventados.
TypeScript/produção passaram: 159 ficheiros preparados, 157 recursos referenciados servidos por HTTPS com hashes corretos. Mesma matriz: 3.401 requisitos/linhas, 7.739 ocorrências, 27 grupos de provas; 10 requisitos de B atualizados, sem fechos visuais ou agregados. A/B e C37 preservados. Critérios visuais novos continuam abertos por C135, assim como as variantes/consumidores delimitados. Este pacote consolida **um incremento B para revisão**, não a candidata final pronta para ativação. Código/configuração/bundle ativos intactos.
**C132, separado:** conta 16 confirmou recebimento, MFA e dashboard; conta 17 já confirmada. Restam 14/15 e os limites históricos do incidente, sem reenvio, rotação ou alterações ativas nesta confirmação.
<!-- /option-B-first-increment-20261013 -->
<!-- product-three-deliveries-20261013 -->
# InvesteMoz: três entregas para decisão da Tempo
**13/10/2026. Proposta: concluir primeiro o núcleo operacional das seis categorias base, em 36–64 horas de trabalho técnico restante.** A Tempo pode incluir também o percurso integrado já ensaiado, elevando o âmbito para 40–72 horas. Concluir todos os consumidores existentes corresponde aos 60–110 anteriores. As opções abaixo delimitam trabalho; não alteram flags, permissões, dados ou funcionalidades disponíveis.
Esta é a síntese da mesma auditoria, não um novo backlog. Os IDs, referências, versões e estados da matriz permanecem. A/B e C37 conservam os fechos válidos; C132 é um incidente separado. Nenhuma implementação, ativação ou nova prova funcional foi executada nesta reorganização.
## 1. Produto utilizável agora
### Disponível no ativo, com limites conhecidos
O endereço é **https://portal-investidor.test**, local à máquina onde o Laragon está instalado. O recibo de disponibilização de 12/10 identifica a entrega `2e2f16c83483`, código `a02ef2300d6c`, com as seis categorias base abertas. Este estado prevalece sobre relatórios históricos que ainda dizem workflow OFF.
| Funcionalidade | Entrada e perfil | O que a evidência permite afirmar | Limite atual |
| --- | --- | --- | --- |
| Autenticação e administração | `/login`, `/dashboard`, `/perfis/gestao`; titulares administrativos existentes | HTTPS, MFA, sessão, acesso ao dashboard e administração têm provas anteriores. Login/MFA/dashboard foram reconfirmados manualmente após a contenção C132. | C132 ainda espera as confirmações individuais de recuperação de Aurora, Palmira e Mario; não presumir que receberam acesso recuperado. C37 é o fecho específico da conta QA18. |
| Criar e acompanhar oportunidades | `/minhas-oportunidades`, `/minhas-oportunidades/create`; Promotor no âmbito atribuído | Navegação/política de Aurora, seis tipos, guardar rascunho, recursos e submissão estão disponibilizados; correção, revisão e publicação existem para os papéis independentes. | O primeiro processo documental legítimo no destino ainda não foi observado integralmente. A prova integral abaixo é QA. Publicação pública requer divulgação autorizada no próprio processo; disponibilização restrita não prova catálogo público. |
| Revisão e publicação | `/minhas-oportunidades`; Validador e Publicador com os âmbitos já atribuídos | Políticas e filas correspondem aos papéis. Administração de segurança não concede acesso operacional universal aos anexos. | Não declarar todas as variantes de cada categoria concluídas. As lacunas concretas estão no núcleo e no quadro por categoria abaixo. |
| País de constituição — COUNTRY02 | Cadastro mestre de organização pelo fluxo existente autorizado | 050000 instalado; duas colunas; histórico e organizações preservados. 030000/040000 também estão instalados e não são uma nova dependência de preparação. | O país mestre real da Tempo permanece sem valor confirmado. Não o inferir do NUIT/contacto; o preenchimento autorizado é posterior e não exige recriar a organização. |
Referência do estado ativo: `outputs/investmoz-workflow-opening-20261012/resultado.md`, manifesto de execução, `web-enabled.json` e `navegacao-perfis-leitura.json`. A disponibilidade não é convertida numa alegação de ensaio humano integral no destino.
### Percursos integralmente demonstrados em QA que já podem ser aproveitados
| Conjunto existente | Resultado demonstrado e correspondência | Limite que permanece |
| --- | --- | --- |
| Oportunidades das seis categorias base | Casos 30–35: edição/gravação/recuperação, submissão, correção, revisão independente, condição fundamentada, aprovação, disponibilização no âmbito ensaiado e histórico. Grupos WF6/MAT6 em `proof-groups.json`; AUD-OP-03/04 e AUD-PROFILE-08/09/11/12/28. | Casos sintéticos, não todas as modalidades. Projeto, imobiliário, terra, parceria e franquia têm disponibilização restrita; venda de negócio tem prova do teaser. Terra inclui um ramo positivo de simulação expressamente identificado, não um direito atribuído. |
| Arrendamento, coedição e transições já provadas | Caso 54 preserva renda 4500 MZN/mês, três documentos, correção/revisão/publicação restrita e nova sessão. LEASE54, COEDIT-GEO; suspensão/republicação 31 e recurso 34 têm recibos próprios. | Não repetir coedição ou os percursos completos sem mudança relevante. Restauração permanece decisão separada. |
| Percurso integrado do investidor A/B | Ideia → dossier → nova sessão → aplicabilidade → ferramenta financeira → resultado no dossier correto → Balcão → acompanhamento; tarefa independente enquanto terra espera; 320/390 px nos critérios aceites. Cinco fases e 19 etapas conservadas. | 190000 e a disponibilização ativa do percurso continuam separados. A/B não encerram todas as variantes das 19 etapas ou a acessibilidade integral. |
| Agronegócio do legado | Consulta pública → artigo → autenticação somente para guardar → dossier → referência → nova sessão → artigo, confirmado manualmente. AUD-LEG-04. | Apenas piloto comprovado; integração dos restantes setores, dispositivos e acessibilidade mantêm critérios próprios. Não está incluído no pacote ativo acima. |
| Documentos dos consumidores ensaiados | Originais/scan/recuperação e PDF fundiário de três páginas apresentado no browser, com hashes e provas anteriores preservados. | WebP 56, royalties/licença 56 e retirada documental após encerramento têm API/SQL, mas apresentação nova ainda pendente. PDF enviado, impressão do browser e gerador servidor são capacidades distintas; recibo Balcão atual é TXT. |
**O conector C135 impede novas observações automáticas nesta sessão, não invalida estes percursos já observados.** Não anunciar uma demonstração ao vivo automatizada disponível enquanto o transporte estiver ausente. API/SQL recentes de C133/C136 e código compilado de C134/C137 não entram nesta lista como percursos visuais integralmente concluídos.
## 2. Essencial para concluir o produto prioritário
### Núcleo proposto: operar as seis categorias base
Saída: uma oportunidade nas variantes expressamente incluídas pode ser criada, guardada incompleta, recuperada, completada, submetida, corrigida, revista independentemente, publicada no âmbito autorizado e acompanhada. Dados territoriais, países, documentos e materialidade necessários a esse processo devem conservar-se. A aprovação interna não representa decisão externa; a ficha e a interface devem distinguir publicação restrita de catálogo público.
| Item / requisitos existentes | Correções | Implementação restante | Verificação | Total | Dependência e critério de saída |
| --- | ---: | ---: | ---: | ---: | --- |
| Perfis, conflitos e acesso — AUD-PROFILE | 1–2 h | 0 h | 1–2 h | **2–4 h** | Atribuições existentes, sem novo registo/terceiro aprovador. Verificar apenas conflitos/revogação dos âmbitos incluídos ainda sem cobertura; titular administrativo não ganha acesso universal. C132 não está nesta parcela. |
| Contratos, materialidade e workflow das seis categorias — AUD-OP-01…05; AUD-PROFILE-08/11/12/28 | 3–5 h | 5–9 h | 4–6 h | **12–20 h** | Reutilizar WF6, MAT6 e LEASE54. Incluir C131/contactos e C136/materialidade; ver só variantes alteradas ou ainda abertas. Reabrir apenas pareceres afetados, manter assinaturas históricas, impedir autoaprovação. Recuperar estado/valores/documentos após a transição. Quadro por categoria abaixo. |
| Países/origem, filtros e estatísticas dos formulários incluídos — AUD-COUNTRY-01…07; AUD-STATS; AUD-FIELD | 2–3 h | 1–3 h | 3–4 h | **6–10 h** | País mestre, residência e origem separados; reutilizar C133, sem reescrever valores antigos. Completar consumidores do núcleo e C134 se o formulário de interesse for incluído. Submissão/replay → um registo/evento → filtro/indicador correto → nova sessão. |
| Seletores/mapas do núcleo — AUD-GEO/REL/FIELD | 1–2 h | 2–4 h | 3–4 h | **6–10 h** | Usar cadastro e correspondências inequívocas existentes; UI de 56 ainda aberta. Alterar pai limpa filhos, IDs recuperados, mapa explica limite administrativo/ausência de geometria, sem apresentar limite como parcela. A importação/publicação ativa é ação futura separada; não depende de resolver todos os 173 casos. |
| Documentos privados dos fluxos incluídos — AUD-OP-02; AUD-SCAN; AUD-LIB | 2–4 h | 1–3 h | 3–5 h | **6–12 h** | ClamD/fila/derivadas existentes e provas de recuperação reutilizadas. Recuperar original e derivada autorizados, negar acesso indevido e preservar original/histórico. Se uma lacuna de confidencialidade afetar o âmbito incluído, tem de ser corrigida. ACL individual desabilitada não é apresentada como funcional. |
| Acessibilidade das rotas do núcleo — AUD-UI | 2–4 h | 0 h | 2–4 h | **4–8 h** | Provas antigas de teclado/axe/320/390 px reutilizadas; observar apenas páginas/erros/estados alterados, rótulos, foco, leitura e controlos de mapa/documentos. C135 condiciona a parte visual nova; dispositivos físicos continuam prova distinta. |
| **Núcleo, sem duplicações** | **11–20 h** | **9–19 h** | **16–25 h** | **36–64 h** | QA e candidata delimitada; instalação/intervenção ativa separadas. |
As estimativas não são requisitos novos nem garantia de corrigir variantes desconhecidas nessa faixa. Correções significam comportamento existente com falha; implementação significa completar critérios já pedidos; verificação inclui apenas cobertura em falta e reconciliação da candidata. Não se reserva um teste por frase: uma prova pode cobrir vários IDs quando coincide o consumidor, campo, perfil, transição e resultado.
### Parcela de 12–20 horas por categoria
Estas parcelas já estão na linha de workflow acima. **Não voltar a somá-las**, nem incluir nelas as horas de mapas, países, anexos comuns ou acessibilidade.
| Categoria / caso reutilizado | Lacuna essencial no âmbito proposto | Critério específico | Parcela |
| --- | --- | --- | ---: |
| Projeto de investimento — 30/52 | Licenciamento aplicável, pressupostos do cenário e materialidade da evidência aninhada ainda sem percurso completo por variante. | Alterar o dado/evidência pertinente, recuperar e reabrir só a revisão afetada; não inventar viabilidade/aprovação externa. | **2–4 h** |
| Imobiliário — venda 31/arrendamento 54 | Compatibilidade/documentos e estados do ramo incluído; provas válidas de renda/correção preservadas. | Renda/periodicidade e documentos continuam íntegros; venda e arrendamento recuperáveis. Construção/ocupação/limites sem prova integral não são declarados concluídos. | **2–3 h** |
| Direitos sobre terra — 32 | Área/unidade, comunidades e encargos nos campos/consumidores efetivamente incluídos. | Evidência aplicável preservada; ausência de ato competente impede apresentar o direito como atribuído. Mapa administrativo continua distinto da parcela. | **2–4 h** |
| Venda de negócio — 33 | Mandato, histórico e apresentação do ramo incluído; o anúncio C133 não foi publicado por esse workflow. | Promotor real e autorização de divulgação recuperáveis; revisão independente e teaser autorizado; fixture não encerra publicação legítima. | **2–3 h** |
| Parceria de negócio — 34 | Contribuições/obrigações monetárias e não monetárias do contrato existente. | Valores/documentos/estado gravados; alteração substantiva reabre apenas as revisões afetadas. A sala de negociação não substitui a oportunidade canónica. | **2–3 h** |
| Franquia — 35/56 | UI dos ramos recentes de taxa/royalties/licença e condições de titularidade/exclusividade incluídas. | Reutilizar HTTP/SQL de C136 e royalties/licença; mostrar reabertura e conservação das outras assinaturas, recuperação e visibilidade correta. | **2–3 h** |
| **Total já incluído** | | | **12–20 h** |
Response permanece um **contrato de compatibilidade**, com IDs/história preservados e `normative_response_complete=false`. Completar os campos/recuperações utilizados no núcleo cabe neste âmbito; uma migração normativa integral de identidades/metadados não cabe nas 12–20 h e continua decisão/desenho próprio. Não criar aprovação fictícia, não perder referências e não chamar conformidade integral à compatibilidade.
### Dependências reais e ordem
1. Escolher o conjunto a concluir. Não alterar o produto por uma exclusão apenas proposta nesta síntese.
2. Fechar os comportamentos incluídos de contratos/perfis; países e documentos podem avançar em paralelo. Preparar estados/documentos QA antes dos ensaios; usar as atribuições existentes, não pedir novamente funcionários ou comprovativos externos da operadora Tempo.
3. Integrar seletores/mapas dos consumidores incluídos. Casos territoriais ambíguos e geometrias ausentes mantêm aviso e nomes, sem associação automática.
4. Executar apenas os critérios visuais novos após um transporte suportado estar disponível. C135 foi separado para suporte; não reiniciar portal/serviços para o resolver nem usar um protocolo alternativo proibido.
5. Fixar a candidata, confirmar dependências e preparar backup/restauro correspondente ao destino e acervo efetivamente incluídos. O ativo já tem 030000/040000/050000; verificar presença, não reinstalar. 190000 só entra se for escolhida a disponibilização do percurso integrado. Alteração ativa mantém autorização própria.
Critério de fecho: **a pessoa conclui a atividade incluída no ambiente previsto, vê o resultado e recupera-o noutra sessão, com acessos permitidos/negados corretos**. Compilação, testes e hashes sustentam esse resultado. Uma falta de prova visual relevante mantém a candidata desse âmbito sem aceitação visual; a indisponibilidade do conector não cria uma nova regra de negócio para a Tempo.
## 3. Evolução posterior
### Complemento dos percursos existentes: 24–46 horas
Adiar estas parcelas permite terminar o núcleo isolado; conserva os pedidos no mesmo backlog. Se a Tempo optar pelo percurso integrado como primeira entrega, a linha de dossier passa para o conjunto essencial, sem repetir A/B.
| Parcela já existente | Correções | Implementação restante | Verificação | Total | Conteúdo e dependência |
| --- | ---: | ---: | ---: | ---: | --- |
| Restantes consumidores de mapas | 1–2 h | 2–3 h | 1–3 h | **4–8 h** | Zonas/carteira/parcerias/Balcão/educação fora do núcleo. Não inclui resolver 173 correspondências sem dados inequívocos. |
| Balcão/orientação/CRM adicional | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Origem/atribuições/documentos/próxima ação dos consumidores restantes. A/B já provado; sem dependência de CRM externo e sem converter TXT em PDF por omissão. |
| Negócios/salas/bolsa adicionais | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Variantes de candidatura/marcos/exportação e C137 visual. C137 não bloqueia o workflow canónico se essas salas não forem incluídas; continua pendente no seu consumidor. |
| Dossier/percurso adicional | 1–2 h | 1–3 h | 2–3 h | **4–8 h** | Variantes existentes além de A/B e compatibilidade das cinco fases/19 etapas. 190000 apenas na entrega integrada; A/B não repetido. |
| Restantes setores do legado existente | 1–2 h | 3–5 h | 2–3 h | **6–10 h** | Biblioteca/contexto/fontes únicos; Energia/Mineração distintos, Turismo sem relações geográficas inferidas, Mercado Financeiro privado enquanto sem conteúdo. |
| Acessibilidade das rotas adicionais | 1–2 h | 0 h | 1–2 h | **2–4 h** | Apenas rotas deste complemento; horas do núcleo não são contadas outra vez. |
| **Complemento, sem duplicações** | **6–12 h** | **8–17 h** | **10–17 h** | **24–46 h** | Independente da aprovação de ofertas, competências modulares e SLA. |
### Incrementos adicionais já pedidos: 76–152 horas preliminares
| Incremento do backlog existente | Estimativa | Dependência própria |
| --- | ---: | --- |
| Simulador fiscal/contributivo | **16–32 h** | Regra/artigo, período, parâmetros disponíveis e cenários; fonte oficial já aceite, sem taxas/zeros substitutos. |
| Educação: rascunhos e jornadas/painéis | **12–24 h** | Perfis/contratos próprios; novas jornadas conservam a prioridade posterior já determinada. |
| Fundos | **8–16 h** | Dados reais de janelas/elegibilidade; não inventar fundos. |
| Comparador societário e modelos | **8–16 h** | Correspondência documental/legal e parâmetros. |
| Capitalização/guião da Bolsa | **8–16 h** | Fontes/processo e condições de aplicabilidade; não representa aprovação externa. |
| Negócios similares/importação de estabelecimentos | **12–24 h** | Fonte, identidade, deduplicação e critérios próprios. O interesse existente C133 é da faixa 60–110, não deste incremento. |
| Editor/versionamento de checklists | **8–16 h** | Regras configuráveis e versões. Checklists/gates existentes do workflow não são cobrados aqui outra vez. |
| Indicadores de utilização | **4–8 h** | Métrica/denominador/apresentação próprios. Filtros e estatísticas existentes de solicitações pertencem aos 60–110. |
| **Total, baixa confiança até contrato/dados por incremento** | **76–152 h** | Não é orçamento das quatro modalidades experimentais, ofertas ou SLA. |
Restauração, ofertas de financiamento/fornecimento, competências modulares e SLA/calendário/nomeações continuam decisões separadas. A proposta pendente de restauração é Publicador autorizado, motivo e auditoria, para revisão não pública, sem republicação automática; rascunho eliminado logicamente tem regra distinta. Não bloqueiam o núcleo normal se não estiverem nele incluídos. Fontes, geometrias de localidades/parcelas ou exemplares inexistentes não recebem um prazo fictício.
## Reconciliação das estimativas
| Âmbito | Correções | Implementação restante | Verificação | Total |
| --- | ---: | ---: | ---: | ---: |
| Núcleo recomendado | 11–20 h | 9–19 h | 16–25 h | **36–64 h** |
| Complemento existente | 6–12 h | 8–17 h | 10–17 h | **24–46 h** |
| **Faixa anterior de percursos existentes, preservada** | **17–32 h** | **17–36 h** | **26–42 h** | **60–110 h** |
| Incrementos posteriores distintos | Não decompostos antes do desenho por incremento | | | **76–152 h** |
36–64 + 24–46 = **60–110**; 60–110 + 76–152 = **136–262**. Se só o núcleo for escolhido, o saldo adiado é 24–46 + 76–152 = **100–198**, não outro orçamento a acrescentar ao total. O trabalho já provado não é novamente estimado. As parcelas são distribuição de planeamento do saldo anterior, com confiança média no código conhecido e menor nas variantes não ensaiadas; não são medições de execução nem datas prometidas.
Fora destes totais: espera/reparação do conector, confirmações e investigação C132, dispositivos reais, dados/fontes ausentes, resolução de todos os 173 casos cartográficos, migração normativa integral de IDs, decisões não aprovadas, janela/intervenção de ativação no destino. Estas exclusões não encerram requisitos nem significam zero esforço; não são necessárias para operar o núcleo se não afetarem o comportamento incluído. QA/build/manifesto da candidata estão na verificação; a execução ativa e o backup/restauro do destino serão delimitados quando a revisão estiver fixada.
## Opções concretas para a Tempo
| Opção | Produto a concluir | Trabalho técnico restante | Trabalho adiado da faixa 60–110 | Efeito |
| --- | --- | ---: | ---: | --- |
| **A — Núcleo operacional, recomendado para a próxima candidata** | Seis categorias nos ramos definidos, dados/documentos privados, revisão/publicação e acompanhamento; mapas/países/acessibilidade desses consumidores. | **36–64 h** | **24–46 h** | Termina um produto operacional delimitado; não espera legado, salas adicionais, novos simuladores, restauração ou §27 integral. |
| **B — Núcleo e percurso integrado do investidor** | A + variantes existentes do dossier/percurso, com cinco fases/19 etapas; aproveita A/B e prepara a dependência 190000 apenas para essa disponibilização. | **40–72 h** | **20–38 h** | Recupera a experiência integrada como parte da primeira entrega; sem repetir A/B nem construir jornadas educativas novas. |
| **C — Todo o âmbito existente** | A + todos os consumidores do complemento, incluindo legado setorial existente. | **60–110 h** | **0 h** | Mais cobertura transversal antes da candidata; ainda não inclui os incrementos posteriores 76–152. |
Redução adicional dentro de A só é concreta depois de a Tempo escolher as categorias/modalidades a excluir: não subtrair horas arbitrariamente nem retirar controlos essenciais de confidencialidade, independência ou gravação. Corrigir C136 e validar os critérios visualmente afetados não é dispensável numa entrega que inclua franquia. Pode-se adiar §27 integral, restauração, camadas não resolvidas e variantes imobiliárias não demonstradas sem converter isso em bloqueio de cadastro de rascunhos.
**Decisão solicitada: A, B ou C como âmbito da próxima candidata.** Nenhum pedido anterior é cancelado por esta escolha; o restante mantém o seu ID, referência e critério no backlog. Até à escolha, não se inicia uma expansão de desenvolvimento por conta desta síntese.
## C135: encaminhamento para suporte, separado do portal
Pedido sanitizado preparado em `C135-pedido-suporte.md`. Falha já registada: transporte IPC nativo ausente (`os error 2`), inventário apps/browsers vazio e `Browser is not available: iab`, antes de selecionar uma janela. Resets/importação documentados já falharam; não repetidos. Não foi estabelecida a causa específica no host.
**Estado do envio: não submetido.** Não há ferramenta/canal de suporte ligado que permita enviar o pedido nesta sessão. O canal oficial é feedback no compositor através de `/`; a documentação também identifica o reporte de problemas. [OpenAI Docs — Feedback and logs](https://learn.chatgpt.com/docs/reference/troubleshooting#feedback-and-logs). O texto pronto permite uma única entrega ao suporte, sem segredos nem o histórico integral da conversa. Não foi aberto um ticket fictício nem contornada a restrição da ferramenta. Alternativa de teste só será usada se estiver realmente disponível e permitida.
Sete grupos visuais novos continuam abertos: C131/contactos, C134/interesse, C137/retirada após encerramento, seletores/mapa 56, WebP 56, royalties 56 e licença 56. Cada opção inclui apenas os grupos que pertencem ao seu âmbito; os restantes não desaparecem da matriz.
<!-- /product-three-deliveries-20261013 -->
<!-- module-exit-synthesis-PDF-C137-20261012 -->
# InvesteMoz: saldo de fecho por módulo
**A medida de conclusão passa a ser o percurso/variante e o resultado recuperável.** As3.401 linhas da matriz e7.739 ocorrências documentais não representam esse número de funcionalidades por construir. Mantém-se uma única matriz/backlog, com histórico e referências. Este saldo distingue provas funcionais, preparação de código, critérios visuais e disponibilidade ativa.
## O que já se pode conservar como concluído
- **A/B:** criação, gravação, nova sessão, aplicabilidade, resultado financeiro no dossier correto, preparação de apoio, acompanhamento e tarefa independente enquanto a terra espera; apresentação320/390px nos critérios aceites. Não repetir.
- **C37:** autenticação QA18, MFA, sessão/logout/recuperação confirmados no âmbito específico. Não repetir.
- **Oportunidades:** seis casos base30–35 e arrendamento54 têm correção, revisão/aprovação independente, disponibilização no âmbito ensaiado e recuperação. Renda4500MZN/monthly preservada. Coedição15/22, suspensão/republicação31 e recurso34 têm recibos próprios.
- **Países:** catálogo ISO comum; residência/constituição/origem separados nos percursos provados. C133 confirmou submissão/recibo/replay/origem/filtros/estatísticas do consumidor de negócios por HTTP/SQL, preservando “Moçambique”. C134 ainda visual.
- **Cartografia:** API hierárquica integral e mapas de recursos anteriores conservam prova;408 geometrias internas QA e quatro níveis de56 guardados/recuperados. A disponibilidade da geometria não é apresentação em todos os mapas.
- **Documentos:** scans reais, originais/derivadas, limites/recuperação e falha/replay de worker nos ensaios anteriores; PDF fundiário de3páginas gerado pelo navegador, apresentado/scaneado e com hash agora reconferido. Revogação nos consumidores ensaiados não encerra ACL individual de todo o portal.
- **Legado:** agronegócio público→autenticação só ao guardar→dossier→referência→nova sessão→artigo, confirmado manualmente. Energia/Mineração distintos e Mercado Financeiro privado.
Há sete IDs agregados fechados apenas em QA nos seus critérios: AUD-COUNTRY-05, AUD-GEO-04, AUD-LEG-04, AUD-OPS-02/03, AUD-PROFILE-27 e AUD-STYLE-01. **Não são sete módulos totalmente concluídos.** Outros requisitos parciais contêm muitos critérios já válidos, como os seis workflows; não os desconsiderar por causa do estado agregado.
## Síntese desde o início da auditoria
Estimativas de trabalho técnico restante, incluindo implementação localizada, ensaios e reconciliação. Confiança média nos percursos existentes; baixa nos incrementos ainda ausentes. São horas de trabalho, não prazos de atendimento/SLA nem datas de entrega. As faixas não incluem espera pelo conector, decisões ou dados inexistentes. Não somar duas vezes horas de documentos/Balcão/parcerias.
| Módulo / IDs existentes | Critérios efetivamente demonstrados | Critérios pendentes e bloqueio concreto | Saída objetiva | Esforço restante |
| --- | --- | --- | --- | --- |
| Autenticação, perfis, dashboard — AUD-PROFILE, AUD-DASH | C37; bootstrap cruzado/onboarding, atribuições segregadas; coedição/negações no âmbito ensaiado. HTTPS/COUNTRY02/perfis disponibilizados no ativo conforme recibos anteriores. | Restam variantes de conflito, revogação/substituição/recuperação não cobertas. C132 espera3confirmações e permanece incidente separado. Funcionários/Tempo já registados; não reabrir essa dependência. | Acesso permitido/negado e revogação nos estados ainda sem prova, preservando histórico e titularidade. | **2–4h**, fora C132 e recuperação C135. |
| Oportunidades/workflow — AUD-OP-01…05, AUD-PROFILE-08/11/12/28 | Seis categorias/arrendamento; coedição; condições; independência; C136/taxa inicial. Novo lote: royalties e substituição de licença viaHTTP/SQL com conservação de assinaturas não afetadas. | UI nova depende de C135. Restam licenças/viabilidade de projeto; variantes imobiliárias indisponíveis; comunidades/área de terra; mandatos/histórico de negócios; contribuições de parceria; exclusividade/titularidade de franquia; maturidade7/8 no consumo público. §27 normativo não é completo: IDs/referências/história conservados. Restauração é decisão distinta, não bloqueia workflow normal. | Cada variante incluída: editar→submeter→revisão afetada→aprovação independente→visibilidade prevista→nova sessão. Excluir claramente variantes não prontas. | **12–20h** para variantes existentes delimitadas/compatibilidade; não inclui transformação normativa de IDs ou módulos não aprovados. |
| 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. |
| 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. |
| Educação — AUD-EDU | Consultas/procura-capacidade existentes, com alcance histórico delimitado. | Rascunho incompleto e jornadas/painéis por ator ausentes. Desenvolvimento de novas jornadas continua condicionado à prioridade das falhas existentes, conforme instrução Tempo. | Rascunho incompleto recuperável, permissões e painel por ator; seletores/capacidade apresentados no seu consumidor. | **12–24h preliminares** para o incremento descrito, após prioridades; fora60–110h. |
| Legado — AUD-LEG/LIB | Piloto agronegócio confirmado; inventário92URLs/50versões; biblioteca/contexto reutilizados. | Conteúdos/imagens/anexos/links/setores ainda sem prova; Mercado Financeiro sem corpo, privado. Móvel/acessibilidade por setor; sem associação territorial automática de Turismo. | Consulta pública/contexto/dossier/recuperação e ficheiros/links íntegros por setor existente. | **6–10h** conteúdo existente; acervo ausente/novos conteúdos excluídos. |
| Fundos/societário/capitalização/negócios similares/importação/checklists/uso — IDs AUD correspondentes e referências de segmentar processosv1 | Documento/versão/hash/alias incorporados; configuradores/serviços comuns identificados. | Incrementos funcionais ainda ausentes ou não demonstrados. Fundos precisam de dados de janelas/elegibilidade; comparador e guião precisam da correspondência documental; checklists precisam de editor/versionamento; indicadores sem métrica/apresentação demonstradas. Ofertas/competências modulares/SLA são decisões separadas. | Versão QA por incremento com contrato/dados/origem/ações/permissões e saída recuperável; não inventar entidades, taxas ou critérios. | **48–96h preliminares**, decompostos abaixo; fora60–110h. |
| Acessibilidade — AUD-UI e consumidores | Teclado/axe/320/390px nas rotas ensaiadas e PDF fundiário visual anterior; esses fechos conservados. | Visuais novos dependem de C135; leitores de ecrã, rotas restantes, documentos etiquetados e dispositivos físicos têm critérios próprios. | Teclado/foco/rótulos/erros/estados e leitura nas rotas incluídas; prova de dispositivo real separada. | **6–12h** rotas incluídas, após conector; equipamento/espera não incluídos. |
## Quanto falta: orçamento e limites
**Percursos existentes e variantes já delimitadas:60–110h.** Soma sem duplicações: perfis2–4 + oportunidades12–20 + países6–10 + mapas10–18 + documentos/Balcão/parcerias14–28 + dossier4–8 + legado6–10 + acessibilidade6–12. Esta faixa foi apresentada antes de ampliar o lote e conserva o mesmo âmbito. As provas novas removem incerteza de execução nos dois ramos da franquia e na revogação; ainda não removem os critérios visuais ou de outros consumidores, pelo que não se subtrai simplesmente o número de testes/horas decorridas.
**Pedidos adicionais já registados, ainda ausentes/parciais:76–152h de orçamento preliminar**, com confiança baixa até confrontar cada contrato/dado: fiscal/contributivo16–32; educação12–24; fundos8–16; comparador/modelos8–16; capitalização/guião8–16; negócios similares/importação12–24; editor/checklists8–16; indicadores4–8. As seis últimas parcelas somam48–96h. Componentes reutilizáveis: biblioteca/metadados/fontes, formulários/rascunhos, organizações/perfis, cartografia, regras de aplicabilidade, CRM interno e resultados no dossier. Não são novas identidades/tabelas paralelas.
**Orçamento de planeamento do âmbito acima:136–262h**, cerca de17–33dias de8h de trabalho técnico. Não é uma data de fecho global nem compromisso operacional. Os incrementos preliminares precisam de desenho/critério por versão; se surgir variante substancial fora dessas premissas, estimar o delta antes de executar. São excluídos do total: espera/intervenção do conector; fontes/exemplares/parâmetros inexistentes; solução de todos os173casos cartográficos sem correspondência; decisões ainda não tomadas sobre restauração, ofertas/competências/SLA; migração normativa de identidades e processos externos reais; ativação e janela de intervenção no destino. Estas exclusões não equivalem a zero trabalho nem a fecho dos pedidos.
Medidas concretas de saldo:46ocorrências históricas de campos em29componentes, não46módulos;519propriedades do schema e248campos recuperados emGET não demonstram todoCreate/Patch;19etapas/cinco fases permanecem rastreadas, mas dois cenáriosA/B não encerram todas as variantes. As contagens de requisitos/grupos são rastreabilidade, não percentagem do produto concluído.
## O que impede fechar e o que pode avançar
1. **C135 técnico:** clientes nativo e browser reinicializados; nativepipe os error2, inventário vazio e IAB indisponível persistem. Não há API exposta para reparar/iniciar o helper no host. A [skill Computer Use](C:/Users/macbook/.codex/plugins/cache/openai-bundled/computer-use/26.1007.21434/skills/computer-use/SKILL.md) diz: “Do not spawn `codex-computer-use.exe`, search for the helper executable, or build a custom helper protocol client.” A recuperação documentada foi tentada; o host tem de voltar a disponibilizar o transporte/helper/provider suportados. Não reiniciar Apache/BD/scanner nem pedir novas tentativas de login. Causa específica além do IPC ausente não estabelecida. Critérios visuais abertos.
2. **Dados:** country master realNULL, geometria de localidades/parcelas ausente e173correspondências não resolvidas; manter explícitos. Importar apenas correspondências inequívocas com a fonte já aceite; relações ambíguas não bloqueiam os consumidores independentes.
3. **Decisões Tempo já pendentes:** R-ARCHIVE/Publicador com motivo→revisão não pública e R-DRAFT distinta; modalidades de oferta versus procura, responsabilidades modulares e SLA/calendário/responsáveis; §27estrito versus contrato de compatibilidade preservandoIDs. Não aplicar por conveniência nem condicionar os seis workflows normais a estas decisões independentes.
4. **Ativo:** funcionamento legítimo com dados/documentos reais e autorização de divulgação é distinto dos ensaios sintéticos. COUNTRY02 ativo e pacote/perfis existentes preservados; este lote não autoriza alterações. C132 aguarda as confirmações14–16 e investigação histórica própria, sem bloquear este trabalho QA.
Para delimitar a próxima candidata utilizável, conservar os ramos completos e excluir variantes acima. **Sete grupos de prova visual novos** permanecem: C131/contactos; C134/formulário de interesse; C137/retirada após encerrar; seleção/mapa de56; apresentação WebP56; royalties56; licença56. Não são sete requisitos ou todo o portal. Depois dessas provas e das lacunas efetivamente incluídas, fixar revisão, conferir dependências030000/040000 e renovar backup/restauro correspondente.190000 entra só no percurso integrado; não artificialmente no workflow isolado.
## Lote executado agora
| Item | Rota/perfil | Resultado e evidência | Critério que continua aberto |
| --- | --- | --- | --- |
| Exportações | `/api/v1/investment/export`; `/api/v2/investment/zones/export.csv`; público | CSV8/11colunas e8linhas de cada conjunto; UTF8/BOM; filtro positivo e replay idêntico; oportunidade interna56 excluída. `next-exports-HTTP.json`. | Botão/UI e demais combinações/limites grandes; não declara todas as exportações concluídas. |
| Royalties/licença | `/minhas-oportunidades/56/edit`, `/workflow`, `/view`, `/resources/documents/{id}/download`; QA21→24→25 | Royalties reabre3gates, licença2; restantes hash/ator/data conservados; aprovação422 antes das revisões; reaprovação24/publicação interna25/nova sessão. PDF próprio clean/hash/MIME e licençaUUIDpreservados. `franchise-variant-royalties/license-HTTP.json`, `next-lot-final-SQL.json`. | UI, exclusividade/titularidade e publicação pública; §27integral. |
| Revogação | `/parcerias/salas/2/documentos/4` e`/partilha`; autor21/participante23/não participante22 | PDF200 antes→sala cancelada→autor retira→sessão antiga/nova404; autor200/hash; regrant409, não autor403, anónimo401. Repetição mantém1original; sala1/anexos intactos. `partnership-revocation-closed-room-revocation-HTTP.json`. | C137UI e restantes variantes de sala; não é ACL individual da oportunidade. |
| C137 | Componente `partnerships/room`, autor do documento | GuardaUI `mutable` ocultava retirada após encerramento emboraAPIpermitisse. Ajustado apenasQA para permitir retirar partilha existente ao autor e manter novas partilhas indisponíveis. TypeScript/build passaram,159assets; novo chunk servido200/hash; manifestoQA87e77091835f… e anteriorcf78… preservados. | Clique/resultado visual com estado adequado; código compilado não encerra o critério. |
| PDF anterior | Impressão fundiária no browser, âmbitoQA anterior | Reutilizado PDF3páginas/hash0676c5f7… com prova visual/scan anteriores e bytes atuais conferidos. PDF sintético1977bytes deste lote é entrada de teste, **não um novo gerador do portal**. | Geradores/templates/PDFs etiquetados e consumidores restantes. ReciboBalcão continuaTXT; não foi convertido silenciosamente. |
Oito requisitos existentes atualizados; zero novosIDs;19grupos de provas com correspondências/limites explícitos. Nenhum fecho visual ou agregado novo. Fontes/configuração/bundle ativos conferidos por hash e intactos. Alteração deste lote é umaTSXna cópiaQA e159assets compilados, com originais/manifesto anterior privados e assets antigos preservados. Reversão técnicaQA deste delta: fonte anterior e manifestoQAanterior, mantendoPDFs,IDs,história e partilha revogada; nunca reautorizar destinatários como reversão. Algoritmov4da materialidade permanece, comv2/v3preservados. Não é pacote pronto para ativação.
<!-- /module-exit-synthesis-PDF-C137-20261012 -->
<!-- consumer-QA-C135-C136-20261012 -->
## Lote QA de seletores, derivadas e variante financeira da franquia
**Nenhuma alteração no ativo.** A/B e C37 mantêm os fechos próprios. C133 conserva a prova API/SQL; C134 permanece compilado em QA, com interação visual pendente. C132 fica separado: conta17 recuperada, confirmações individuais14–16 ainda pendentes. Nenhum email ou segredo foi reenviado neste lote.
O lote atualiza nove requisitos existentes, sem novos IDs: AUD-FIELD-030, AUD-GEO-02/03, AUD-OP-02/03/04, AUD-SCAN-01, AUD-UI-01 e AUD-PROFILE-28. A matriz tem **3.401 requisitos/linhas e 7.739 ocorrências de origem**:3060 sem evidência suficiente,318 parciais,6 decisões Tempo,1 falha,7 demonstrados apenas em QA e9 não implementados. Nenhum requisito agregado ou critério visual foi encerrado por este lote.
### Evidência nova e critérios restantes
Base QA: **https://portal-investidor.test:18445**, PostgreSQL `stability_consumers_20261011_084534_test:55441`. O cabeçalho QA foi conferido em cada resposta; as leituras SQL finais ocorreram em transação READ ONLY. QA56 é uma oportunidade sintética, com documentação identificada como simulação sem validade jurídica.
| Item e requisito | Rota, perfil e ação | Demonstrado neste lote | Critério restante e evidência necessária |
| --- | --- | --- | --- |
| Hierarquia — AUD-FIELD-030/AUD-GEO-02 | `/minhas-oportunidades/56/resources`; Promotor21 guarda, nova sessão recupera. APIs `/minhas-oportunidades/territory-options` e `POST /minhas-oportunidades/56/resources/locations`. | Cabo Delgado→Ancuabe/distrito→Ancuabe/posto→Ancuabe-Sede/localidade: quatro IDs recuperados; pai de nível errado422 e país PT com território MZ422. | Mostrar seleção, troca de pai/país, limpeza dos filhos e erros adjacentes a1440/390px; captura e resultado após guardar. A API não demonstra os cliques nem a limpeza na interface. |
| Limites — AUD-GEO-03 | `/minhas-oportunidades/territory-geometries?territory_id={UUID}`; perfil autorizado. Consulta pública `/api/v1/investment/territory-geometries`. | Província/distrito/posto: geometria INE disponível, contextos1/2/3. Localidade cadastrada sem geometria própria, recebe só três limites ancestrais; `investment_site=false`. Camadas internas não expostas na consulta pública:0. | Mapa deve distinguir limite administrativo de local de investimento e ausência de limite da localidade. Captura/legenda/teclado/zoom em cada consumidor ainda aberto;173 correspondências e Mandie/Guro mantidos. Sem novas importações ou publicações. |
| Original/derivadas — AUD-OP-02/AUD-SCAN-01 | `POST /minhas-oportunidades/56/resources/images`; `POST /minhas-oportunidades/56/resources/images/{imagem}/prepare`; `GET .../download` e `GET .../preview/{documento}`. Autor21/coeditor22/Validador24/Publicador25; outra organização23/anónimo. | Upload→quarentena423→job do scan real ClamD1.5.4→original limpo→WebP320/640/1280→scan próprio→download200/hashes→nova sessão. Replay conserva IDs, versão2 e um evento derivatives_prepared. Outraorg403/anónimo401, incluindo URL assinada. Bytes cifrados e original preservados. | Apresentação visual da imagem/WebP e erros; outros formatos/PDFs/consumidores não cobertos. Os jobs tratados pertencem só a56: não foi um novo ensaio do worker nem consumo da fila alheia. Reutilizar os recibos prévios de interrupção/replay. |
| Response de recursos — AUD-OP-04 | `GET /minhas-oportunidades/56/response`; Promotor e perfis no âmbito. | IDs de localização/imagem, SHA original e autor21 recuperados no contrato ligado aos recursos. | §27 integral continua `normative_response_complete=false`: IDs bigint/referência histórica, metadata desconhecida e pareceres paralelos não são convertidos. Novas variantes exigem campos/IDs/metadata específicos; não se declara conformidade global. |
| C136, franquia — AUD-OP-03/04/AUD-PROFILE-28 | `/minhas-oportunidades/56/edit`, `PUT .../draft`, `POST .../workflow`, `GET .../view`; Promotor21→Validador24→Publicador25, MFA próprio em sessões normais. | Submissão/aprovação independente; taxa inicial1000→1250; nova submissão reabre marca/licença, legal da franquia e financeiro, conserva confidencialidade/hash/ator/data. Aprovação422 antes das revisões;24 reaprova e25 disponibiliza internamente. Nova sessão recupera taxa/estado. Autor não autoaprova403. | Interface da variante, royalties viaHTTP/UI e restantes variantes abaixo. Esta publicação usa o workflow real em QA, mas é **restrita**, não prova catálogo público. O anúncio do lote C133 continua fixture e não é substituído por esta franquia. |
| C135, conector — AUD-UI-01 | Inventários suportados de apps e navegador, antes de qualquer seleção/input. | Chromium1243 está em execução; pipe nativo ausente, os error2; inventário apps/browsers vazio. Primeiro ponto de falha é IPC. | Repor o transporte do conector no host e obter inventário QA antes de retomar os visuais novos. Processo específico/causa além do IPC ausente não determinados. Não há prova de falha do Chrome ou do portal; sem contorno de protocolos e sem pedir novos testes repetidos ao utilizador. |
**C136 — causa e correção:** a projeção v3 de `financial_review` não incluía `business_transaction.franchise_terms.initial_fee` nem `royalties`. A alteração podia conservar um parecer financeiro desatualizado. Apenas em QA, a projeção v4 incorpora esses dois campos já existentes. As regras históricas v2/v3 continuam verificadas pelo respetivo algoritmo, preservando assinaturas/ator/data; não se recalculam assinaturas silenciosamente. Antes/depois foram reproduzidos em memória e a taxa inicial foi depois demonstrada pelo HTTP/SQL normal. Royalties passou a regressão do serviço, não uma transição HTTP ou interface. O ficheiro ativo conserva o hash anterior; não foi corrigido por este lote.
**Limites da execução:** não se repetiram os seis percursos visuais base, arrendamento54, coedição15, suspensão/republicação31 ou recurso34. O novo caso56 é necessário para a falha financeira recém-identificada e não altera os casos anteriores. Dois erros de leitura de propriedades no harness foram corrigidos e os pedidos válidos aproveitados, sem criar oportunidades repetidas; não são falhas do portal. Só a disponibilização final foi retomada depois da aprovação já válida, sem a repetir.
Os critérios restantes por consumidor/categoria constam de consumidores-restantes.md e workflow-criterios-saida-20261011.md. Demais estados dos módulos e evidências abaixo preservados.
<!-- /consumer-QA-C135-C136-20261012 -->
<!-- independent-QA-C133-C134-20261012 -->
## Lote independente em QA — países e origem em interesses de negócios
**Ativo intacto.** C132 mantém as três confirmações de acesso pendentes; isso não bloqueou este lote. C131 HTTP/persistência já provados foram reutilizados; não se repetiram A/B ou C37.
| Caso / requisitos | Resultado | Estado |
|---|---|---|
| C133 — AUD-COUNTRY-03/04, AUD-STATS-01, AUD-FIELD-014 | O filtro por MZ omitia o país anterior “Moçambique”, apesar de gravação/recuperação corretas. Em QA, o catálogo comum fornece nomes ISO/PT/EN com correspondência única para consulta; o valor guardado e a origem BR permanecem intactos. | API/persistência demonstradas em QA; não ativado. |
| Interesse no negócio sintético | Forma pública200/catálogo249 → POST201 → gravação → replay201 com referência idêntica → nova sessão de gestão → recuperação/filtro. ISO MZ e origem BR separados; origem ausente mantém não informado; país/origem inválidos422; dados diferentes na mesma chave409; leitura anónima401 e Promotor sem gestão403. SQL confirma um recibo/evento/consentimento por registo e outbox não consumido. | HTTP e SQL demonstrados; interação visual pendente. |
| C134 — AUD-FIELD-014, AUD-UI-01 | Formulário lançava só mensagem global, ignorando errors por campo da API. Componente QA liga erros a inputs/seletores, descrição acessível e foco ao primeiro erro, preservando valores e chave. TypeScript/build passaram; novo chunk HTTPS servido com hash exato. | Código compilado e servido QA; foco/apresentação ainda não demonstrados. |
**Limites concretos:** não se declarou cobertura do país de constituição, dos outros formulários nem da acessibilidade integral. O anúncio é uma fixture sintética para testar este consumidor: rascunho criado pelo serviço existente, estado publicado preparado; não é prova da revisão/publicação pelo workflow. O critério de preparação/publicação operacional pelo fluxo existente continua aberto. Tentativas de harness com email reservado sem MX e leitura Windows sem UTF-8 ficaram separadas das falhas do portal; o registo sintético inicial foi preservado, não reescrito.
**Navegador:** Chromium local em execução, mas list_apps falhou por pipe nativo inexistente (os error2); cua.getState devolveu apps/browsers vazios. Nenhuma captura ou confirmação visual inventada. Não se pediu ao utilizador para repetir percursos válidos.
**Próximo trabalho executável:** seletores/mapas dos consumidores restantes, derivados/permissões documentais e semântica/materialidade/Response§27 das variantes ainda identificadas. As ofertas, competências modulares, SLA, restauração e partilha individual conservam as decisões/gates próprios. País mestre da Tempo não será inferido nem gravado no ativo por este lote.
Provas no diretório da auditoria: business-country-before/after/variants/persistence; country-filter-QA-delta; business-feedback-QA-delta/build-QA/assets. Atualizados somente cinco requisitos existentes; nenhum novo ID de requisito ou backlog. C133/C134 são casos de reprodução. A compilação nova está exclusivamente na QA18445, com fonte/configuração/bundle anteriores preservados para reversão. Sem migrations, contas, permissões, serviços ou notificações externas alterados.
<!-- /independent-QA-C133-C134-20261012 -->
<!-- C132-contained-20261012 -->
## C132 contido no ativo — incidente ainda aberto
Autorização específica do responsável executada: apenas `config/inertia.php`, DevTools OFF desde 12/10 18:57:15 UTC. HTTP anónimo index/detalhe real/detalhe arbitrário **404**. Login **200** e confirmação manual de **login, MFA e dashboard**. C131 não aplicado; COUNTRY02, papéis, bundle, chave/cifra, A/B e C37 preservados.
276 diagnósticos em 279 ficheiros preservados restritamente. Cookies/passwords/tokens mascarados nos exemplares retidos, mas quatro sementes TOTP e 32 códigos de recuperação correspondentes às contas 14–17 foram expostos: renovados seletivamente, obrigatoriedade MFA preservada. Zero correspondências entre os valores retidos e as credenciais atuais. Backup/restauro do destino renovado antes da resposta às credenciais, 295 tabelas/31 sequências, clone isolado 55441. Restam entrega individual das novas entradas e delimitação histórica; **não declarar fecho do incidente**.
[Relatório de contenção, alcance, período, provas e medidas restantes](C132-incidente-contido.md). Os retratos anteriores de C132 exposto abaixo são histórico anterior à contenção, não o estado atual. A matriz existente mantém os IDs; AUD-PROFILE-26 passa a parcial, sem fecho da privacidade integral.
<!-- /C132-contained-20261012 -->
# Visão consolidada por módulo — 12/10/2026
**O workflow das seis categorias base, COUNTRY02 e a administração de perfis estão disponíveis no ativo. A cobertura funcional permanece delimitada pelos percursos demonstrados. C132 foi contido no ativo por autorização específica: endpoints anónimos 404, quatro MFA afetadas renovadas. O incidente continua aberto; C131 permanece apenas em QA.** Esta visão resume a [matriz existente](matriz-requisitos.csv) e o [backlog existente](backlog-priorizado.csv). Não cria requisitos nem substitui o histórico.
Ativo: `https://portal-investidor.test`, entrega `2e2f16c83483`, código `a02ef2300d6c`, PostgreSQL `investemoz:5432`, 295 tabelas. QA completa: `https://portal-investidor.test:18445`, `stability_consumers_20261011_084534_test:55441`, 295 tabelas, cookie e chave próprios. A QA 18118 tem 194 tabelas e não demonstra equivalência integral. A leitura ativa foi sem POST ou alteração de código, configuração e dados de negócio; os GET podem produzir os registos/sessões de visitante normais do servidor.
## Produto disponível e cobertura real
| 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. |
| 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. |
| 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. |
| 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. |
| Governação e incrementos seguintes — AUD-MARKET/ESTABLISHMENT/FUND/COMPANY/CAPITAL/CHECKLIST, AUD-PROFILE-18/22/32 | Aceitação de fontes oficiais e regras Tempo permanentes. Identidades e cadastros mestres únicos. | Segmentação documental e versões/hash reconciliados; alias local do mesmo DOCX não criou importação/IDs. | Negócios similares/importação de estabelecimentos, fundos, comparador, capitalização/guia da Bolsa e jornadas não implementados ou ainda sem exemplares recuperáveis. Checklists existem em configuração; editor/versionamento integral não demonstrado. Quatro modulares, ofertas, competências e SLA continuam decisões separadas. |
“Disponível” indica configuração/rota/instalação e âmbito existentes, não prova de cada ação. O ativo ainda não tem demonstração integral do primeiro processo legítimo. Os consumidores e perfis detalhados permanecem na [lista existente](consumidores-restantes.md); não são novos requisitos.
## Seis categorias base e lacunas concretas
| Categoria/caso QA | Percurso demonstrado que se reutiliza | Materialidade demonstrada | Critérios ainda por concluir |
|---|---|---|---|
| Projeto de investimento 30/52 | Contrato, correção de condição, aprovação independente, publicação restrita e recuperação. | Investimento total/mitigação técnica reabrem revisão técnica, preservam revisão jurídico-territorial. | Variantes de viabilidade, condições financeiras/técnicas/documentos, todos os campos §27 e todos os efeitos na apresentação pública. |
| Imobiliário 31/54 | Venda ensaiada e arrendamento 54 com documentos, submissão, correção, revisão e publicação restrita. Renda 4500 MZN/mês preservada. | Titular reabre revisão registral/urbanística, conserva propriedade/conformidade predial. | Planeado, ocupado, em construção e com ónus continuam fora do âmbito disponível para submissão. Rascunhos de preparação não equivalem a autorização de publicar essas variantes. |
| Direitos sobre terra 32 | Correção e aprovação; publicação inicialmente bloqueada pela dependência externa real. Ensaio positivo separado usa simulação explicitamente QA. | Titular/documento reabrem revisão jurídico-fundiária, conservam gates não afetados. | Não existe prova de ato externo real. Documentos, correspondências territoriais restantes e variantes comunitárias/ambientais não integralmente demonstrados. |
| Venda de negócio 33 | Contrato ensaiado, correção, aprovação independente, publicação e recuperação. | Registo da entidade reabre triagem societária e conserva outros pareceres. | Mandatos, titularidade, histórico/projeções e variantes de ativos/passivos; §27 documental integral. |
| Parceria de negócio 34 | Condição, correção, aprovação e publicação ensaiadas. | Direitos de voto reabrem governação/diligência jurídica, preservam triagem/financeiros. | Demais aportes e direitos; recurso/suspensão/republicação por variante e documentos aplicáveis. Sala de parceria não é automaticamente contrato modular aprovado. |
| Franquia 35 | Registo/licença e revisões no caso ensaiado, publicação e recuperação. | Registo reabre revisão jurídica de franquia, conserva marca/financeiros/confidencialidade. | Royalties, exclusividade, alcance territorial e documentos/licenças de cada variante. |
Não se exige ensaio novo para cada frase: uma transição com campos, perfis, gravação/recuperação e resultado identificados pode cobrir várias cláusulas. A materialidade de seis campos não prova todos os campos; o mesmo comportamento num componente comum não prova a ligação de dados de outro consumidor. Os dez grupos e seus limites estão em `proof-groups.json` no ZIP, também inscritos nas colunas da matriz/backlog. São 269 requisitos ligados explicitamente; não são 269 fechos.
## C132 e demais bloqueios
**C132 ativo confirmado às 18:40:45 UTC (20:40:45 de Moçambique), 12/10/2026.** Dois GET sem cookie/token/autenticação, TLS validado: listagem 200 de 445 metadados (27 de gestão, 15 dashboard, 48 login, 14 MFA, 341 outros; 88 metadados de POST). Um detalhe operacional respondeu 200 com objeto de utilizador autenticado, cabeçalhos Cookie/XSRF, corpos e caminhos de origem. O recibo exporta apenas contagens/chaves/booleanos; não identifica quais credenciais ou dados estão em todos os registos nem afirma que todos os 445 detalhes foram examinados.
Causa: ambiente `local`, DevTools ativado por omissão e middleware que permite leitura anónima nesse ambiente. Afeta diagnósticos retidos de consumidores de autenticação/gestão; contorna a confidencialidade que as políticas normais dessas páginas pretendem assegurar. Correção QA explícita `inertia.devtools.enabled=false` devolve 404 em listagem e detalhe, com login/MFA e páginas ensaiadas preservados. **Suplemento autorizado de 12/10 18:57:15 UTC: ativo contido, endpoints 404.** A análise local confirmou quatro sementes e 32 códigos de recuperação válidos antes da resposta: renovados apenas para 14–17. Registos com ACL restrita, backup/restauro renovado e login/MFA/dashboard confirmado pelo responsável. Incidente permanece aberto; consultar [relatório específico](C132-incidente-contido.md). A descrição acima conserva a prova anterior à contenção. Não restaurar uma configuração que reabra a exposição.
C131 impede alguns contactos válidos de serem guardados devido a espaços internos, embora o nome normalizado seja válido. QA normaliza antes de validar e conserva a chave/reutilização; interface atual e disponibilização separada pendentes. Ausência de geometrias ativas impede mostrar esses limites, mas não bloqueia todas as ações do workflow. Um anúncio QA ainda não publicado e o pipe indisponível são limitações de preparação/observação, não falhas comprovadas de submissão ou do portal inteiro.
## Constrangimentos a resolver antecipadamente
- **Controlo visual:** Chromium local continua em execução (`ms-playwright/chromium-1243`), mas `sky.list_apps` não liga ao pipe nativo (`os error 2`) e `cua.getState` devolve apps/browsers vazios. Não é ausência de navegador nem erro do portal. Preparar uma recuperação única do conector; conservar as provas visuais válidas, não pedir tentativas sucessivas ao proprietário.
- **Estado dos fixtures:** localizar anúncio sintético de negócio apto e publicá-lo apenas em QA pelo workflow existente antes de ensaiar interesse/origem/estatísticas. Não atribuir papéis nem estados diretamente na base como atalho. Contas QA 21/22/23/24/25 já existem; não depender dos funcionários.
- **Documentos:** conhecer extensões/MIME/tamanhos, limites PHP web, scanner, queues e permissões antes de cada consumidor. Não iniciar worker sobre fila ativa na preparação. A leitura da supervisão deve respeitar a ACL; a falta de acesso desta sessão não prova serviço parado.
- **Cartografia:** corresponder código/nome/pai contra o exemplar aceite antes de importar. Separar caso inequívoco de ambíguo e camada interna de publicação. A relação de 173 pendentes já está na matriz/documento existente.
- **Revisão e dados mestres:** fixar as duas fontes PHP corrigidas e os hashes finais; o bundle não mudou. Renovar backup/restauro do alvo antes de eventual disponibilização. A organização Tempo e os funcionários já estão cadastrados/atribuídos; não reabrir essa dependência. País mestre NULL é dado legítimo ainda por preencher.
- **Decisões concretas:** restauração pelo Publicador para revisão não pública, regra distinta para rascunho eliminado, ofertas/competências modulares, calendário/responsáveis de SLA e relações territoriais indeterminadas. Não bloquear trabalhos independentes nem converter estas propostas em regras sem decisão da Tempo.
## Lotes restantes, cobertura e esforço
Horas de trabalho estimadas por lote, incluindo reconciliação/ensaio e pequenas correções localizadas. Não são compromisso de atendimento nem prazo externo. Pressupõem a QA completa disponível, fixtures existentes e acesso visual recuperado nos critérios de interface. Variantes novas e alterações extensas serão estimadas após reprodução/decisão. Não multiplicar por 3.401 linhas ou por 7.739 referências.
| Ordem | Lote e cobertura prevista | Critério de saída | Esforço estimado / dependências |
|---|---|---|---|
| P0 | C132 contenção e C131 contactos, delta QA `a23156a65be2` | QA com listagem/detalhe 404, normalização/recuperação preservadas, provas atuais de interface onde aplicável; revisão/backup correspondentes. Ativo só após autorização própria. | 2–4 h de preparação/verificação do pacote, fora a recuperação do conector e a janela de execução autorizada. Código já preparado. |
| P1 | Seis categorias: lacunas de Response/§27 e materialidade documental | Mapear contrato Create/Patch/Read às variantes incluídas; reabrir somente gates afetados; mensagens claras nas variantes indisponíveis. Reutilizar WF6/MAT6/LEASE54. | 12–20 h de reconciliação/ensaios dos critérios restantes. Correções extensas e novas variantes fora da faixa; não inclui ofertas/modulares. |
| P1 | Países/origem/estatísticas: perfil, manifestações, negócios, fundiário e Balcão | Por consumidor: valor correto, submissão, recuperação, filtro/estatística e repetição sem duplicações; distinguir país mestre/residência/origem. | 8–16 h. Fixture público de negócio em QA preparado primeiro. País real não inventado; prova ativa de preenchimento depende de ação legítima. |
| P1 | Seletores/mapas de zonas, carteira, educação, parcerias e catálogo | Limites/pontos corretos, limpeza de descendentes, recuperação, filtros/privacidade e apresentação por rota. Correspondências inequívocas adicionais sem duplicar as 408. | 12–20 h para consumidores e primeiras correspondências inequívocas; 173 casos não têm fecho total previsível enquanto faltarem correspondências inequívocas. Mandie/Guro separado. |
| P1 | Documentos/PDFs/exportações/derivadas por consumidor | Original preservado, scan, derivada autorizada, downloads/aliases negados a não autorizados, falha/repetição sem duplicação. | 8–16 h para casos restantes agrupados por tipo e política. Prova no destino exige processo legítimo; não criar processo fictício no ativo. |
| P2 | Acessibilidade restante | Teclado/foco, rótulos/erros/estados e leitor de ecrã nas rotas incluídas; contraste inconclusivo resolvido. | 6–12 h após controlo visual. Dispositivos reais e PDFs etiquetados permanecem critérios separados. |
| P2 separada | Legado: restantes setores/acervo | Conteúdo/imagens/anexos/links/consulta pública/contexto por setor; Mercado Financeiro permanece privado sem corpo. | 8–16 h de reconciliação/ensaio do conteúdo existente; expansão de conteúdo depende dos exemplares, sem converter artigo em oportunidade. |
| Transversal | Cláusulas ainda sem correspondência explícita | Agrupar pelo contrato/consumidor/estado e citar a mesma prova para todos os critérios que cobre, com exceções/limites. | 12–20 h para o próximo conjunto priorizado, não estimativa de fecho das 3.062 linhas ainda sem prova suficiente. Sem exigir teste isolado por frase. |
A/B e C37 não entram nestes lotes. O primeiro lote utilizável continua o workflow delimitado já disponibilizado; C132 foi disponibilizado separadamente sob autorização específica; C131 permanece o próximo delta QA separado. Não incluir 190000, cartografia, legado ou decisões modulares nesse delta por conveniência.
## Contagens e integridade
3.401 IDs únicos/linhas, 7.739 ocorrências de origem e 604 fontes inventariadas. Estados do requisito agregado: 3.062 sem evidência suficiente; 316 parciais; 1 com falha; 9 não implementados; 6 dependentes de decisão concreta; 7 demonstrados apenas em QA no âmbito definido. As sete linhas históricas fechadas, A/B, C37, coedição e demais critérios válidos permanecem conservados. A contagem agregada não é uma lista de 3.062 funcionalidades novas nem mede ausência de produto ativo.
O ZIP é uma cópia de revisão da única matriz/backlog, com relatório executivo, casos, plano, visão por módulo, correspondências cartográficas, manifesto e provas sanitizadas. Exclui bases, credenciais, códigos/segredos MFA, `.env`, originais privados e diagnósticos expostos. C131 permanece correção PHP QA. C132: uma configuração PHP aplicada no ativo e quatro credenciais MFA renovadas por resposta autorizada ao incidente; zero alterações de schema, flags, serviços ou bundle. O backup/restauro de 12/10 11:10:30 UTC é da entrega ativa anterior; C132 tem novo dump/restauro de 19:02:57 UTC (295 tabelas/31 sequências) e recuperação da configuração/cifra em armazenamento restrito. Não reutilizar segredos comprometidos na reversão.
@@ -0,0 +1,344 @@
<!-- option-B3-exit-table-20261013 -->
## Opção B: tabela única dos critérios de saída
[Tabela atual: concluído/prova, trabalho executável, C135 e dependência concreta](saldo-opcao-B.md).22 grupos, sem novos IDs ou outro backlog; A/B/C37 preservados.25–43 h estimadas restantes (5–10 correções+5–10 implementação+15–23 verificação), não horas consumidas nem prazo garantido.
Projeto 30: PDF próprio/scan real/hash, licença aplicável sintética, revisão jurídica apenas, aprovação 24/publicação 25 restrita e outra sessão; visual ainda aberto. Scanner QA13310 tinha assinaturas >48 h; atualizado só emQA, limite intacto/fila alheia preservada. Sem delta de código do produto ou recompilação. Ativo intacto; candidata final não fixada.
C132 separado:14–17 confirmadas, recuperação individual concluída; investigação histórica/limites ainda abertos. Sem envio, rotação ou alteração ativa. As secções datadas abaixo preservam o histórico; para o estado atual usar esta tabela.
<!-- /option-B3-exit-table-20261013 -->
<!-- option-B2-saldo-20261013 -->
## Opção B: saldo atualizado, C140/C141 e critérios restantes
[Saldo por critério, consumidor, bloqueio e esforço](saldo-opcao-B.md). **Restam 25–43 h técnicas**, reestimativa da faixa 40–72, separadas em 5–10 correções, 5–10 implementação pedida e 15–23 verificação. Não é percentagem de conclusão nem tempo medido; espera C135/ativação/evolução fora. B continua sem candidata final.
C140: unidade explícita da parcela guardada/recuperada emQA, sem converter área 1100; apenas cadastral reabre. C141: preparação de área/unidade incompleta guardável; submissão 422→completar par→revisões/condição preexistente→aprovação 24/publicação 25 restrita→nova sessão.148 tarefas anteriores e originais/dossiers preservados; 6 tarefas novas próprias, sem prazos. Interface nova aberta por C135, separado das falhas do produto.
A/B e C37 preservados. C132 separado:14/16/17 confirmadas, apenas 15 pendente; nenhum segredo/envio/rotação/alteração ativa. Zero alterações do portal ativo.
<!-- /option-B2-saldo-20261013 -->
<!-- option-B-first-increment-20261013 -->
## Opção B em QA: âmbito fixado e critérios novos demonstrados
[Âmbito e aceitação fixados antes da execução](ambito-B-aceitacao-QA.md). [Resultados, acessos e critérios restantes](execucao-B-QA.md). A migração 190000 já existia neste clone; habilitou-se apenas a flag QA. C138 corrigiu a repetição fundiária, 409 → 202 com o mesmo recibo, país/origem e quatro IDs recuperáveis. C139 corrigiu maturidade 7/8 na publicação e pesquisa pública, sem converter os catálogos históricos.
Variantes de licença não aplicável (30), área/comunidade sintética (32), exercício financeiro (33), contribuições (34) e exclusividade (56) passaram por gravação, reabertura apenas dos pareceres afetados, revisão independente e recuperação noutra sessão. 33 foi publicado no catálogo público QA; os outros quatro têm visibilidade restrita. Consulta pendente continuou a impedir publicação apesar da aprovação interna. Originais e 132 tarefas anteriores preservados; 16 tarefas novas destes casos, sem prazos inventados.
TypeScript/produção passaram: 159 ficheiros preparados, 157 recursos referenciados servidos por HTTPS com hashes corretos. Mesma matriz: 3.401 requisitos/linhas, 7.739 ocorrências, 27 grupos de provas; 10 requisitos de B atualizados, sem fechos visuais ou agregados. A/B e C37 preservados. Critérios visuais novos continuam abertos por C135, assim como as variantes/consumidores delimitados. Este pacote consolida **um incremento B para revisão**, não a candidata final pronta para ativação. Código/configuração/bundle ativos intactos.
**C132, separado:** conta 16 confirmou recebimento, MFA e dashboard; conta 17 já confirmada. Restam 14/15 e os limites históricos do incidente, sem reenvio, rotação ou alterações ativas nesta confirmação.
<!-- /option-B-first-increment-20261013 -->
<!-- module-exit-synthesis-PDF-C137-20261012 -->
## Lote executado agora
| Item | Rota/perfil | Resultado e evidência | Critério que continua aberto |
| --- | --- | --- | --- |
| Exportações | `/api/v1/investment/export`; `/api/v2/investment/zones/export.csv`; público | CSV8/11colunas e8linhas de cada conjunto; UTF8/BOM; filtro positivo e replay idêntico; oportunidade interna56 excluída. `next-exports-HTTP.json`. | Botão/UI e demais combinações/limites grandes; não declara todas as exportações concluídas. |
| Royalties/licença | `/minhas-oportunidades/56/edit`, `/workflow`, `/view`, `/resources/documents/{id}/download`; QA21→24→25 | Royalties reabre3gates, licença2; restantes hash/ator/data conservados; aprovação422 antes das revisões; reaprovação24/publicação interna25/nova sessão. PDF próprio clean/hash/MIME e licençaUUIDpreservados. `franchise-variant-royalties/license-HTTP.json`, `next-lot-final-SQL.json`. | UI, exclusividade/titularidade e publicação pública; §27integral. |
| Revogação | `/parcerias/salas/2/documentos/4` e`/partilha`; autor21/participante23/não participante22 | PDF200 antes→sala cancelada→autor retira→sessão antiga/nova404; autor200/hash; regrant409, não autor403, anónimo401. Repetição mantém1original; sala1/anexos intactos. `partnership-revocation-closed-room-revocation-HTTP.json`. | C137UI e restantes variantes de sala; não é ACL individual da oportunidade. |
| C137 | Componente `partnerships/room`, autor do documento | GuardaUI `mutable` ocultava retirada após encerramento emboraAPIpermitisse. Ajustado apenasQA para permitir retirar partilha existente ao autor e manter novas partilhas indisponíveis. TypeScript/build passaram,159assets; novo chunk servido200/hash; manifestoQA87e77091835f… e anteriorcf78… preservados. | Clique/resultado visual com estado adequado; código compilado não encerra o critério. |
| PDF anterior | Impressão fundiária no browser, âmbitoQA anterior | Reutilizado PDF3páginas/hash0676c5f7… com prova visual/scan anteriores e bytes atuais conferidos. PDF sintético1977bytes deste lote é entrada de teste, **não um novo gerador do portal**. | Geradores/templates/PDFs etiquetados e consumidores restantes. ReciboBalcão continuaTXT; não foi convertido silenciosamente. |
Oito requisitos existentes atualizados; zero novosIDs;19grupos de provas com correspondências/limites explícitos. Nenhum fecho visual ou agregado novo. Fontes/configuração/bundle ativos conferidos por hash e intactos. Alteração deste lote é umaTSXna cópiaQA e159assets compilados, com originais/manifesto anterior privados e assets antigos preservados. Reversão técnicaQA deste delta: fonte anterior e manifestoQAanterior, mantendoPDFs,IDs,história e partilha revogada; nunca reautorizar destinatários como reversão. Algoritmov4da materialidade permanece, comv2/v3preservados. Não é pacote pronto para ativação.
Saldo por módulo, bloqueios e esforço na visao-consolidada-modulos.md; mesmas matrizes, sem novo backlog.
<!-- /module-exit-synthesis-PDF-C137-20261012 -->
<!-- consumer-QA-C135-C136-20261012 -->
## Lote QA de seletores, derivadas e variante financeira da franquia
**Nenhuma alteração no ativo.** A/B e C37 mantêm os fechos próprios. C133 conserva a prova API/SQL; C134 permanece compilado em QA, com interação visual pendente. C132 fica separado: conta17 recuperada, confirmações individuais14–16 ainda pendentes. Nenhum email ou segredo foi reenviado neste lote.
O lote atualiza nove requisitos existentes, sem novos IDs: AUD-FIELD-030, AUD-GEO-02/03, AUD-OP-02/03/04, AUD-SCAN-01, AUD-UI-01 e AUD-PROFILE-28. A matriz tem **3.401 requisitos/linhas e 7.739 ocorrências de origem**:3060 sem evidência suficiente,318 parciais,6 decisões Tempo,1 falha,7 demonstrados apenas em QA e9 não implementados. Nenhum requisito agregado ou critério visual foi encerrado por este lote.
### Evidência nova e critérios restantes
Base QA: **https://portal-investidor.test:18445**, PostgreSQL `stability_consumers_20261011_084534_test:55441`. O cabeçalho QA foi conferido em cada resposta; as leituras SQL finais ocorreram em transação READ ONLY. QA56 é uma oportunidade sintética, com documentação identificada como simulação sem validade jurídica.
| Item e requisito | Rota, perfil e ação | Demonstrado neste lote | Critério restante e evidência necessária |
| --- | --- | --- | --- |
| Hierarquia — AUD-FIELD-030/AUD-GEO-02 | `/minhas-oportunidades/56/resources`; Promotor21 guarda, nova sessão recupera. APIs `/minhas-oportunidades/territory-options` e `POST /minhas-oportunidades/56/resources/locations`. | Cabo Delgado→Ancuabe/distrito→Ancuabe/posto→Ancuabe-Sede/localidade: quatro IDs recuperados; pai de nível errado422 e país PT com território MZ422. | Mostrar seleção, troca de pai/país, limpeza dos filhos e erros adjacentes a1440/390px; captura e resultado após guardar. A API não demonstra os cliques nem a limpeza na interface. |
| Limites — AUD-GEO-03 | `/minhas-oportunidades/territory-geometries?territory_id={UUID}`; perfil autorizado. Consulta pública `/api/v1/investment/territory-geometries`. | Província/distrito/posto: geometria INE disponível, contextos1/2/3. Localidade cadastrada sem geometria própria, recebe só três limites ancestrais; `investment_site=false`. Camadas internas não expostas na consulta pública:0. | Mapa deve distinguir limite administrativo de local de investimento e ausência de limite da localidade. Captura/legenda/teclado/zoom em cada consumidor ainda aberto;173 correspondências e Mandie/Guro mantidos. Sem novas importações ou publicações. |
| Original/derivadas — AUD-OP-02/AUD-SCAN-01 | `POST /minhas-oportunidades/56/resources/images`; `POST /minhas-oportunidades/56/resources/images/{imagem}/prepare`; `GET .../download` e `GET .../preview/{documento}`. Autor21/coeditor22/Validador24/Publicador25; outra organização23/anónimo. | Upload→quarentena423→job do scan real ClamD1.5.4→original limpo→WebP320/640/1280→scan próprio→download200/hashes→nova sessão. Replay conserva IDs, versão2 e um evento derivatives_prepared. Outraorg403/anónimo401, incluindo URL assinada. Bytes cifrados e original preservados. | Apresentação visual da imagem/WebP e erros; outros formatos/PDFs/consumidores não cobertos. Os jobs tratados pertencem só a56: não foi um novo ensaio do worker nem consumo da fila alheia. Reutilizar os recibos prévios de interrupção/replay. |
| Response de recursos — AUD-OP-04 | `GET /minhas-oportunidades/56/response`; Promotor e perfis no âmbito. | IDs de localização/imagem, SHA original e autor21 recuperados no contrato ligado aos recursos. | §27 integral continua `normative_response_complete=false`: IDs bigint/referência histórica, metadata desconhecida e pareceres paralelos não são convertidos. Novas variantes exigem campos/IDs/metadata específicos; não se declara conformidade global. |
| C136, franquia — AUD-OP-03/04/AUD-PROFILE-28 | `/minhas-oportunidades/56/edit`, `PUT .../draft`, `POST .../workflow`, `GET .../view`; Promotor21→Validador24→Publicador25, MFA próprio em sessões normais. | Submissão/aprovação independente; taxa inicial1000→1250; nova submissão reabre marca/licença, legal da franquia e financeiro, conserva confidencialidade/hash/ator/data. Aprovação422 antes das revisões;24 reaprova e25 disponibiliza internamente. Nova sessão recupera taxa/estado. Autor não autoaprova403. | Interface da variante, royalties viaHTTP/UI e restantes variantes abaixo. Esta publicação usa o workflow real em QA, mas é **restrita**, não prova catálogo público. O anúncio do lote C133 continua fixture e não é substituído por esta franquia. |
| C135, conector — AUD-UI-01 | Inventários suportados de apps e navegador, antes de qualquer seleção/input. | Chromium1243 está em execução; pipe nativo ausente, os error2; inventário apps/browsers vazio. Primeiro ponto de falha é IPC. | Repor o transporte do conector no host e obter inventário QA antes de retomar os visuais novos. Processo específico/causa além do IPC ausente não determinados. Não há prova de falha do Chrome ou do portal; sem contorno de protocolos e sem pedir novos testes repetidos ao utilizador. |
**C136 — causa e correção:** a projeção v3 de `financial_review` não incluía `business_transaction.franchise_terms.initial_fee` nem `royalties`. A alteração podia conservar um parecer financeiro desatualizado. Apenas em QA, a projeção v4 incorpora esses dois campos já existentes. As regras históricas v2/v3 continuam verificadas pelo respetivo algoritmo, preservando assinaturas/ator/data; não se recalculam assinaturas silenciosamente. Antes/depois foram reproduzidos em memória e a taxa inicial foi depois demonstrada pelo HTTP/SQL normal. Royalties passou a regressão do serviço, não uma transição HTTP ou interface. O ficheiro ativo conserva o hash anterior; não foi corrigido por este lote.
**Limites da execução:** não se repetiram os seis percursos visuais base, arrendamento54, coedição15, suspensão/republicação31 ou recurso34. O novo caso56 é necessário para a falha financeira recém-identificada e não altera os casos anteriores. Dois erros de leitura de propriedades no harness foram corrigidos e os pedidos válidos aproveitados, sem criar oportunidades repetidas; não são falhas do portal. Só a disponibilização final foi retomada depois da aprovação já válida, sem a repetir.
### Consumidores e variantes ainda abertos
| Rota | Perfil e operação | Critério em falta | Evidência a produzir ou reutilizar |
| --- | --- | --- | --- |
| `/negocios/{slug}/manifestar-interesse`; `/management/interests` | Público/gestor: países, origem, erros e filtros | C134: foco/rótulos/erros/valores e chave preservados; publicação do anúncio pelo fluxo próprio ainda não demonstrada. | Reutilizar C133 API/SQL e build C134. Nova captura só dos critérios de interface; o anúncio sintético não encerra publicação. |
| `/minhas-oportunidades/15/resources` e `/15/edit` | Coeditor22/autor21: correção pós-submissão | Coedição de rascunho já demonstrada; falta coedição na correção e revogação nessa ação. | Reutilizar coedição/mapa/PDF prévios; novo estado needs_information e revogação em fixture própria, leitura/escrita recusadas. Não repetir rascunho comum. |
| `/oportunidades?view=map`, `/api/v1/investment/map`, `/carteira/{id}` | Público: pesquisa e mapa | Consumidores sem prova própria: filtros/limites/ausência de geometria, recuperação do contexto, legenda/teclado. | Resposta API com fonte/visibilidade + captura do consumidor; sem publicar camadas internas como preparação do teste. |
| `/management/investment/zones/{id}`; `/zonas/{id}`; `/api/v2/investment/zones/export.csv` | Gestor escreve recursos no seu âmbito; público consulta | Seletores/mapa/anexo e exportação por zona não encerrados pelo mapa de oportunidades. | Estado próprio QA, persistência/nova sessão, hash/scan e acesso público/restrito conforme autorização; captura e CSV do mesmo filtro. |
| `/investidor/terra-duat/{id}/editar`, `/{id}/documentos/{anexo}`, `/{id}/imprimir` | Investidor proprietário e gestor no âmbito | Hierarquia, documentos e impressão das variantes não cobertas por A/B; HTML de impressão não prova PDF gerado/etiquetado. | Reutilizar A/B apenas no que efetivamente cobre; novo documento/caso próprio, original/hash/scan, recusa outra conta, impressão e acessibilidade específicas. |
| `/balcao-virtual/dossiers/{id}/documentos/{documento}`; `/balcao-virtual/pedidos/{id}/recibo` | Titular/analista autorizado: ficheiro e recibo | Documentos por tipo e recuperação após retirada/revogação. O endpoint de recibo atual gera **TXT**, não PDF; não declarar o PDF concluído. | Protocolo/snapshot do mesmo pedido, conteúdo MIME real, hash/autorização e apresentação. A/B permanece fechado; PDF é critério documental próprio ainda sem implementação neste endpoint. |
| `/parcerias/salas/{id}/documentos/{anexo}` e `POST .../partilha` | Participante autorizado: partilha/revogação | Variantes de destinatário/estado e revogação ainda sem prova específica. | Reutilizar o recibo da sala1 apenas no âmbito efetivo; destinatário antes200/depois nega, original preservado e nova sessão. ACL individual de oportunidade continua indisponível e não é substituída pela sala de parceria. |
| `/minhas-oportunidades/{id}/workflow` e `/{id}/response` | Promotor/Validador/Publicador por tipo/âmbito | Variantes de categorias abaixo; §27 parcial. | Transição do campo específico→persistência→reabertura só dos pareceres afetados→aprovação independente→visibilidade prevista→nova sessão; captura só dos passos ainda sem prova. |
### Critérios restantes por categoria
| Categoria e referência válida | Semântica/materialidade restante | Documentos/Response restante |
| --- | --- | --- |
| Projeto30/52 | Licenciamento e pressupostos de cenários; alteração de evidência aninhada demonstrada em serviço, não em todos os consumidores. Risco/correção/condição prévios reutilizados. | Evidência própria por variante; PDF/exportações dos outros consumidores; §27 parcial. |
| Imobiliário31 e arrendamento54 | Venda/arrendamento preservados, renda4500 MZN/monthly. Construção planeada, ocupação contratada, encargos e limites urbanísticos por variante. | Título/licença/avaliação54 já scaneados e recuperados; documentos das modalidades restantes, sem presumir direitos reais. |
| Direitos sobre terra32 | Área/unidade/comunidades/plano no código com regressões; faltam novos casos de campo/consumidor. Parcelas/direitos externos continuam separados do limite administrativo. | Ato QA32 é simulação, não decisão externa real. Localidades/parcelas sem geometria própria mantêm lacuna; metadata/§27 parcial. |
| Venda de negócio33 | Financeiros/histórico/projeções/confidencialidade por variante; cadastro do anúncio existente é consumidor distinto. C133 cobre interesse/país/origem/SQL desse anúncio, não publicação. | Mandato/teaser/destinatários específicos; proposta de ausência de histórico não vira regra aprovada. |
| Parceria34 | Contribuições monetárias/não monetárias, obrigações e documentos adicionais; voto/recurso anteriores preservados. | Revogação da sala1 não encerra ACL individual de documentos da oportunidade; §27 e metadados de pareceres distintos. |
| Franquia35/56 | Taxa inicial56 HTTP/SQL agora demonstrada; royalties serviço apenas. UI da taxa, HTTP/UI de royalties, exclusividade, licença/titularidade e território continuam abertos. | Documento contratual56 é simulação própria com scan real; variantes de licença/confidencialidade por destinatário pendentes; §27 parcial. |
### Próximo trabalho executável e reversão QA
1. **Documentos por consumidor,4–6h estimadas:** recibo TXT/HTML versus PDF real, fundiário e anexos de zonas/parcerias; verificar tipos/scan/hash/revogação por rota. Pressupõe serviços QA e estados existentes disponíveis. Não consumir fila ativa ou notificações externas.
2. **Variantes de workflow,3–5h para franquia:** royalties, licença e exclusividade, sem repetir taxa inicial ou casos base. Outros tipos por pequenos lotes próprios conforme dados/documentos necessários. Restauração/partilha individual/ofertas/módulos/SLA mantêm decisões separadas.
3. **Visual/acessibilidade:** C131/C134, novos seletores/limites/WebP/materialidade quando o conector voltar a expor uma janela QA. Não estimar conclusão enquanto faltar o transporte; leitor de ecrã e dispositivos reais são provas distintas.
Não é candidata de ativação. Delta de código deste lote: **apenas PHP `OpportunityReviewMateriality.php` na cópia QA**, sem nova compilação; o manifesto QA C134 mantém SHA `cf78d5516251bc27c0d1b74fdfc257adf9a3113276dce9109c3c312e57d70fe9`. Fonte anterior privada preservada e hash conferido. Reversão QA: desabilitar ensaio desta variante e recuperar a fonte anterior quando não houver decisões v4 a utilizar; conservar todos os dados/IDs/documentos/decisões v4, sem recalcular assinaturas ou tentar fazê-las valer pelo algoritmo v3. Nova candidata deverá incluir o algoritmo v4 e os históricos v2/v3, com backup/restauro correspondente. Nenhuma instalação ou ativação autorizada por esta entrega.
Provas sanitizadas: `connector-diagnosis-C135.json`; `franchise-materiality-before/after.json`; `workflow-franchise-materiality/finish-HTTP.json`; `consumer-lot-quarantine/derive/recover-HTTP.json`; `consumer-lot-document-state-original/derivatives.json`; `consumer-lot-final-SQL.json`; `consumer-lot-preservation.json`. Cada grupo enumera IDs e limites em `proof-groups.json`. Sem cookies, códigos, QR ou segredos anexados.
<!-- /consumer-QA-C135-C136-20261012 -->
<!-- workflow-opening-2e2f16c83483-20261012 -->
## Estado atual — workflow disponibilizado em 12/10/2026
**Entrega 2e2f16c83483 / código a02ef2300d6c disponibilizada; seis categorias base abertas para os perfis já atribuídos. COUNTRY02 e administração ON.** [Resultado, acessos e limitações](../../../../outputs/investmoz-workflow-opening-20261012/resultado.md), [manifesto de execução](../../../../outputs/investmoz-workflow-opening-20261012/manifesto-execucao.json), [HTTPS e 159 recursos conferidos](../../../../outputs/investmoz-workflow-opening-20261012/web-enabled.json) e [navegação por perfil](../../../../outputs/investmoz-workflow-opening-20261012/navegacao-perfis-leitura.json).
Autorização do responsável: «pode fazer a entrega». Nove fontes/159 recursos, três gates conjuntos; nenhuma migration, conta, organização, representação, atribuição, importação, publicação ou alteração de serviço. Backup real anterior à intervenção de 11:10:30UTC restaurado/verificado:295 tabelas/31sequências/1391ficheiros/4originais/6MFA. Código/dados/grants/cifra/histórico preservados e contenção preparada. Bootstrap e validação de funcionários concluídos não voltam a ser requisitos pendentes.
**Critérios restantes incluídos:** acompanhamento do primeiro processo/documentos legítimos no destino; a conferência HTTP/política não é uma nova demonstração visual humana. QA/contacto e fechos A/B/C37 preservados, sem repetição. **Fora:** contrato normativo integral/cargo ainda parcial, variantes não demonstradas, restauração/partilha individual, camadas cartográficas, legado,190000,modulares/ofertas/competências/SLA,acessibilidade integral/dispositivos reais. Notificações OFF. As pendências não identificadas como dependência deste âmbito não bloqueiam os acessos já abertos.
As referências a workflow OFF/designações/importações/ativação pendentes nos blocos abaixo conservam o histórico e não substituem este estado atual. Mesma matriz, sem novos IDs/fontes ou fechos globais.
<!-- /workflow-opening-2e2f16c83483-20261012 -->
<!-- workflow-authorized-activation-20261011 -->
## Execução técnica autorizada no destino — 41caea0f900f
**Código/bundle, B1/B2, 030000 → 040000 e bootstrap cruzado concluídos no destino. COUNTRY02 preservado ON; fluxos operacionais OFF.** [Resultado e limites](../../../../outputs/investmoz-workflow-activation-20261011/resultado.md), [provas sanitizadas](../../../../outputs/investmoz-workflow-activation-20261011/evidencias-destino.json), [procedimento executado/reversão](../../../../outputs/investmoz-workflow-activation-20261011/procedimento-executado.md) e [designações](../../../../outputs/investmoz-workflow-activation-20261011/designacoes-operacionais.md).
Pacote/code/manifesto41caea0f900f/117d2d889701 preservados. Backup do destino de17:12:20UTC restaurado/verificado no clone:288 tabelas/31sequências/867ficheiros/4originais. No destino, somente030000 pela conta2 e040000 pela conta13, por ações HTTP autenticadas:288→291→295tabelas/5colunas/0novas sequências. Auditoria sem duplicações. Bootstrap:pedido13/confirmação2, sessões/MFA próprios, uma dupla/um pedido consumido. Zero novas identidades/organizações/representações ou concessões operacionais.
ClamD3310/LocalService/assinaturas28150 e ACLs positivas/negativas demonstrados. PHPweb20M/24M/256M/180s/GD/WebP e trêsvhosts verificados no Chromium com TLS reconhecido. Recarga própria graciosa do Apache expressamente autorizada após Laragon não recarregar a instância fora dele. Worker supervisionado habilitado após releitura da default vazia/notificações OFF; primeira execução0. O processamento documental completo/falha/repetição continua prova distinta do clone; no destino falta atividade documental legítima. Dados das288tabelas anteriores,4originais/2envelopesMFA eCOUNTRY02 preservados.
**Pendências operacionais:** designarPromotor/Validador/Publicador com contaexistente,organização/representação legítima,tipos/âmbito/responsabilidade; abertura dos fluxos separada. País mestre real aguardará organização legítima. Restauração/partilha individual,190000,cartografia/acervo/legado,modulares/ofertas/SLA continuam fora. A/B/C37 e provas QA válidas preservadas, sem repetição. Contenção preservaHTTPS/cifra/COUNTRY02/schema/histórico; restauro completo exige decisão separada.
Mesma matriz:3401requisitos/linhas,7739ocorrências, apenas3evidências complementadas; zero novosIDs/fontes e estados gerais preservados. Os blocos seguintes são históricos; as instalações e o bootstrap neles referidos como pendentes foram concluídos neste âmbito técnico.
<!-- /workflow-authorized-activation-20261011 -->
<!-- workflow-execution-preparation-20261011 -->
## Preparação técnica e habilitação operacional separadas
[Relatório da preparação](../../../../outputs/investmoz-workflow-execution-preparation-20261011/relatorio-preparacao.md), [proposta única de execução](../../../../outputs/investmoz-workflow-execution-preparation-20261011/procedimento-unico.md), [backup do destino](../../../../outputs/investmoz-workflow-execution-preparation-20261011/backup-destino-verificado.json) e [designações operacionais](../../../../outputs/investmoz-workflow-execution-preparation-20261011/designacoes-operacionais.md).
Candidata **41caea0f900f**, código **117d2d889701**, ZIP/manifesto imutáveis; 98a8e0b70892 e o plano histórico B1/B2 preservados. O responsável confirmou que ID 2/nala@tempo.co.mz e ID 13/onala@me.com são **duas pessoas diferentes**. Identificação e independência dos titulares resolvidas; nenhum bootstrap/grant ativo executado.
Backup/restauro do **destino real investemoz:5432** renovado **2026-10-11T17:12:20+00:00**, restaurado somente no novo clone 55441: **288 tabelas/31 sequências/867 ficheiros**, 4 originais/0 ausentes/2 MFA legíveis, linhas/seq/bytes iguais. Mais 68 ficheiros de serviços face aos 799, com scanner/config/assinaturas/PHP/XML e metadados de 986 ACLs. DACLs/tarefas recuperadas como ficheiros/metadados, não aplicadas no Windows ativo. Compatibilidade e reversão vazia 030000→040000 passaram no novo clone: 288→291→295 tabelas, 5 colunas; todas as linhas/colunas/seq e 050000 preservadas. Não é instalação autenticada no destino.
**Uma autorização técnica proposta:**código/bundle+B1/B2+030000→040000 autenticadas+bootstrap cruzado dos dois titulares. Manter COUNTRY02 ON e os fluxos operacionais OFF. Readiness preparado apenas em armazenamento privado de recuperação, ainda não disponibilizado aos instaladores do destino. Fila ativa lida sem consumo/notificações externas; nova leitura imediatamente antes do worker, parar perante NotifyInterestReceived ou classe desconhecida. Intervenção no destino continua por autorizar.
**Habilitação operacional separada:**faltam designações de Promotores, Validadores e Publicadores, com conta existente, organização/representação legítima, tipos e âmbito. Isso condiciona a abertura dos fluxos, não a preparação/instalação técnica. As provas de LocalService, bootstrap, coedição, categorias, A/B e C37 válidas foram reaproveitadas. Nenhuma nova prova de dispositivos reais/acessibilidade integral foi declarada. Restauração/partilha individual, 190000, legado, ofertas/modulares/SLA permanecem fora; restauro completo do destino exige decisão própria.
Mesma matriz: 3401 requisitos/7739 ocorrências; três células de evidência atualizadas, nenhum ID/fonte/estado geral alterado. Os blocos seguintes preservam o histórico; as pendências de backup e de independência neles referidas ficam reconciliadas por este bloco atual.
<!-- /workflow-execution-preparation-20261011 -->
<!-- consolidated-workflow-qa-20261011 -->
## Candidata consolidada 41caea0f900f — QA, sem ativação
[Relatório e bloqueios](../../../../outputs/investmoz-workflow-consolidated-20261011/relatorio-consolidacao.md), [procedimento único](../../../../outputs/investmoz-workflow-consolidated-20261011/procedimento-unico.md) e [manifesto](../../../../outputs/investmoz-workflow-consolidated-20261011/manifesto.json).
Delta 117d2d889701 integrado: 22 ficheiros de código + 159 assets (181 no ZIP), referência 98a8e0b70892 preservada. Compilação de produção do delta verificada por bytes; nenhuma alteração de código adicional. Prévia Chromium/MFA 040000 com fingerprint novo e dependência 030000 corresponde ao restauro renovado; gestor legado fora da dupla QA recebe 403, titular autorizado recebe 200. Instalações/funcionalidades válidas não repetidas.
LocalService S-1-5-19 demonstrada no clone 55441: configuração lida, ClamD 13310, quatro scans PDF de 20 MiB/trêsWebP, fila 4 → 0 e repetição 0 → 0, zero recursos novos/falhas e hashes/cifra recuperados; escrita só nas áreas QA autorizadas, negada em código/vendor/config/.env e leitura alheia negada. Tarefa própria removida. Limite180s/lease 210 s anteriores preservados como prova distinta de utilizador interativo. Não é instalação/prova do destino 3310.
191 ficheiros reconciliados:22código + 159 bundle + 1 env+9documentais, incluindo os 4 originais do destino com hashes iguais e 5 ficheiros sintéticos. Backup 799 do destino tem âmbito maior; os 8 documentais exclusivos da QA 188 continuam no backup anterior. Restauro QA renovado 16:49:42 UTC: 295 tabelas / 31 sequências / 191 ficheiros / 9 MFA; renovar o backup/restauro do destino real e associar à revisão antes da intervenção.
B3: responsável confirmou nala@tempo.co.mz (**ID 2**) e onala@me.com (**ID 13**); email/MFA/gestão legada verificados READ ONLY e compatibilidade do envelope validada no clone. IDs 3/18 iniciais reconciliados. Designação registada, sem conceder privilégios. Ainda faltam autorização/cerimónia cruzada e contas/organização/tipos/âmbito operacionais. B1/B2: serviços 3310, supervisão/limites e ACLs efetivas do destino por autorizar/verificar; RX adicional não neutraliza escrita herdada. Notificações OFF e nova leitura da default imediatamente antes de iniciar worker; parar perante classe desconhecida ou notificação enfileirada.
Mesma matriz: 3401 requisitos / 7739 ocorrências, três evidências complementadas, zero IDs/estados gerais novos. COUNTRY02 ativo e fechos A/B/C37 preservados. Restauração/partilha individual/190000/legado/modulares/ofertas/SLA permanecem fora. Os blocos seguintes mantêm o histórico.
<!-- /consolidated-workflow-qa-20261011 -->
<!-- service-followup-qa-20261011 -->
## Serviços e confirmação cruzada — QA de 11/10/2026
[Relatório](../../../../outputs/investmoz-service-followup-20261011/relatorio.md) e [evidências](../../../../outputs/investmoz-service-followup-20261011/evidencias-por-criterio.json).
PT3M real: processo terminado entre 178.227 e 180.244 s; job reservado retomado após lease 210 s, sem duplicações. PDF 2,5 MiB, imagem 3,3 MB/três WebP, PHP web 20M/POST 24M/GD/WebP e rejeições20 MiB+1/25 MiB/10 MiB+1 demonstrados. Fronteira 20 MiB: web201; CLI 128M falha por memória; comando já previsto 256M recupera mesmojob/original sem reenviar, pico 148 MiB. Plano preservado; não omitir -d memory_limit=256M. Default do destino lida sem executar:zero jobs/falhas; tipos/efeitoSMTP explicitados.
Bootstrap cruzado demonstrado como **delta QA 117d2d889701**, sem integração na candidata 98a8e0b70892: pedido15/confirmação16 com MFA e auditoria separados, sem autoaprovação; pedido recuperado em nova sessão, sem privilégio antecipado. Segundo titular sem gestão geral prévia. Zero DDL adicional, entidades/Fortify reutilizados. Terceiro inicializador não é exigência organizacional; a futura candidata deve incorporar a nova cerimónia.
RestauroQA pós-uso **2026-10-11T16:29:27+00:00**:295 tabelas/31 sequências/191 ficheiros/9 MFA; não substitui o destino. B1/B2: intervenção/provaLocalService / PHPweb/ClamD no destino; B3: dois titulares/âmbitos legítimos e integração do delta. Mesmas3401 linhas/7739 ocorrências, zero IDs/estados gerais novos. COUNTRY02/A-B/C37 preservados; restauração/partilha individualOFF. Os blocos seguintes conservam a história.
<!-- /service-followup-qa-20261011 -->
<!-- workflow-scope-qa-20261011 -->
<!-- workflow-upgrade-qa-20261011 -->
## Atualização do clone do destino — 98a8e0b70892
**QA demonstrada; ativo não atualizado.**030000→040000 autenticadas no clone real288→295;050000/COUNTRY02,originais,permissões,cifra/histórico preservados. PDF/PNG/DOCX/XLSX e3WebP com scanClamDreal/hash/recuperação;worker sai após reservar e recupera mesmojob210s depois;repetições sem duplicação. C127:Super requer perfil operacional no âmbito+elevação de consulta independente15min,sem aprovação própria;revogação/novo login e outro dossier recusados. C128:derivadas reutilizadas. UI390px e asset carregado conferidos. A/B,C37 e provas válidas conservadas.
Lista única de bloqueios:B1ClamD do destino stale;B2worker/PHPdocumental supervisionados por comprovar no destino;B3dois titulares+terceiro gestorMFA+âmbitos legítimos por designar. Instalações só sob futura autorização;190000 não bloqueia workflow isolado. Restauração e partilha individual permanecem desabilitadas. Candidata/código:98a8e0b70892/557cbad27987,17ficheiros/158assets,`activation_ready=false`. Relatório e procedimento:`outputs/investmoz-workflow-upgrade-20261011/`.
Mesma matriz3401requisitos/linhas,7739ocorrências;seteIDs atualizados,zero novos. Backup/restauro REAL do alvo `2026-10-11T15:11:50+00:00`:288tabelas/31seq/799ficheiros/2MFA;QA pós-uso `2026-10-11T15:11:55+00:00`:295/31/188/9MFA. Não transformar este restauroQA em prova de funcionamento ativo. Renovar após ajustes/revisão/expiração/antes da intervenção.
*As secções seguintes conservam evidências e estados históricos;este bloco contém o estado atual.*
<!-- /workflow-upgrade-qa-20261011 -->
## Candidata delimitada e proteção documental — 11/10/2026
C126 corrigido somente em QA: a rota geral exige a autorização atual da oportunidade. Originais, derivadas e revogação de perfil foram demonstrados; a ACL individual continua indisponível e explicada na interface. R-ARCHIVE e R-DRAFT são propostas separadas. As variantes imobiliárias excluídas continuam recuperáveis em preparação, com submissão recusada e erros semânticos preservados.
Nova candidata **e871f8aadb59**, código **d19dd63b67b4**: 14 ficheiros de código e 158 assets recompilados. [Relatório com âmbito, ACL e decisões](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/relatorio.md), [procedimento](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/procedimento.md), [manifesto](../../../../outputs/investmoz-opportunity-workflow-scope-20261011/manifesto.json). A referência `8af63e2fe657` mantém os bytes e o histórico, mas C126 impede a sua disponibilização.
Backup do **destino real** renovado em 2026-10-11T14:24:45+00:00: 288 tabelas, 31 sequências, 799 ficheiros e dois envelopes MFA, com restauro apenas em QA/55441. QA funcional: 295 tabelas, 31 sequências, 288 ficheiros e 17 envelopes MFA. A diferença de sete tabelas corresponde a 030000/040000; o acervo privado QA não foi importado no ativo.
**Ainda não pronto para ativação:** ClamD do destino com assinaturas obsoletas; worker/GD e processamento documental por demonstrar no destino; ensaio de atualização do clone e recibos/prévias específicos; designação de titulares e âmbitos legítimos. O destino tem apenas duas contas com MFA e o bootstrap exige dois titulares e um terceiro gestor independente com MFA: essa preparação humana falta. Zero geometrias no destino; importação separada se forem incluídos os limites administrativos. Não reaplicar 050000. 030000 precede 040000; 190000 permanece separado.
COUNTRY02 ativo, A/B e C37 preservados; nenhuma alteração no ativo. Mesma matriz: 3.401 requisitos/linhas, 7.739 ocorrências, dez requisitos existentes atualizados e zero IDs novos; estados gerais preservados.
<!-- workflow-fixed-candidate-20261011 -->
Revisão consolidada para revisão **8af63e2fe657**, código **f07f34a11eab**; C125 e arrendamento54 completo integrados. [Relatório/limitações](../../../../outputs/investmoz-opportunity-workflow-consolidated-final-20261011/relatorio.md), [manifesto](../../../../outputs/investmoz-opportunity-workflow-consolidated-final-20261011/manifesto.json), [procedimento e reversão](../../../../outputs/investmoz-opportunity-workflow-consolidated-final-20261011/procedimento.md), [pacote/hashes](../../../../outputs/investmoz-opportunity-workflow-consolidated-final-20261011/pacote.json).
Bundle anterior de produção conferido por hash, sem nova recompilação. Backup/restauro QA de **2026-10-11T13:40:15+00:00**: **295 tabelas,31 sequências,286 ficheiros**, incluindo acervo29/metadata3, três PDFs próprios54 e12ficheiros do delta. Não é backup do alvo ativo nem autorização de ativação. COUNTRY02 ativo/A-B/C37 preservados. A referência3d9d392e0a0f é histórica e permanece intacta.
# Workflow de oportunidades: critérios de saída em QA — 11/10/2026
Este incremento complementa a matriz existente. COUNTRY02 permanece ativo e intacto. A/B e C37 mantêm os fechos aceites. A integração do legado, o percurso integrado, os quatro módulos experimentais, ofertas e SLA são frentes separadas. Nenhuma instalação, habilitação, publicação ou alteração de dados no ambiente ativo foi realizada.
## Cobertura reaproveitada e cobertura nova
**Coedição:** `profiles-v1-http-qa.json`, de 10/10 às07:05:26UTC, já demonstrava QA22 a editar e recuperar o rascunho15 da organização de QA21, com recusas por organização/tipo/papel/estado. Essa prova não foi repetida. Faltava a utilização visual dos recursos pelo coeditor. Agora QA22 guardou país/hierarquia, recuperou noutra sessão e apresentou o limite no mapa. Alterar o país/pai limpou os descendentes. QA23 recebeu403 na leitura e escrita. Não foram acrescentadas associações territoriais aceites automaticamente.
Criação, rascunho incompleto, recuperação, correção e submissão anteriores são reutilizados, em particular o ciclo visual da oportunidade52. Suspensão/republicação do imóvel31 e recurso da parceria34 conservam os recibos anteriores. Os ensaios novos cobrem os ramos afetados pela materialidade e pelas condições, sem repetir A/B ou a autenticação da conta18.
## Resultado por categoria
| Categoria e caso QA | Semântica/documentos demonstrados | Materialidade e workflow novos na interface | Lacunas concretas que continuam abertas |
| --- | --- | --- | --- |
| Projeto de investimento,30/52 | Reconciliação das rubricas/financiamento, moeda e maturidade; recurso próprio com hash/scan; preparação e recuperação anteriores. Ensaio negativo de financiamento em memória, separado da interface. | Alterar mitigação de risco reabriu apenas `technical_review`. Revisão territorial manteve ator/data/hash. Condição bloqueou aprovação, foi resolvida com evidência, QA24 aprovou e QA25 disponibilizou com acesso restrito. GET Response não gravou nova versão. | Variantes económicas/licenças e obrigações externas específicas dependem do caso. Não existe certificação automática de viabilidade. Response normativo integral continua pendente. |
| Imobiliário,31 e arrendamento54 | Venda31 preservada;54 mantém renda4500 MZN/monthly, três documentos próprios scaneados, nova sessão e erros junto à renda previamente demonstrados. | Promotor21 submete→Validador24 solicita correção→Promotor21 corrige/resubmete→três gates24→aprovação24→Publicador25 disponibiliza com acesso restrito;14 recuperações de UI/Response e SQL confirmam renda/periodicidade. | Construção planeada, ocupação contratada, encargos e limites urbanísticos por variante; sem direito real ou decisão externa presumidos. |
| Fundiário/DUAT,32 | MultiPolygon vazio é recusado; limite administrativo não é parcela. Autorizações e documentos mantêm referências próprias. | Titular alterado reabriu só `land_legal_review`. Aprovação interna seguida de publicação422 por autorização externa pendente foi demonstrada. Um ramo adicional, **SIMULAÇÃO QA sem efeito jurídico**, acrescentou documento fictício identificado; reabriu só `competent_authority_clearance`, teve aprovação independente, disponibilização restrita e recuperação noutra sessão. | O ramo positivo não comprova direito real ou decisão externa. Casos reais de área/encargos/consulta/conflitos e compatibilidade cadastral têm de usar os seus próprios dados. As173 correspondências cartográficas pendentes continuam fora deste fecho. |
| Venda de negócio,33 | Preço zero recusado no contrato; identificação societária, financeiros e confidencialidade por referências próprias. Teaser público e proteção dos documentos têm provas anteriores. | Alterar registo da entidade reabriu só `corporate_screening`; condição resolvida, aprovação independente e publicação do teaser recuperadas. | Interesse em anúncio público de negócio existente `/negocios/{slug}/manifestar-interesse`, modalidades e estatística específica desse consumidor ainda têm variantes pendentes. Não confundir esse cadastro existente com a oportunidade canónica. Entidade sem histórico depende da proposta funcional separada. |
| Parceria de negócio,34 | Governação nula recusada; contribuições e documentos têm contrato próprio. Recurso anterior preservado. | Alterar voto reabriu apenas `legal_tax_due_diligence` e `partnership_governance_review`. Condição/evidência, aprovação independente e disponibilização restrita passaram. | Valores/condições de contribuições e responsabilidades reais por modalidade precisam de evidência. A revogação individual na sala de parceria não equivale a ACL documental individual de oportunidades; esse último mecanismo não foi acrescentado. |
| Franquia,35 | Marca vazia recusada; licença, território, exclusividade e taxas usam o contrato existente. | Alterar registo societário reabriu só `franchise_legal_review`; marca/licença, financeiro e confidencialidade conservaram assinaturas. Condição, resolução, aprovação independente e disponibilização restrita recuperadas. | Variantes de exclusividade, royalties e titularidade da licença não se encerram apenas pelo registo societário. Dados/licenças reais continuam necessários. |
Evidências novas: `functional-workflow-chromium-20261011.json` (seis categorias), `functional-land-publication-chromium-20261011.json`, `functional-materiality-semantic-qa-20261011.json`, `functional-category-semantics-qa-20261011.json`, `functional-conditions-semantic-qa-20261011.json` e `functional-final-persistence-qa-20261011.json`, no diretório privado da auditoria. Os recibos diferenciam interface, respostas e SQL; os ensaios em memória não são apresentados como cliques na interface.
## Correções executadas
1. **Materialidade v3:** titular/documento fundiário, área/unidade, comunidades, plano de exploração, identificação societária, histórico financeiro, governação/franquia e contacto interno passaram a integrar os pareceres pertinentes. Referências documentais aninhadas também incluem bytes/hash e disponibilidade. Uma correção editorial conserva os pareceres. As assinaturas v2 são verificadas pelo algoritmo original e conservam hash, ator e data; não foram recalculadas silenciosamente.
2. **Condições internas:** armazenadas no `workflow_context` e auditoria existentes, sem tabela paralela. Responsável autorizado explícito, data opcional, bloqueio de aprovação ou publicação, resolução por Validador com documento ativo/analisado. Mudança da evidência ou do parecer pertinente reabre a condição e conserva a resolução anterior. Nenhum responsável externo ou SLA é inferido.
3. **Filtro de oportunidades:** o formulário enviava `deleted=false`, recusado pela validação booleana da API. Agora envia0/1. O clique em Pesquisar foi demonstrado; categoria/estado/título e filas recuperam resultados e indicadores correspondentes ao conjunto autorizado.
4. **Indicadores:** incluídos os estados de correção, revisão, espera de informação e rejeição, antes omitidos dos cartões.
5. **Acessibilidade fundiária:** anel de parcela passou a ter rótulo sem salto de título; mapas de parcela/localização têm nomes acessíveis distintos. Repetidas só as rotas afetadas. Nove rotas incluídas passaram o conjunto automático ensaiado, teclado/atalho de conteúdo e ausência de overflow a320/390px. O erro bloqueante das condições recebeu foco e mensagem acessível.
## Mapas, filtros, estatísticas e documentos
- **Recursos da oportunidade15, QA22:** país MZ/Portugal, hierarquia Cabo Delgado/Ancuabe, limpeza dos descendentes, gravação, nova sessão e mapa, com outra organização negada.408 correspondências existentes preservadas;173 lacunas e Mandie/Guro ambíguo permanecem no inventário territorial. Nenhuma importação/divulgação de camada neste pacote.
- **Lista de oportunidades, QA21:** seis consultas por categoria/estado/texto/filas, após clique real no filtro. Indicadores somam o total do conjunto filtrado autorizado, não o estado antigo da ficha publicada.
- **Gestão de solicitações, QA17:** origem desconhecida e PT, combinadas com país MZ e pesquisa; campos e resultados separados. Estatísticas continuam por três coleções distintas e pelo filtro de origem. País/pesquisa filtram a lista, conforme a explicação da interface; não são apresentadas como investidores únicos. Provas anteriores de submissão/repetição dos quatro formulários públicos foram reutilizadas.
- **PDF privado na oportunidade15:** upload por QA22, scan ClamD real, hash recuperado pelo autor QA21, exclusão lógica e antigo URL404 nas duas sessões, restauro dos mesmos bytes, organização indevida403 e anónimo redirecionado ao login sem receber o PDF. Originais/cifra/auditoria preservados. Esta é retirada global do recurso, distinta de revogação de partilha individual. PDFs/exportações de Balcão, zonas e outros consumidores continuam por critério próprio.
- **Response/§27:** condições recuperáveis acrescentadas ao adaptador existente; versão/identificadores/história sem perdas. `normative_response_complete=false` permanece correto: IDs bigint de raiz/atores/setor, referência histórica, metadata de criação desconhecida e pareceres paralelos não são convertidos ou inventados. O adaptador é um contrato de compatibilidade, não uma declaração de conformidade normativa integral.
## Dependências verificadas conjuntamente
QA em `https://portal-investidor.test:18445`, PostgreSQL `stability_consumers_20261011_084534_test:55441`, guarda contra o ativo, PHP8.5.11/Apache equivalente, produção e HTTPS reconhecido.030000 e040000 já instalados; prévias autenticadas confirmaram dependências e schema, sem repetir instalação. Papéis/MFA, documentos, ClamD1.5.4 com assinaturas de11/10 e GD/WebP foram usados conjuntamente. A disponibilização do percurso integrado está OFF na QA deste lote:190000 não é bloqueio do workflow isolado.
As prévias mostram `ready=false` quando o recibo antigo não corresponde ao fingerprint novo. Isso não impede usar o schema já instalado em QA e não autoriza nova instalação. O restauro final deste lote é prova QA; prontidão de instalação ativa exige recibos correspondentes ao destino e ao código fixo.
**Leitura do serviço no destino,12:01:25UTC:** ClamD3310 responde, mas as assinaturas de09/10 têm51,59horas, além do limite48. `signatures_stale` bloqueia novos scans. Nenhuma atualização ativa foi executada. Fila configurada como `database` não comprova worker supervisionado. Atualização/manutenção das assinaturas e verificação do worker são dependências operacionais antes de disponibilizar anexos e derivadas no destino.
## Proposta de restauração para decisão
**R-ARCHIVE:** Publicador autorizado pelo âmbito/tipo, sem conflito com autoria/representação, restaura com motivo, versão/ETag, chave estável e auditoria. Retorno proposto: `needs_information`, apresentado como **preparação para nova revisão, não público**. Aprovação e publicação anteriores ficam no histórico, sem autorização vigente para publicar. Documentos/IDs/classificações permanecem. Nova submissão reavalia materialidade, evidências, competências e revogações; pareceres ainda válidos podem ser conservados, exigindo nova aprovação independente e ação explícita de publicação. Não repor automaticamente catálogo, visibilidade, publicação agendada ou acesso público anterior.
**R-DRAFT, decisão distinta:** para rascunho privado **nunca submetido nem publicado**, propor eliminação lógica e restauro ao autor ou a outro Promotor autorizado da organização, com representação/tipo válidos, motivo e auditoria, retornando apenas a `draft`. Essa autorização não decorre automaticamente da coedição aprovada e diverge da proibição genérica de exclusão pelo Promotor na v1. Rascunho pessoal fica limitado ao titular. Se já submetido/publicado, usar o workflow de arquivo/R-ARCHIVE. A regra de dependências deve conservar filhos/documentos e vedar eliminação física.
Perguntas para decisão: **aprovar R-ARCHIVE com retorno `needs_information` não público? Aprovar R-DRAFT para autor/Promotores autorizados da organização, restrito a nunca submetidos/publicados?** Nenhuma das duas regras foi implementada por antecipação. O serviço legado continua a rejeitar restauro de registos com autor; a candidata exclui esse restauro até à decisão.
## Fronteira da candidata e reversão
Código e bundle preparados exclusivamente em cópia privada QA. A candidata inclui workflow/condições/materialidade das seis categorias nos ramos ensaiados, recursos privados, filtros/indicadores e correções de acessibilidade enumeradas. Não habilita legado, ofertas, módulos experimentais, SLA ou percurso integrado, nem importa geometrias. Não encerra todas as modalidades de cada categoria, §27 integral, leitor de ecrã/dispositivos reais, partilhas individuais de oportunidades ou restauração ainda proposta.
Para disponibilização futura: renovar backup/restauro do **alvo ativo** e comparação da revisão; prévia correspondente030000 → aplicação autenticada apenas se ausente → prévia040000 → aplicação autenticada apenas se ausente. Bootstrap e habilitações funcionais legítimas são ações separadas; não escolher titulares, criar contas/organizações ou inventar representações. O ativo tem atualmente0 organizações/representações e não tem030000/040000. Instalar DDL não cria um percurso funcional sem habilitações.190000 fica para o pacote integrado.
Contenção: desligar apenas as flags do pacote de oportunidades/perfis, conservando COUNTRY02 ON, HTTPS, cookie/cifra, colunas, documentos e auditoria. Depois de uso, não executar `down`/drop nem restaurar a base inteira sem decisão própria. Manter o bundle/código anterior para contenção, preservando as estruturas aditivas; testar compatibilidade antes de substituição. A candidata não é apresentada como pronta para ativar enquanto ClamD, worker, habilitações e prévias/backup do destino não estiverem resolvidos.
<!-- functional-category-remaining-20261011 -->
## Critérios ainda não encerrados por categoria
As lacunas abaixo são variantes ou contratos adicionais, não uma repetição do ramo já demonstrado. “Preparado” não equivale a verificado na interface. IDs da matriz: AUD-OP-03/04, AUD-PROFILE-06/07/08/09/10/11/12/19/21/23/25/28/30/31, AUD-GEO-03, AUD-LIB-02/SCAN-01, AUD-STATS-01 e AUD-UI-01.
| Categoria | Semântica ainda por critério | Materialidade ainda por prova | Documentos ainda por consumidor | Response/§27 |
| --- | --- | --- | --- | --- |
| Projeto | Variantes de licenciamento e pressupostos de cenários. O caso30 reconcilia rubricas; não decide viabilidade nem aprova externamente. | Valores têm hash/gates e ensaio em memória; risco tem ciclo visual. Substituição de evidência aninhada foi ensaiada em memória, não como substituição visual completa por cada variante económica. | Original/derivadas próprias têm recibos anteriores e retirada global tem prova nova. PDF/exportações de outros consumidores e ACL individual de oportunidade não ficam incluídos. | Adaptador com condições, GET sem gravação e hashes recuperados; lacunas normativas comuns abaixo. |
| Imobiliário | Venda31 e arrendamento54 demonstrados;54 preserva4500 MZN/mês. Construção/ocupação/limites urbanísticos ainda por variante. | Venda: titular alterado reabre registry_urban_review; arrendamento: correção/revisão independente nos três gates, hashes assinados recuperados. | Três documentos próprios de54: título/registo, licença e avaliação, todos SIMULAÇÃO QA com scan real/recuperação por hash; ramos documentais restantes pendentes. | Response compatível recuperado, forma normativa§27 ainda parcial; IDs/história preservados. |
| Fundiário | Parcela vazia recusada; polígono administrativo não atribui terra. QA32 positiva é simulação expressa. Faltam situações reais de consulta, encargos/conflitos e compatibilidade cadastral. | Titular e ato externo tiveram ciclos diferentes. Área/unidade/comunidades/plano pertencem aos gates no código; variantes visuais adicionais precisam de casos próprios. | Ato externo sintético identificado testou o bloqueio/libertação em QA. Não comprova direito real. Sem importação cartográfica neste pacote;173lacunas e ambiguidade preservadas. | Mesmas lacunas comuns, autorização interna e decisão externa separadas. |
| Venda de negócio | Preço/entidade/teaser ensaiados. Origem/país/repetição/estatísticas do interesse no anúncio existente não encerrados por esta oportunidade canónica; entidade sem histórico continua na proposta separada. | Identificação societária visual; financeiros, histórico/projeções e confidencialidade estão nos gates v3, faltando variantes visuais individuais. | Documentos próprios e teaser separados; mandato e destinatários por modalidade precisam de critério próprio. | Compatibilidade não estabelece equivalência automática com o anúncio do cadastro existente. |
| Parceria | Governação/contribuições com contrato; variantes de obrigações, valor indicativo e responsabilidades reais não presumidas. | Voto alterado reabriu dois gates e preservou os demais. Contribuição monetária/não monetária e documentos adicionais ainda por variante visual. | Revogação na sala1 é prova desse consumidor. ACL individual de documentos de oportunidade não foi acrescentada; retirada global15 não a substitui. | Pareceres paralelos conservados no contexto; sem converter para um único estado normativo fictício. |
| Franquia | Marca e identificação têm critérios demonstrados. Variantes de exclusividade, royalties e licença/território requerem evidência própria. | Registo societário visual; licença, marca, taxas/território estão nos gates, mas os ramos visuais distintos continuam pendentes. | Licença/documentação própria ligada; variantes de titularidade/confidencialidade por destinatário não fechadas por35. | Compatibilidade e recuperação demonstradas; mesmas lacunas normativas comuns. |
**Lacunas comuns de§27:** IDs bigint existentes para raiz/atores/setor, referência histórica existente, metadata de criação histórica desconhecida e pareceres paralelos. O adaptador não satisfaz a forma normativa integral; estes valores não serão transformados nem inventados. A candidata aceita explicitamente o contrato de compatibilidade existente e expõe `normative_response_complete=false`. Uma eventual migração de identidade/estados exige desenho e aprovação próprios, não está escondida neste lote.
## Consumidores incluídos: saída e limite
| Rota | Perfil e ação | Evidência de saída | Critério que permanece fora desse fecho |
| --- | --- | --- | --- |
| `/minhas-oportunidades` | Promotor21: categoria/estado/texto/filas | Clique Pesquisar,6consultas, indicadores e SQL independente coincidentes. Teclado/atalho/axe/320/390px. | Combinações novas de filtros e outras filas/perfis por variante; leitor real. |
| `/minhas-oportunidades/15/edit` e`/resources` | Coeditor22: país/hierarquia/mapa/PDF; autor21 recupera; outraorg23 recusa | Coedição prévia HTTP preservada. Nova sessão, mapa Cabo Delgado/Ancuabe, limpeza de descendentes, original scaneado/hash, retirada404/restauro mesmosbytes. | Coedição de correção pós-submissão e revogação do coeditor nessa ação; ACL individual. |
| `/minhas-oportunidades/30..35/view` | Promotor/Validador24/Publicador25: materialidade/condição/aprovação/publicação | Seis ramos novos com recuperações, independência e GET Response sem nova versão. Land32 positiva recuperada noutra sessão; publicação prévia422 externa preservada. | Variantes da tabela acima; restauração de oportunidade aguardando política. |
| `/management/interests` | Gestão17: origem unknown/PT+paísMZ+texto | Listas e três coleções estatísticas separadas; origem determina estatística, país/texto determinam lista, conforme UI. | Interesse público de negócio existente e outras modalidades/transições; país/texto não passam a filtrar estatísticas por inferência. |
| `/management/opportunity-resources-install` | Gestor17/MFA: prévia030000 | InstaladoQA, fingerprint/dependências recuperados; nenhuma reinstalação. | Prévia/prontidão/backup do alvo ativo ainda necessários. |
| `/management/profile-install` | TitularQA26/MFA: prévia040000 | Ledger/schema8itens/dependências consistentes e dupla existente preservada. | Bootstrap/designações legítimas no ativo e prévia correspondente. |
A revisão de acessibilidade inclui9rotas, não todo o portal; leitor de ecrã real, dispositivos físicos e PDFs etiquetados continuam separados. Mapas partilhados mantêm o resultado anterior quando não há geometria: não há preenchimento fictício.
## Recuperação e destino
Restauro QA anterior de12:10:22UTC:295tabelas,31sequências,270ficheiros,16envelopes MFA normais recuperáveis. Conta19 é o controlo **Synthetic wrong-key MFA negative control QA**, criado por`tools/portal-qa-mfa.php` com chave estrangeira; deve continuar a rejeitar desencriptação. Não foi reparada nem autenticada. Os envelopes herdados13/2 recuperam com a chave da origem conservada no backup privado. Nenhuma chave/cifra/conta foi alterada, e C37 não foi reaberto.
Leitura ativa em12:14:31UTC, transaçãoREADONLY:288tabelas,13contas,0organizações/representações,1990territórios cadastrados e **0geometrias**.020000/050000 presentes;030000/040000/190000 ausentes. COUNTRY02ON e demais flagsOFF; manifesto ativo`250ae618d716c0ffff1cfe3409cf55ba18e52f0ec86d305aa938fe2375adda4b`conservado. Assim, mostrar limites administrativos no destino requer importação cartográfica **separadamente autorizada**; territórios cadastrados não a substituem. A candidata atual não importa nem publica camadas.
O backup QA não renova o backup/restauro ativo. O cenário organizacional continua dependente de cadastro/representação legítimos; a alternativa individual exige perfil funcional autorizado e não inventa organização.
<!-- functional-candidate-link-20261011 -->
Candidata anterior preservada **3d9d392e0a0f**, código **df6be252f1a0**. [Relatório e limitações](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/relatorio.md), [procedimento/reversão](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/procedimento.md), [manifesto](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/manifesto.json) e [pacote/hashes](../../../../outputs/investmoz-opportunity-workflow-candidate-20261011/pacote.json).
<!-- workflow-lease-20261011 -->
## Atualização — variante de arrendamento54
Chromium HTTPS QA/Promotor21: dashboard → Minhas oportunidades → Nova oportunidade → arrendamento54; rascunho incompleto guardado/recuperado noutra sessão; renda -1 recusada422 com mensagem junto ao campo/aria-invalid/aria-describedby, input preservado mas valor não gravado; renda4500/periodicidade monthly corrigidas e apresentadas noutra sessão. ResponseGET e SQL coincidem. C125: uma opção por organização/tipo apesar de concessões repetidas; QA22 continua apenas com o seu tipo, sem alterar papéis/representações. Recibos functional-lease-editor-chromium-20261011.json/functional-lease-persistence-qa-20261011.json. Venda31/A-B/C37 preservados.
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.
<!-- workflow-lease-consolidated-20261011 -->
## Arrendamento completo e critérios atuais — 11/10/2026
Arrendamento54: três PDFs próprios de título/registo, licença de utilização e avaliação, explicitamente SIMULAÇÃO QA, upload por UI→scan real ClamD→download/hash em nova sessão; Promotor21 submete→Validador24 solicita correção fundamentada→Promotor21 corrige/resubmete→três revisões independentes24→aprovação24→Publicador25 disponibiliza com acesso restrito. Quatorze recuperações de UI/Response mantêm renda4500 MZN/periodicidade monthly; SQL, snapshots de edição e auditoria coincidem. QA23/organização distinta recebe403 no contrato e no documento; autor não tem ações de aprovação/publicação. Provas functional-lease-workflow-chromium-20261011.json / functional-lease-workflow-persistence-qa-20261011.json. Provas anteriores de múltiplos papéis, seis categorias, coedição, A/B e C37 reutilizadas sem repetição.
| Categoria | Casos reutilizados | Critérios demonstrados | Critérios restantes |
| --- | --- | --- | --- |
| Projeto | 30; rascunho52 | Contrato, materialidade/condições, correção/revisão/aprovação/publicação recuperadas. | Cenários económicos/licenças externos aplicáveis; análise interna não certifica viabilidade. |
| Imobiliário | Venda31; arrendamento54 | Venda preservada. Arrendamento com documentos próprios, correção, três gates independentes e publicação restrita;4500 MZN/mês preservados. | Construção planeada/em curso, ocupação contratada, encargos e limite urbanístico por ramo; sem inventar ato/direito real. |
| Fundiário | 32 | Dependência externa bloqueia publicação; ramo positivo sintético explicitamente identificado, aprovação/publicação restrita e recuperação. | Casos reais de consulta/conflitos/encargos/área/cadastro.173 correspondências pendentes e Mandie/Guro ambíguo preservados. |
| Venda de negócio | 33 | Identidade societária, confidencialidade, condição, aprovação independente e teaser público com documentos protegidos. | Interesse no anúncio /negocios/{slug}/manifestar-interesse e suas estatísticas; financeiros/histórico por variante; entidade sem histórico é decisão separada. |
| Parceria | 34 | Voto reabre só dois gates; demais pareceres conservados; condição/aprovação/publicação restrita recuperadas. | Contribuições monetárias/não monetárias por modalidade e documentação própria; ACL documental individual de oportunidade não demonstrada. |
| Franquia | 35 | Registo societário reabre apenas gate aplicável, preservando financeiro/licença/confidencialidade; aprovação/publicação restrita recuperadas. | Exclusividade, royalties, titularidade de licença e território por ramo próprio. |
Comuns: Response de compatibilidade recuperável (`normative_response_complete=false`), sem conversões de IDs/história; §27 integral continua parcial. R-ARCHIVE e R-DRAFT são decisões distintas pendentes, sem implementar restauração automática. Acessibilidade das9rotas/320/390px já demonstrada é preservada; teclado/leitor real, PDFs etiquetados e dispositivos físicos não se tornam concluídos por este ensaio. Legado, ofertas, competências modulares e SLA permanecem frentes separadas. COUNTRY02 ativo e fechos A/B/C37 preservados. Nenhuma alteração ativa.
Matriz:3401requisitos/linhas;7739ocorrências.9linhas existentes atualizadas em cada projeção,0novosIDs, estados gerais preservados; o percurso específico de arrendamento fica demonstrado em QA.
@@ -1,6 +1,7 @@
# InvestMoz — contratos e workflow de oportunidades em QA
<!-- qa-response-20261010:begin -->
## Incremento atual — Response/§27 e propostas para decisão
Somente QA **http://127.0.0.1:18097**, `desk_restore_20261009_174726_test:55441`. Mesmo inventário/matriz; nenhum fecho integral ou escrita ativa.
@@ -20,18 +21,19 @@ Provas: `opportunity-response-http-qa.json`, `OpportunityCanonicalWorkflowTest`,
<!-- qa-response-20261010:end -->
<!-- qa-installation-cartography-20261010:begin -->
## Estado atual — instalador, documentos e cartografia
QA exclusivamente: **http://127.0.0.1:18097**, `desk_restore_20261009_174726_test:55441`. Ativo inspecionado apenas por leitura em 2026-10-10T12:26:56+00:00: 030000, 040000 e 09/190000 ausentes; zero geometrias; manifesto preservado. **C37, Promotor QA21 e A/B permanecem visualmente pendentes. Candidata à ativação ainda não fixada.**
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --- | --- | --- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
Prova de recuperação QA: dump consistente → nova base `profile_restore_20261010_123125_test:55441` → **295 tabelas com linhas/hashes iguais e 71 ficheiros fisicamente recuperados por hash**; todos os ficheiros referenciados recuperados por hash. Arquivo privado inclui o runtime e a chave QA estável. Readiness só atesta preparação técnica desta revisão. Repetir após fixar a candidata e preparar backup ativo apenas numa futura ativação autorizada.
@@ -43,24 +45,25 @@ Prova de recuperação QA: dump consistente → nova base `profile_restore_20261
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Resultado atual por categoria — semântica e atribuições em QA, 10/10/2026
Este bloco conserva a revisão semântica anterior; o estado atual está no início do documento; as secções anteriores abaixo permanecem como histórico. Estados antigos sobre objetos opacos, coordenação editorial e ausência de 190000 ficam confrontados com os resultados concretos deste bloco. **Código preparado e HTTP/persistência em QA não encerram interface nem funcionalidade ativa.** Não houve escrita na base ativa. C37 e aceitação visual permanecem pendentes.
Servidor **http://127.0.0.1:18097**, base **desk_restore_20261009_174726_test:55441**, Fortify e MFA normais. **Promotor QA 21** continua a conta de ensaio do dashboard. Não usar Auditor ou Superutilizador em seu lugar.
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| --- | --- | --- | --- | --- | --- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| ------------------------- | -------------------------------- | ------------------------------- | ------------------------------- | ------------------------- | --------------------------------------------- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
As dez categorias recuperaram dados noutra sessão autenticada. As seis com contrato definido aceitaram os cenários semânticos documentados; as quatro restantes conservaram rascunhos, sem inventar um perfil modular para as submeter. Fundiário #32 separa aprovação interna da decisão externa. Venda #33 passou depois pelo percurso editorial público, sem divulgar resumo/dados privados.
@@ -78,28 +81,27 @@ As dez categorias recuperaram dados noutra sessão autenticada. As seis com cont
Mesma matriz: **3.386 requisitos / 3.386 linhas**, **6.838 ocorrências de origem**. IDs, fontes, critérios, versões divergentes e referências anteriores conservados.
| Estado canónico | Requisitos | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências de origem |
| ------------------------------- | ---------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31 e AUD-OPS-01**, em [matriz-requisitos.csv](matriz-requisitos.csv). Nenhum desses critérios visuais foi fechado por API.
## Próximo trabalho executável e decisões separadas — lote semântico atual
| Prioridade / requisito | O que já tem prova QA | Falta / próxima ação e critério concreto |
| --- | --- | --- |
| P0 — UI-01/C37 | Diagnóstico/MFA preservados; ensaios HTTP21 não fecham18. | C37 e confirmação visual continuam pendentes conforme pedido. Quando retomados, dashboard→MFA→sessão→refresh→logout→novo login; rastreio sanitizado e primeiro ponto de perda. Nenhum novo teste visual solicitado agora. |
| P1 — OP-04 / PROFILE-28/25 | Seis editores/regras no contrato do servidor; dez drafts e doze rejeições por campo recuperadas. | Observar cada categoria na UI21, erro junto ao controlo e nova sessão; reconciliar unidades aplicáveis, entidade/título/cadastro e limites urbanísticos com gates; completar Response/§27 apenas reutilizando entidades. Não regredir source/enums/IDs ou tornar campos incompletos obrigatórios para guardar. |
| P1 — OP-03 / PROFILE-11/12/19 | Filas, parecer atribuído, resposta, revisão e coordenação editorial com task/hash/papéis; negações específicas. | Interface por24/25/29, reatribuição e revogação; incidentes, disponibilidade e revisão periódica. Parecer externo requer responsabilidade institucional concreta, não um ator fictício; aprovação interna não substitui decisão externa. |
| P1 — GEO-03 / COUNTRY/STATS | Seis contratos ligam localização/documentos por IDs e país MZ; investimento recupera mercadoFR; editores consultam geometrias no nível selecionado. | Verificar visual de todos os consumidores afetados, país/origem→recuperação→filtro→estatística por formulário. Resolver nomes pendentes do pacote:31distritos+157postos; localidades/parcelas não inferidas de limites administrativos. Reutilizar importação autenticada/idempotente; publicação de camada é separada. |
| P1 — OP-02 / LIB / PROFILE-23 | Originais por perfil, negação de organização23, cifragem/hash, PNG e duas derivadas ClamD; PDF do ensaio atual separado. | Continuar DOCX/XLSX, partilhas, PDFs/exportações/derivadas sem prova específica; preservar originals/versões. Consistência de erro404 recurso excluído versus423 scan pendente foi corrigida no consumidor de oportunidades. |
| P1 — PROFILE-23 | Dois avisos preexistentes de league/commonmark identificados no lote anterior. | Avaliar consumidores e corrigir compatibilidade emQA; não apagar o achado nem atribuir a Opis. |
| P2 — PROFILE-31 / OPS-01 | 190000confirmadaQA/ausenteativo;030/040QA;baseBalcãoativa instalada, hashes atualizados. | Construir instalação/bootstrap autenticados040 com duasidentidades reais explicitamente designadas; não mudar titulares nem retirar privilégio ativo automaticamente. Apósvisual, fixar candidata e renovarbackup/restauro dessa revisão; executar apenas migrações faltantes pelo mecanismo adequado. |
| Prioridade / requisito | O que já tem prova QA | Falta / próxima ação e critério concreto |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| P0 — UI-01/C37 | Diagnóstico/MFA preservados; ensaios HTTP21 não fecham18. | C37 e confirmação visual continuam pendentes conforme pedido. Quando retomados, dashboard→MFA→sessão→refresh→logout→novo login; rastreio sanitizado e primeiro ponto de perda. Nenhum novo teste visual solicitado agora. |
| P1 — OP-04 / PROFILE-28/25 | Seis editores/regras no contrato do servidor; dez drafts e doze rejeições por campo recuperadas. | Observar cada categoria na UI21, erro junto ao controlo e nova sessão; reconciliar unidades aplicáveis, entidade/título/cadastro e limites urbanísticos com gates; completar Response/§27 apenas reutilizando entidades. Não regredir source/enums/IDs ou tornar campos incompletos obrigatórios para guardar. |
| P1 — OP-03 / PROFILE-11/12/19 | Filas, parecer atribuído, resposta, revisão e coordenação editorial com task/hash/papéis; negações específicas. | Interface por24/25/29, reatribuição e revogação; incidentes, disponibilidade e revisão periódica. Parecer externo requer responsabilidade institucional concreta, não um ator fictício; aprovação interna não substitui decisão externa. |
| P1 — GEO-03 / COUNTRY/STATS | Seis contratos ligam localização/documentos por IDs e país MZ; investimento recupera mercadoFR; editores consultam geometrias no nível selecionado. | Verificar visual de todos os consumidores afetados, país/origem→recuperação→filtro→estatística por formulário. Resolver nomes pendentes do pacote:31distritos+157postos; localidades/parcelas não inferidas de limites administrativos. Reutilizar importação autenticada/idempotente; publicação de camada é separada. |
| P1 — OP-02 / LIB / PROFILE-23 | Originais por perfil, negação de organização23, cifragem/hash, PNG e duas derivadas ClamD; PDF do ensaio atual separado. | Continuar DOCX/XLSX, partilhas, PDFs/exportações/derivadas sem prova específica; preservar originals/versões. Consistência de erro404 recurso excluído versus423 scan pendente foi corrigida no consumidor de oportunidades. |
| P1 — PROFILE-23 | Dois avisos preexistentes de league/commonmark identificados no lote anterior. | Avaliar consumidores e corrigir compatibilidade emQA; não apagar o achado nem atribuir a Opis. |
| P2 — PROFILE-31 / OPS-01 | 190000confirmadaQA/ausenteativo;030/040QA;baseBalcãoativa instalada, hashes atualizados. | Construir instalação/bootstrap autenticados040 com duasidentidades reais explicitamente designadas; não mudar titulares nem retirar privilégio ativo automaticamente. Apósvisual, fixar candidata e renovarbackup/restauro dessa revisão; executar apenas migrações faltantes pelo mecanismo adequado. |
Decisões independentes, sem bloquear este lote:
@@ -109,48 +111,45 @@ Decisões independentes, sem bloquear este lote:
Não iniciar jornadas educativas novas. Mantêm-se cinco fases/19 etapas e URLs, dossier privado, oportunidade publicada, fontes oficiais aceites e histórico.
## Ativação reconciliada: 030000, 040000 e **09/190000** — nenhuma execução no ativo
A omissão de **2026_10_09_190000_prepare_investor_path** na sequência anterior foi um erro documental; a extensão **continua necessária e não foi substituída**. Não confundir com **2026_10_07_190000_create_internal_virtual_desk**, que já está instalada no ativo.
| Recurso | QA restaurada:55441 | Ativo investemoz:5432, READ ONLY | Evidência |
| --- | --- | --- | --- |
| Gestão020000 | Instalada | Instalada | Ledger/schema anteriores preservados |
| Balcão07/190000 e orientação08/120000 | Instalados | Ambos no ledger | Leitura efetiva das migrações, sem boot de sessão ativa |
| Recursos09/030000 | Instalada | Ausente | Tabelas e ledger; não repetirQA |
| Perfis10/040000 | Instalada | Ausente | Tabelas/verificaçãoQA; nunca instalada no ativo neste trabalho |
| Percurso09/190000 | **Ledger + duas colunas + definição publicada** | **Ledger ausente; duas colunas ausentes; nenhuma definição** | `dashboard-active-readonly.json`, `opportunity-semantic-environment-qa.json` |
| Recurso | QA restaurada:55441 | Ativo investemoz:5432, READ ONLY | Evidência |
| ------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| Gestão020000 | Instalada | Instalada | Ledger/schema anteriores preservados |
| Balcão07/190000 e orientação08/120000 | Instalados | Ambos no ledger | Leitura efetiva das migrações, sem boot de sessão ativa |
| Recursos09/030000 | Instalada | Ausente | Tabelas e ledger; não repetirQA |
| Perfis10/040000 | Instalada | Ausente | Tabelas/verificaçãoQA; nunca instalada no ativo neste trabalho |
| Percurso09/190000 | **Ledger + duas colunas + definição publicada** | **Ledger ausente; duas colunas ausentes; nenhuma definição** | `dashboard-active-readonly.json`, `opportunity-semantic-environment-qa.json` |
DefiniçãoQA `61000919-0000-4000-8000-000000000001`, publicada, SHA256 **e0acbc723cd3def7e415b2ef7a0173add08387c3cedabac9bb7b86409e4d25bf**. Duas colunas: `investor_journeys.path_definition_id` e `journey_steps.path_detail`. Mantém cinco fases e rastreabilidade das19etapas; não renumera/reescreve os roteiros existentes. Recurso preparado/definição publicada não demonstra A/B na interface.
Dependências verificadas no código: **030000** usa oportunidades/documentos existentes e cria três coleções de recursos; **040000** acrescenta quatro tabelas de autorização/auditoria, uma coluna de revisão em users e três colunas em opportunities, preservando identidades/histórico; não usa as colunas de190000. **190000** usa investor_journeys/journey_steps/questionnaire_versions e depende da baseBalcão/orientação incluída no instalador. Não existe dependência DDL entre030/040 e190; disponibilizar o workflow requer020+030+040 e tasks/catalogue existentes; disponibilizar o percurso integrado requer190 e as capacidades instaladas/configuradas. Os fingerprints incluem código comum de perfis: alterar o código invalida provas antigas de readiness, sem converter isso numa dependência de schema.
| Ordem futura | Ação concreta e efeito / contagem esperada | Dependência e reversão |
| --- | --- | --- |
| 0 | Incorporar visualC37/Promotor21/A-B; corrigir falhas e fixar revisão/manifesta/configuração. Renovar dumpDB+ficheirosoriginaisprivados+chaveestável e restauroverificado numa novaQA. | Candidata ainda não fixada; provas antigas não são backup dessa revisão. Nunca key:generate indiscriminado. |
| 1 | Disponibilizar código/Composer/bundle após aprovação de ativação, flagsfalse. | Nesta análise só buildQA foi atualizado; manifestativo preservado. Reversão para código/build anteriores e flagsfalse; assegurar compatibilidade de leitura. |
| 2 | **030000**, se ledger/schema realmente ausentes: préviaGET e aplicaçãoPOST autenticada `/management/opportunity-resources-install` com hash/confirm. | Três coleções resource e metadado de cifra; **zero documentos/dados publicados/importados**. Base020/documentos existentes. Downgrade destructive recusado se originais cifrados usados. |
| 3 | **040000**, se ausente: instalar quatro tabelas/colunas através de mecanismo autenticado e bootstrap/recuperação da dupla, ainda por implementar paraativo. | Não substituir por migrateglobal/configmanual para contornar guarda. **Zero contas/grants QA** noativo. Titulares/reconciliação de permissões reais precisam de decisão explícita. Código independente de190. |
| 4 | **09/190000**, se ausente: préviaGET e aplicaçãoPOST autenticada `/management/balcao-install`; instalador seleciona só migrações faltantes. | BaseBalcão07/190000 e orientação08/120000 jáconstamdoativo: não repetir. **Duas colunas + uma definição publicada**, se não existir equivalente; **zero dossiers/journeys criados automaticamente**. Versões publicadas imutáveis. |
| 5 | Configurar catálogos/responsabilidades reais e instalar apenas contratos modulares aprovados; comparar IDs/citações/versões. | A autoridade sintética QA3e1ff315… e atores21–31 não são dados deativação. Sem alteração automática de valores legados. |
| 6 | Importação cartográfica autenticada privada `/management/territory-geometry-import`: prévia/correspondências/hash→aplicação idempotente→auditoria. | QA393=11províncias+128distritos+254postos; ativo0naúltimaleitura. **393 candidatas inequívocas**, sujeitas à prévia da revisão e aos mesmos IDs;188pendentes(31/157), sem criar geometrias falsas. Contagem final deve ser medida no alvo. Reversão por lote/metadados e histórico, sem apagar cadastros. |
| 7 | Ativar flags de perfis/oportunidades e percurso separadamente, testar navegação completa e permissões. | 030/040 antesdoscontratos/workflow;190antesdodisponibilizarpercurso; C37/visual/A-B não encerrados. Preparação paralela e acesso direto continuam. |
| 8 | **Publicar camadas, oportunidades ou documentos como ações separadas e explícitas**. | Nenhuma instalação/importação publica automaticamente; publicação não ativa cálculo fiscal. Usar decisões/evidências/hash atuais e autorização de divulgação. |
| Ordem futura | Ação concreta e efeito / contagem esperada | Dependência e reversão |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Incorporar visualC37/Promotor21/A-B; corrigir falhas e fixar revisão/manifesta/configuração. Renovar dumpDB+ficheirosoriginaisprivados+chaveestável e restauroverificado numa novaQA. | Candidata ainda não fixada; provas antigas não são backup dessa revisão. Nunca key:generate indiscriminado. |
| 1 | Disponibilizar código/Composer/bundle após aprovação de ativação, flagsfalse. | Nesta análise só buildQA foi atualizado; manifestativo preservado. Reversão para código/build anteriores e flagsfalse; assegurar compatibilidade de leitura. |
| 2 | **030000**, se ledger/schema realmente ausentes: préviaGET e aplicaçãoPOST autenticada `/management/opportunity-resources-install` com hash/confirm. | Três coleções resource e metadado de cifra; **zero documentos/dados publicados/importados**. Base020/documentos existentes. Downgrade destructive recusado se originais cifrados usados. |
| 3 | **040000**, se ausente: instalar quatro tabelas/colunas através de mecanismo autenticado e bootstrap/recuperação da dupla, ainda por implementar paraativo. | Não substituir por migrateglobal/configmanual para contornar guarda. **Zero contas/grants QA** noativo. Titulares/reconciliação de permissões reais precisam de decisão explícita. Código independente de190. |
| 4 | **09/190000**, se ausente: préviaGET e aplicaçãoPOST autenticada `/management/balcao-install`; instalador seleciona só migrações faltantes. | BaseBalcão07/190000 e orientação08/120000 jáconstamdoativo: não repetir. **Duas colunas + uma definição publicada**, se não existir equivalente; **zero dossiers/journeys criados automaticamente**. Versões publicadas imutáveis. |
| 5 | Configurar catálogos/responsabilidades reais e instalar apenas contratos modulares aprovados; comparar IDs/citações/versões. | A autoridade sintética QA3e1ff315… e atores21–31 não são dados deativação. Sem alteração automática de valores legados. |
| 6 | Importação cartográfica autenticada privada `/management/territory-geometry-import`: prévia/correspondências/hash→aplicação idempotente→auditoria. | QA393=11províncias+128distritos+254postos; ativo0naúltimaleitura. **393 candidatas inequívocas**, sujeitas à prévia da revisão e aos mesmos IDs;188pendentes(31/157), sem criar geometrias falsas. Contagem final deve ser medida no alvo. Reversão por lote/metadados e histórico, sem apagar cadastros. |
| 7 | Ativar flags de perfis/oportunidades e percurso separadamente, testar navegação completa e permissões. | 030/040 antesdoscontratos/workflow;190antesdodisponibilizarpercurso; C37/visual/A-B não encerrados. Preparação paralela e acesso direto continuam. |
| 8 | **Publicar camadas, oportunidades ou documentos como ações separadas e explícitas**. | Nenhuma instalação/importação publica automaticamente; publicação não ativa cálculo fiscal. Usar decisões/evidências/hash atuais e autorização de divulgação. |
Reversão: desativarflags/voltarbundle compatível e conservar originais/auditoria. Migrações usadas não devem ser eliminadas por rollback genérico;190recusadownquandohápercurso,030recusacomcifrados,040preservaperfil/oportunidade. Quando necessária reversão de dados, usar o restauroverificado da candidata com reconciliação das escritas posteriores. **ready=true é preparação; não instalação, ativação nem aceitação funcional.**
## Reprodução e evidências adicionais — mesmo inventário
| Caso / requisito | Passos e esperado | Observado / causa | Correção e estado |
| --- | --- | --- | --- |
| C55 — OP-02 | QA21→PDF limpo→exclusão lógica→GETdownload. Esperado: recurso indisponível, sem atribuir falha de scan. Restaurar e recuperar original. | HTTP423/quarentena porque download juntava row inexistente à condição de scan. | Separa ausência/exclusão404 de quarentena423; teste específico e ensaioPDFweb18097. Originais/hash preservados; visualpendente. Prova da falha `opportunity-semantic-documents-http-qa-attempt1.json`. |
| C56 — OP-04/PROFILE-25 | Promotor21 abre editor de categoria; campos de núcleo devem ter um único valor/controlo e erros associados. | Revisão do código: formulário legado e contrato canónico duplicavam título/território/campos, com valores independentes. | Contrato canónico único no modo perfil; formulário legado continua na gestão própria. BuildQA/TS e payloadAPI; observação visualpendente. |
| C57 — OP-04/PROFILE-28 | Guardar fim anterior ao início/ciclo/serviços incompletos/documento estrangeiro/comunidade sem consulta/financeiros incompletos; recuperar noutra sessão; submeter. | Regras anteriores aceitavam objetos opacos sem semântica suficiente. | 12negativas422 com caminho de campo; rascunhos recuperados; seis cenários completos submetidos/revistos. Não extrapolar a regras jurídicas ainda sem âmbito/gate. |
| C58 — OP-03/PROFILE-19/12 | Parecer com destinatário técnico/jurídico; responder outro ator; aprovar pendente. Depois atribuir publicação e tentar outro Publicador. | Fluxo anterior não tinha destinatário/resposta/fila completa nem atribuição editorial. | #30destinatário29/resposta/tarefa;outro403/aprovação422; #33filaeditorial29/outro25publica403/designado29publica. Sem gateautoaprovado/prazofictício; visualpendente. |
| 190000 — OPS-01/PROFILE-31 | Comparar ledger/duascolunas/definição QA eativo, distinguir migraçãoBalcão07 depercurso09. | Plano anterior omitia recurso ainda ausenteativo. | 09/190000confirmadaQA e ausenteativo, necessária/nãosubstituída; seqüência autenticada recolocada. Nenhuma execuçãoativa. |
| Caso / requisito | Passos e esperado | Observado / causa | Correção e estado |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| C55 — OP-02 | QA21→PDF limpo→exclusão lógica→GETdownload. Esperado: recurso indisponível, sem atribuir falha de scan. Restaurar e recuperar original. | HTTP423/quarentena porque download juntava row inexistente à condição de scan. | Separa ausência/exclusão404 de quarentena423; teste específico e ensaioPDFweb18097. Originais/hash preservados; visualpendente. Prova da falha `opportunity-semantic-documents-http-qa-attempt1.json`. |
| C56 — OP-04/PROFILE-25 | Promotor21 abre editor de categoria; campos de núcleo devem ter um único valor/controlo e erros associados. | Revisão do código: formulário legado e contrato canónico duplicavam título/território/campos, com valores independentes. | Contrato canónico único no modo perfil; formulário legado continua na gestão própria. BuildQA/TS e payloadAPI; observação visualpendente. |
| C57 — OP-04/PROFILE-28 | Guardar fim anterior ao início/ciclo/serviços incompletos/documento estrangeiro/comunidade sem consulta/financeiros incompletos; recuperar noutra sessão; submeter. | Regras anteriores aceitavam objetos opacos sem semântica suficiente. | 12negativas422 com caminho de campo; rascunhos recuperados; seis cenários completos submetidos/revistos. Não extrapolar a regras jurídicas ainda sem âmbito/gate. |
| C58 — OP-03/PROFILE-19/12 | Parecer com destinatário técnico/jurídico; responder outro ator; aprovar pendente. Depois atribuir publicação e tentar outro Publicador. | Fluxo anterior não tinha destinatário/resposta/fila completa nem atribuição editorial. | #30destinatário29/resposta/tarefa;outro403/aprovação422; #33filaeditorial29/outro25publica403/designado29publica. Sem gateautoaprovado/prazofictício; visualpendente. |
| 190000 — OPS-01/PROFILE-31 | Comparar ledger/duascolunas/definição QA eativo, distinguir migraçãoBalcão07 depercurso09. | Plano anterior omitia recurso ainda ausenteativo. | 09/190000confirmadaQA e ausenteativo, necessária/nãosubstituída; seqüência autenticada recolocada. Nenhuma execuçãoativa. |
## Ensaio visual preparado — permanece pendente conforme pedido
@@ -174,39 +173,38 @@ Atualizado em **2026-10-10T08:52:56+00:00**. Incremento da mesma auditoria e mat
Servidor **http://127.0.0.1:18097**; destino guardado **desk_restore_20261009_174726_test:55441**. Zero escritas na base ativa. **C37 e toda a aceitação visual deste incremento permanecem pendentes.** Props da interface, API e persistência foram verificadas; nenhum clique ou renderização no navegador foi observado.
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --- | --- | --- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
Os requisitos acima continuam **parciais**: nenhum passou a concluído pelo incremento. O detalhe está no [relatório do workflow](workflow-oportunidades-qa.md); fontes, versões, critérios e percursos permanecem na [mesma matriz](matriz-requisitos.csv).
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| ------------------------------ | ----------------------------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requisitos abertos**. As referências e versões anteriores foram preservadas.
## Provas reproduzíveis e limites
| Prova privada local (sem credenciais) | Percurso / camada |
| --- | --- |
| `opportunity-workflow-http-qa.json` | 288 pedidos ao servidor 18097, Fortify/MFA normal; dez categorias, gravação/recuperação noutra sessão, ciclo investimento18, correção/gates/aprovação/publicação interna; rejeição/negativas iniciais. |
| `opportunity-workflow-extended-http-qa.json` | 91 pedidos; recurso29, imobiliário19 público com ClamD/derivadas, confirmação/hash, proposta privada preserva público, suspensão404; fundiário20 autorizado internamente mas publicação422. |
| `opportunity-workflow-multirole-http-qa.json` | 45 pedidos; autor Prom+Val+Pub403, aprovador Val+Pub403, Auditor acumulado403, três atribuições temporárias revogadas; nova sessão Promotor21 normal. |
| `opportunity-workflow-territory-tasks-http-qa.json` | 95 pedidos; oportunidade28 localiza principal em segundo lugar, conclui revisão por correção, resubmete sem atribuição herdada e suspende sem tarefas abertas; oportunidade29 conclui tarefa com rejeição. |
| `opportunity-workflow-verification-qa.json` | Releitura atual do contrato e referências: seis passam, quatro sem perfil; país/localização e hashes documentais. O total territorial inclui fixture QA isolada e não prova cobertura real. |
| `opportunity-workflow-final-tests-qa.xml` | 19 testes / 426 asserções, zero erros/falhas; testes específicos de estados, binding estrangeiro, integridade de bytes, draft/null, filtros privados e independência. Fixtures de política não são prova de ClamD real. |
| `profiles-v1-preservation-qa.json` | Registos anteriores de 18 conjuntos conservados por ID/colunas originais; MFA18 e build ativo preservados. Captura 2026-10-10T08:51:35+00:00. |
| Prova privada local (sem credenciais) | Percurso / camada |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `opportunity-workflow-http-qa.json` | 288 pedidos ao servidor 18097, Fortify/MFA normal; dez categorias, gravação/recuperação noutra sessão, ciclo investimento18, correção/gates/aprovação/publicação interna; rejeição/negativas iniciais. |
| `opportunity-workflow-extended-http-qa.json` | 91 pedidos; recurso29, imobiliário19 público com ClamD/derivadas, confirmação/hash, proposta privada preserva público, suspensão404; fundiário20 autorizado internamente mas publicação422. |
| `opportunity-workflow-multirole-http-qa.json` | 45 pedidos; autor Prom+Val+Pub403, aprovador Val+Pub403, Auditor acumulado403, três atribuições temporárias revogadas; nova sessão Promotor21 normal. |
| `opportunity-workflow-territory-tasks-http-qa.json` | 95 pedidos; oportunidade28 localiza principal em segundo lugar, conclui revisão por correção, resubmete sem atribuição herdada e suspende sem tarefas abertas; oportunidade29 conclui tarefa com rejeição. |
| `opportunity-workflow-verification-qa.json` | Releitura atual do contrato e referências: seis passam, quatro sem perfil; país/localização e hashes documentais. O total territorial inclui fixture QA isolada e não prova cobertura real. |
| `opportunity-workflow-final-tests-qa.xml` | 19 testes / 426 asserções, zero erros/falhas; testes específicos de estados, binding estrangeiro, integridade de bytes, draft/null, filtros privados e independência. Fixtures de política não são prova de ClamD real. |
| `profiles-v1-preservation-qa.json` | Registos anteriores de 18 conjuntos conservados por ID/colunas originais; MFA18 e build ativo preservados. Captura 2026-10-10T08:51:35+00:00. |
PHPStan dos componentes alterados, TypeScript e compilação QA passaram. Manifesto QA **`984244d5dd9ece719d5c2d2ab852a6019aae8f728dab654c5a8bd6e75adec5a8`**; ativo **`75352185c2a85c34ab726613db864a598e301a5b342ebbc80ac8e678eed17a94`**. Nenhuma página foi renderizada/clicada no navegador deste ensaio. A extensão de fonte `source.json` mantém flags false como fotografia histórica da extração, não como configuração do runtime atual.
@@ -239,44 +237,41 @@ O rascunho admite ausência, vazio e null nos campos ainda não preenchidos, pre
Recolher por passo apenas hora UTC, perfil/ID, URL sem tokens, ação, resultado visível e referência do registo. Omitir Cookie, X-XSRF-TOKEN, passwords, segredo/código MFA e documentos privados de capturas. C37/investidor 18 e cenários A/B continuam no roteiro existente, separados deste ensaio. Sucesso HTTP abaixo não certifica nenhum dos passos visuais.
## Próximo trabalho executável — incremento de 10/10/2026
| Prioridade / requisito | Correção concreta seguinte | Critério de fecho e dependência |
| --- | --- | --- |
| P0 — UI-01/C37; DASH-01/C43 | Incorporar ensaio visual com Promotor 21 e, separadamente, investidor 18; registar falhas com URL, ação, estado e resposta sanitizada. | Login/MFA → dashboard → guardar → logout → nova sessão → recuperar, sem loop, perda ou acesso indevido; não substituível por HTTP. |
| P1 — OP-04; PROFILE-28 | Completar editores e validações semânticas §25: grelhas de serviços/ónus, avaliação/documento, ocupação/título/cadastro, comunidades/consulta/benfeitorias, financeiros/beneficiário efetivo, NDA, governação e franquia; completar Response. Reutilizar contrato e entidades atuais. | Rascunho parcial recuperável; cada condição aplicável recusa dados inválidos e aceita dados/evidências completos; interface por categoria. Confirmar correspondências de objetos opacos do schema, sem alterar os significados legados silenciosamente. |
| P1 — OP-03; PROFILE-11/12/19/21 | Completar filas/revisões e editoriais, reatribuição, pareceres, incidentes e recurso; manter hash da versão e independência. | Atores distintos e responsáveis explicitamente designados, motivos/evidência e histórico; revogação reavaliada. Ciclo principal já demonstrado por HTTP, não repetir o inventário. |
| P1 — COUNTRY/STATS/GEO | Completar cobertura por formulário/consumidor, mapas e nomes cartográficos pendentes. | País/origem persistidos → recuperação → filtros/estatísticas; território cadastrado ≠ geometria ≠ mapa apresentado. 393 limites privados não encerram integração visual; faltam 31 distritos e 157 postos. |
| P1 — OP-02/LIB/PROFILE-23 | Verificar tipos/partilhas/PDFs e derivadas ainda sem prova específica e autorizações do original. | ClamD real separado por operação; hashes/originais preservados; acesso permitido/negado e resultado visível. PNG/documentos do ciclo e duas derivadas já demonstrados. |
| P1 — PROFILE-23 (achado adicional) | Composer audit apontou dois avisos preexistentes em `league/commonmark`: GHSA-97jj-33gv-5xf9 e GHSA-3q6v-r5mr-hxv8. Identificar consumidores/configuração e preparar correção compatível em QA. | Prova local `workflow-composer-audit.json`; avaliar aplicação dos avisos e validar os consumidores afetados. Não atribuir aos três pacotes Opis nem declarar exploração demonstrada. |
| P2 — PROFILE-22/31 | Configuração SLA versionada, instalaçao autenticada de perfis/dupla e preparação de ativação. | Decisões reais explícitas; ensaio backup/restauro da candidata posterior à visual; nenhum prazo ou titular real escolhido por QA. |
| Prioridade / requisito | Correção concreta seguinte | Critério de fecho e dependência |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| P0 — UI-01/C37; DASH-01/C43 | Incorporar ensaio visual com Promotor 21 e, separadamente, investidor 18; registar falhas com URL, ação, estado e resposta sanitizada. | Login/MFA → dashboard → guardar → logout → nova sessão → recuperar, sem loop, perda ou acesso indevido; não substituível por HTTP. |
| P1 — OP-04; PROFILE-28 | Completar editores e validações semânticas §25: grelhas de serviços/ónus, avaliação/documento, ocupação/título/cadastro, comunidades/consulta/benfeitorias, financeiros/beneficiário efetivo, NDA, governação e franquia; completar Response. Reutilizar contrato e entidades atuais. | Rascunho parcial recuperável; cada condição aplicável recusa dados inválidos e aceita dados/evidências completos; interface por categoria. Confirmar correspondências de objetos opacos do schema, sem alterar os significados legados silenciosamente. |
| P1 — OP-03; PROFILE-11/12/19/21 | Completar filas/revisões e editoriais, reatribuição, pareceres, incidentes e recurso; manter hash da versão e independência. | Atores distintos e responsáveis explicitamente designados, motivos/evidência e histórico; revogação reavaliada. Ciclo principal já demonstrado por HTTP, não repetir o inventário. |
| P1 — COUNTRY/STATS/GEO | Completar cobertura por formulário/consumidor, mapas e nomes cartográficos pendentes. | País/origem persistidos → recuperação → filtros/estatísticas; território cadastrado ≠ geometria ≠ mapa apresentado. 393 limites privados não encerram integração visual; faltam 31 distritos e 157 postos. |
| P1 — OP-02/LIB/PROFILE-23 | Verificar tipos/partilhas/PDFs e derivadas ainda sem prova específica e autorizações do original. | ClamD real separado por operação; hashes/originais preservados; acesso permitido/negado e resultado visível. PNG/documentos do ciclo e duas derivadas já demonstrados. |
| P1 — PROFILE-23 (achado adicional) | Composer audit apontou dois avisos preexistentes em `league/commonmark`: GHSA-97jj-33gv-5xf9 e GHSA-3q6v-r5mr-hxv8. Identificar consumidores/configuração e preparar correção compatível em QA. | Prova local `workflow-composer-audit.json`; avaliar aplicação dos avisos e validar os consumidores afetados. Não atribuir aos três pacotes Opis nem declarar exploração demonstrada. |
| P2 — PROFILE-22/31 | Configuração SLA versionada, instalaçao autenticada de perfis/dupla e preparação de ativação. | Decisões reais explícitas; ensaio backup/restauro da candidata posterior à visual; nenhum prazo ou titular real escolhido por QA. |
**Decisões concretas:** (1) quais versões imutáveis de perfil, campos, documentos e gates são aprovadas para concessão, financiamento, fornecimento e outros? (2) qual política versionada fixa prazos, tolerância, ciclos e escalamento? (3) quem assume formalmente as responsabilidades institucionais e os exatamente dois superutilizadores ativos? Não bloqueiam as correções independentes, nem foram inferidas dos atores sintéticos.
| Grupo dos pedidos abertos (projeção da mesma matriz) | Requisitos |
| --- | ---: |
| Parciais | 3187 |
| Não implementados | 145 |
| Preparados em QA | 46 |
| Instalados com falha de acesso | 2 |
| ---------------------------------------------------- | ---------: |
| Parciais | 3187 |
| Não implementados | 145 |
| Preparados em QA | 46 |
| Instalados com falha de acesso | 2 |
Lista integral: **http://127.0.0.1:18097/qa-auditoria/pedidos-abertos**, sob MFA de gestor/Auditor/Superutilizador QA. Cada cartão conserva o estado canónico, fontes, lacuna e próxima ação. “Preparado em QA” indica um escopo provado, não conclusão total.
## Sequência reconciliada de disponibilização futura — não executada
Leitura ativa de 10/10: PostgreSQL `investemoz:5432`, transação READ ONLY, seis oportunidades publicadas; 020000 instalada, 030000/040000/percurso ausentes, flags desativadas, zero geometrias. Build ativo preservado. A revisão candidata **não está fixada**; `ready=true` e fingerprints anteriores não autorizam nem demonstram instalação.
| Ordem | Ação e efeito previsto | Dependência / reversão |
| --- | --- | --- |
| 0 | Incorporar visual C37/C43/A/B e workflow, corrigir falhas; fixar revisão, configuração e manifestos. Renovar backup DB + ficheiros privados/originais + chave estável e provar restauro numa nova QA isolada. | Provas anteriores preservadas, sem as apresentar como restauro desta revisão. Não gerar nova chave. |
| 1 | Disponibilizar código e dependências compatíveis, flags desligadas. Composer adiciona `opis/json-schema 2.4.1`, `opis/string 2.1.0`, `opis/uri 1.1.0`; zero atualizações/remoções preexistentes. | Não importar contas, classificações, contactos ou documentos sintéticos QA. Reverter código/assets compatíveis, preservando payloads/histórico. |
| 2 | Não repetir 020000. Se 030000 continuar ausente, usar prévia/aplicação autenticada `/management/opportunity-resources-install`: três tabelas, uma coluna documental, uma função e três triggers previstos. | Backup/restauro confirmado; hashes/contagens verificados no estado real; não publica nem habilita o percurso. |
| 3 | Preparar e testar o mecanismo autenticado 040000: quatro tabelas, uma coluna de utilizador, três de oportunidade, uma função e dois triggers previstos; dupla inicial/substituição independente. | Aplicação atual demonstrada exclusivamente QA. Instalação/bootstrap ativo autenticado ainda pendente; titulares reais não definidos. Não remover privilégios ativos automaticamente. |
| 4 | Configurar referências/contactos/hierarquia, perfis/tipos/representação, responsabilidades e MFA; quatro contratos modulares apenas após aprovação da versão. | Reutilizar dados mestres reais. As referências sintéticas de ensaio não resolvem cadastros ativos vazios. SLA permanece indeterminado até política aprovada. |
| 5 | Importação cartográfica autenticada, privada e idempotente; se ativo permanecer zero e correspondências iguais, até **393 = 11 províncias + 128 distritos + 254 postos**. Esperados 581 = 11/159/411; pendentes 188 = 0/31/157, nomes no relatório de correspondências. | Prévia → correspondências inequívocas → scan/hash → aplicar → auditoria; nenhuma localização/conta/perímetro de projeto inventado. Reversão pelo lote preserva origem/uso/histórico. **Publicação de camadas é ação separada.** |
| 6 | Disponibilizar flags/assets/navegação aprovados e o percurso I1–I3 pela instalação existente, sem repetir ações já presentes. Publicar cada oportunidade separadamente, com aprovação/hash/prévia/âmbito. | Cinco fases/19 etapas preservadas, dossier privado separado. Voltar flags a false limita disponibilização; manter guardas de confidencialidade para novos dados. Não executar down destrutivo após uso. |
| Ordem | Ação e efeito previsto | Dependência / reversão |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Incorporar visual C37/C43/A/B e workflow, corrigir falhas; fixar revisão, configuração e manifestos. Renovar backup DB + ficheiros privados/originais + chave estável e provar restauro numa nova QA isolada. | Provas anteriores preservadas, sem as apresentar como restauro desta revisão. Não gerar nova chave. |
| 1 | Disponibilizar código e dependências compatíveis, flags desligadas. Composer adiciona `opis/json-schema 2.4.1`, `opis/string 2.1.0`, `opis/uri 1.1.0`; zero atualizações/remoções preexistentes. | Não importar contas, classificações, contactos ou documentos sintéticos QA. Reverter código/assets compatíveis, preservando payloads/histórico. |
| 2 | Não repetir 020000. Se 030000 continuar ausente, usar prévia/aplicação autenticada `/management/opportunity-resources-install`: três tabelas, uma coluna documental, uma função e três triggers previstos. | Backup/restauro confirmado; hashes/contagens verificados no estado real; não publica nem habilita o percurso. |
| 3 | Preparar e testar o mecanismo autenticado 040000: quatro tabelas, uma coluna de utilizador, três de oportunidade, uma função e dois triggers previstos; dupla inicial/substituição independente. | Aplicação atual demonstrada exclusivamente QA. Instalação/bootstrap ativo autenticado ainda pendente; titulares reais não definidos. Não remover privilégios ativos automaticamente. |
| 4 | Configurar referências/contactos/hierarquia, perfis/tipos/representação, responsabilidades e MFA; quatro contratos modulares apenas após aprovação da versão. | Reutilizar dados mestres reais. As referências sintéticas de ensaio não resolvem cadastros ativos vazios. SLA permanece indeterminado até política aprovada. |
| 5 | Importação cartográfica autenticada, privada e idempotente; se ativo permanecer zero e correspondências iguais, até **393 = 11 províncias + 128 distritos + 254 postos**. Esperados 581 = 11/159/411; pendentes 188 = 0/31/157, nomes no relatório de correspondências. | Prévia → correspondências inequívocas → scan/hash → aplicar → auditoria; nenhuma localização/conta/perímetro de projeto inventado. Reversão pelo lote preserva origem/uso/histórico. **Publicação de camadas é ação separada.** |
| 6 | Disponibilizar flags/assets/navegação aprovados e o percurso I1–I3 pela instalação existente, sem repetir ações já presentes. Publicar cada oportunidade separadamente, com aprovação/hash/prévia/âmbito. | Cinco fases/19 etapas preservadas, dossier privado separado. Voltar flags a false limita disponibilização; manter guardas de confidencialidade para novos dados. Não executar down destrutivo após uso. |
Após uso, reverter por configuração compatível, suspensão/arquivo autorizado ou compensação auditada; não eliminar decisões, documentos, consentimentos, relações ou originais. Restauro global exige reconciliar alterações posteriores ao backup. Este plano não contém aprovação de ativação nem declaração de instalação ativa.
@@ -1,18 +1,19 @@
<!-- qa-visual-results-20261010:begin -->
## Ensaios visuais e pendências atuais — 2026-10-10T17:57:54.604301+00:00
Trabalho exclusivo na QA da porta 18097, base `desk_restore_20261009_174726_test:55441`. Nenhuma alteração na base ativa. A mesma matriz mantém **3393 requisitos / 3393 linhas / 6845 ocorrências de origem**: 3235 parciais, 145 não implementados, 5 dependentes de decisão, 1 implementado mas não ativado e 7 concluídos e demonstrados. Os estados globais não mudaram; foram atualizados subcritérios com provas próprias. A ausência de requisitos globalmente classificados “com falha” não significa ausência de casos abertos.
| Requisito | Demonstrado em QA | Critérios ainda pendentes |
| --- | --- | --- |
| C37; UI01; PROFILE24–25 | MFA manual QA18 aceite às 17:40:21 e 17:46:42 UTC; autenticação persistida e dashboard 200. Responsável confirmou acesso. O 403 inicial era do relatório administrativo reservado. Mensagem e retorno ao painel corrigidos; Chromium QA21 provou recusa 403, retorno e F5 sem perder sessão. | F5, logout e novo login no navegador habitual QA18. Não declarar o loop anterior resolvido por inferência: o rastreio não demonstra um ciclo persistente. Uma atualização Inertia 409 isolada não é perda de autenticação. |
| A/B; GUIDE01; SIM02; DESK01–02; CRM01 | Chromium desktop QA18: criação → gravação → nova sessão → recuperação → aplicabilidade → ferramenta → resultado no dossier → preparação no Balcão → acompanhamento interno → nova recuperação. Cinco fases e 19 etapas preservadas. A dispensa S10; B aguarda informação externa em S10 enquanto S02 avança. Resultado: equilíbrio de 20 unidades e défice A=0 / B=70.000 MZN. QA23 recebe 403/404; gestor não vê resultados financeiros privados. | Balcão demonstrado em preparação DRAFT, sem submissão ou decisão externa. Restantes critérios especializados, fiscalidade, documentos e consumidores não encerrados. Repetição final A/B móvel ainda necessária. |
| DASH01; PROFILE05/32 | QA21, a partir do dashboard: “Minhas oportunidades” e “Nova oportunidade” → rascunho incompleto #50 → guardar → nova sessão → recuperar → editar. Promotor solicita arquivo; Publicador QA25 arquiva com fundamento; estado recuperado. | Restauração por perfil ausente no workflow. Definir e implementar ator/regra coerentes sem conceder arquivo direto ao Promotor por inferência. Workflow e contratos especializados ainda exigem demonstrações próprias. |
| COUNTRY01–04/06/07 | Residência PT guardada no perfil e recuperada após F5. Negócio e fundiário DRAFT: país PT / origem FR guardados e recuperados. Balcão A/B: PT / ZA recuperados noutra sessão. Quatro formulários públicos apresentam 249 países cada. Gestão: filtros ZA/unknown, quatro manifestações sem origem e zero pedidos submetidos ZA, com rascunhos excluídos. | Nos formulários públicos, a presença de opções não prova submissão ou recuperação. Concluir cada gravação e estatística positiva de origem conhecida no UI. Nos rascunhos de negócio/fundiário, F5 não substitui nova sessão. |
| GEO01–03 | Oportunidade própria QA21 #51 e criação de projeto, cluster e corredor: Cabo Delgado registado → API com uma geometria acessível → um polígono SVG visível em cada consumidor. | Seleções desse ensaio não guardadas. Recuperar relações por consumidor e testar descendentes, restantes mapas e perfis. Tiles externos bloqueados no ensaio, sem confirmação da base externa. 408 associações anteriores e 173 pendentes preservadas; Mandie/Guro ambíguo. |
| LEG02/03/06/07; C77–C83 | Corrigidos landmarks, ARIA, hierarquia de títulos, reflow, foco das tabelas e idioma HTML pt-MZ em QA. Quinze execuções dirigidas de axe, em 320/390/1440px, sem violações automáticas ou overflow. Três páginas com skiplink primeiro e tabelas financeiras operadas por teclado. | Cobertura integral, leitor de ecrã, dispositivos reais, mais perfis e editor C74. O dossier QA21 verifica o componente móvel corrigido, sem substituir a repetição final A/B. |
| DOC01; C84 | Retirada mensagem global falsa de ClamD pendente; scan e motor apresentados por ficheiro/versão. Os 22 scans reais anteriores permanecem demonstrados. | PDFs, exportações, partilhas, derivadas e operações restantes exigem provas próprias. Um original limpo não comprova a derivada. |
| OPS01 | Backup QA 2026-10-10T17:48:11+00:00: 295 tabelas e 103 ficheiros restaurados. Ativo READ ONLY, backup 2026-10-10T17:48:52+00:00: 288 tabelas restauradas numa base QA distinta e cinco ficheiros conferidos no arquivo. Instalador/publicação: 9 testes / 93 asserções, além de TypeScript. | Aplicação, compatibilidade e reversão da futura revisão candidata no clone fresco do ativo. Revisão candidata global e ativação continuam por fixar. Contagens de testes não substituem critérios funcionais. |
| Requisito | Demonstrado em QA | Critérios ainda pendentes |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| C37; UI01; PROFILE24–25 | MFA manual QA18 aceite às 17:40:21 e 17:46:42 UTC; autenticação persistida e dashboard 200. Responsável confirmou acesso. O 403 inicial era do relatório administrativo reservado. Mensagem e retorno ao painel corrigidos; Chromium QA21 provou recusa 403, retorno e F5 sem perder sessão. | F5, logout e novo login no navegador habitual QA18. Não declarar o loop anterior resolvido por inferência: o rastreio não demonstra um ciclo persistente. Uma atualização Inertia 409 isolada não é perda de autenticação. |
| A/B; GUIDE01; SIM02; DESK01–02; CRM01 | Chromium desktop QA18: criação → gravação → nova sessão → recuperação → aplicabilidade → ferramenta → resultado no dossier → preparação no Balcão → acompanhamento interno → nova recuperação. Cinco fases e 19 etapas preservadas. A dispensa S10; B aguarda informação externa em S10 enquanto S02 avança. Resultado: equilíbrio de 20 unidades e défice A=0 / B=70.000 MZN. QA23 recebe 403/404; gestor não vê resultados financeiros privados. | Balcão demonstrado em preparação DRAFT, sem submissão ou decisão externa. Restantes critérios especializados, fiscalidade, documentos e consumidores não encerrados. Repetição final A/B móvel ainda necessária. |
| DASH01; PROFILE05/32 | QA21, a partir do dashboard: “Minhas oportunidades” e “Nova oportunidade” → rascunho incompleto #50 → guardar → nova sessão → recuperar → editar. Promotor solicita arquivo; Publicador QA25 arquiva com fundamento; estado recuperado. | Restauração por perfil ausente no workflow. Definir e implementar ator/regra coerentes sem conceder arquivo direto ao Promotor por inferência. Workflow e contratos especializados ainda exigem demonstrações próprias. |
| COUNTRY01–04/06/07 | Residência PT guardada no perfil e recuperada após F5. Negócio e fundiário DRAFT: país PT / origem FR guardados e recuperados. Balcão A/B: PT / ZA recuperados noutra sessão. Quatro formulários públicos apresentam 249 países cada. Gestão: filtros ZA/unknown, quatro manifestações sem origem e zero pedidos submetidos ZA, com rascunhos excluídos. | Nos formulários públicos, a presença de opções não prova submissão ou recuperação. Concluir cada gravação e estatística positiva de origem conhecida no UI. Nos rascunhos de negócio/fundiário, F5 não substitui nova sessão. |
| GEO01–03 | Oportunidade própria QA21 #51 e criação de projeto, cluster e corredor: Cabo Delgado registado → API com uma geometria acessível → um polígono SVG visível em cada consumidor. | Seleções desse ensaio não guardadas. Recuperar relações por consumidor e testar descendentes, restantes mapas e perfis. Tiles externos bloqueados no ensaio, sem confirmação da base externa. 408 associações anteriores e 173 pendentes preservadas; Mandie/Guro ambíguo. |
| LEG02/03/06/07; C77–C83 | Corrigidos landmarks, ARIA, hierarquia de títulos, reflow, foco das tabelas e idioma HTML pt-MZ em QA. Quinze execuções dirigidas de axe, em 320/390/1440px, sem violações automáticas ou overflow. Três páginas com skiplink primeiro e tabelas financeiras operadas por teclado. | Cobertura integral, leitor de ecrã, dispositivos reais, mais perfis e editor C74. O dossier QA21 verifica o componente móvel corrigido, sem substituir a repetição final A/B. |
| DOC01; C84 | Retirada mensagem global falsa de ClamD pendente; scan e motor apresentados por ficheiro/versão. Os 22 scans reais anteriores permanecem demonstrados. | PDFs, exportações, partilhas, derivadas e operações restantes exigem provas próprias. Um original limpo não comprova a derivada. |
| OPS01 | Backup QA 2026-10-10T17:48:11+00:00: 295 tabelas e 103 ficheiros restaurados. Ativo READ ONLY, backup 2026-10-10T17:48:52+00:00: 288 tabelas restauradas numa base QA distinta e cinco ficheiros conferidos no arquivo. Instalador/publicação: 9 testes / 93 asserções, além de TypeScript. | Aplicação, compatibilidade e reversão da futura revisão candidata no clone fresco do ativo. Revisão candidata global e ativação continuam por fixar. Contagens de testes não substituem critérios funcionais. |
**C80 corrigido:** a resposta tardia do GET do rascunho podia substituir preenchimento já iniciado. Edição e avanço ficam bloqueados até a recuperação terminar; o retorno exige o snapshot completo guardado. Chromium com resposta deliberadamente atrasada comprovou bloqueio, recuperação e libertação. A/B recuperaram os inputs corretos noutra sessão, preservando versões anteriores.
@@ -28,6 +29,7 @@ As versões históricas abaixo ficam preservadas. Afirmações antigas sobre fal
# Gestão de Oportunidades integrada no Dashboard
<!-- qa-response-20261010:begin -->
## Incremento atual — Response/§27 e propostas para decisão
Somente QA **http://127.0.0.1:18097**, `desk_restore_20261009_174726_test:55441`. Mesmo inventário/matriz; nenhum fecho integral ou escrita ativa.
@@ -47,18 +49,19 @@ Provas: `opportunity-response-http-qa.json`, `OpportunityCanonicalWorkflowTest`,
<!-- qa-response-20261010:end -->
<!-- qa-installation-cartography-20261010:begin -->
## Estado atual — instalador, documentos e cartografia
QA exclusivamente: **http://127.0.0.1:18097**, `desk_restore_20261009_174726_test:55441`. Ativo inspecionado apenas por leitura em 2026-10-10T12:26:56+00:00: 030000, 040000 e 09/190000 ausentes; zero geometrias; manifesto preservado. **C37, Promotor QA21 e A/B permanecem visualmente pendentes. Candidata à ativação ainda não fixada.**
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --- | --- | --- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](auditoria-portal/propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
| Requisitos | Código preparado / prova QA | Critério ainda aberto |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PROFILE-31 / OPS-01 | GET/POST `/management/profile-install`, bootstrap separado; prévia, dependências, hash, MFA, repetição e auditoria. Instalação vazia revertida/reinstalada; falha de auditoria reverte DDL e ledger, permitindo repetir. Uso/histórico impedem remoção. No servidor já utilizado, `changed=false`; nenhum titular ou privilégio alterado. Promotor, Auditor e organização alheia recebem 403. | Instalação/bootstrap visual e titulares reais designados; recuperação simultânea da dupla depende de D-R1. Backup do schema não recupera MFA perdido. |
| GEO-02/03 | **15 novas**: cinco distritos e dez postos; **393 reutilizadas**. Total **408**: 11 províncias, 133 distritos e 264 postos. API do mapa recupera os 15 novos limites. 1.990 cadastros e 361 geometrias originais preservados; sem publicação. | **173 lacunas nomeadas**: 26 distritos e 147 postos; ambiguidades e edições distintas. Seletores/mapas por consumidor continuam com aceitação visual pendente. Localidades/parcelas não inferidas. |
| OP-02 / documental | DOCX/XLSX: pacote válido, scan ClamD real, acesso de QA21/24/25 e QA23 negado; exclusão lógica, restauro e original idêntico noutra sessão MFA. | Renderização de Office, exportações/PDFs derivados e restantes consumidores continuam pendentes por operação. |
| LAND-01 / PART-01 / SCAN-01 | PDF, PNG e JPEG em fundiário e sala de parceria: seis scans reais com hashes iguais. Autor recupera originais; partilha explícita permite nova sessão; revogação retira acesso/listagem, sem apagar original. Gestor não ganha acesso por esse papel. **91 pedidos** no recibo próprio. | Modelo de impressão recuperado, mas PDF gerado no navegador e interface não demonstrados. Estes seis scans não encerram outros tipos, derivadas ou permissões. |
| OP-03 / OP-04 | Código da interface e resposta distinguem aprovação interna, disponibilização restrita e catálogo público. Casos #30 restrito, #33 público e #32 aprovado sem publicação recuperados pela API; consulta da política pública efetiva. | Interface; Response integral/§27 e condições sem regra inequívoca continuam parciais. Testes dos seis contratos não encerram a demonstração visual. |
| PROFILE-22/28 | [Quatro perfis e SLA com regra, fundamento, efeito e decisões concretas](auditoria-portal/propostas-perfis-modulares-sla.md). | Propostas **inativas**; quatro categorias continuam com rascunhos recuperáveis, mas submissão/publicação bloqueadas. Nenhum prazo ou responsável real configurado. |
Prova de recuperação QA: dump consistente → nova base `profile_restore_20261010_123125_test:55441` → **295 tabelas com linhas/hashes iguais e 71 ficheiros fisicamente recuperados por hash**; todos os ficheiros referenciados recuperados por hash. Arquivo privado inclui o runtime e a chave QA estável. Readiness só atesta preparação técnica desta revisão. Repetir após fixar a candidata e preparar backup ativo apenas numa futura ativação autorizada.
@@ -70,6 +73,7 @@ Prova de recuperação QA: dump consistente → nova base `profile_restore_20261
<!-- qa-installation-cartography-20261010:end -->
<!-- qa-semantic-20261010:begin -->
## Ensaio visual preparado — permanece pendente conforme pedido
URL QA **http://127.0.0.1:18097/dashboard**. Conta **Promotor QA21**, MFA normal, credenciais/código obtidos apenas localmente. Não incluir cookies, cabeçalhos X-XSRF-TOKEN, segredos ou corpo do código em capturas. C37/conta18 é um ensaio independente e continua pendente.
@@ -85,25 +89,24 @@ URL QA **http://127.0.0.1:18097/dashboard**. Conta **Promotor QA21**, MFA normal
Registar por ação URL/ator/ID/estado/API/persistência/resultado visível; associar a mesma matriz. A/B completos e cincofases/19etapas continuam no roteiro existente, sem renumerar. Não fechar critérios por leitura dos dados ou totaldetestes.
## Resultado atual por categoria — semântica e atribuições em QA, 10/10/2026
Este bloco conserva a revisão semântica anterior; o estado atual está no início do documento; as secções anteriores abaixo permanecem como histórico. Estados antigos sobre objetos opacos, coordenação editorial e ausência de 190000 ficam confrontados com os resultados concretos deste bloco. **Código preparado e HTTP/persistência em QA não encerram interface nem funcionalidade ativa.** Não houve escrita na base ativa. C37 e aceitação visual permanecem pendentes.
Servidor **http://127.0.0.1:18097**, base **desk_restore_20261009_174726_test:55441**, Fortify e MFA normais. **Promotor QA 21** continua a conta de ensaio do dashboard. Não usar Auditor ou Superutilizador em seu lugar.
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| --- | --- | --- | --- | --- | --- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Categoria / ID QA | Rascunho | Edição / recuperação | Submissão | Revisão | Publicação |
| ------------------------- | -------------------------------- | ------------------------------- | ------------------------------- | ------------------------- | --------------------------------------------- |
| Investimento — #30 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Imobiliário — #31 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Fundiário/DUAT — #32 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Bloqueada: autorização externa pendente |
| Venda de negócio — #33 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Pública, só teaser; prova editorial posterior |
| Parceria de negócio — #34 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Franquia — #35 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | Aceite | Gates e aprovação interna | Interna; sem exposição pública |
| Concessão — #36 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Financiamento — #37 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Fornecimento — #38 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
| Outros — #39 | Incompleto guardado e recuperado | Edição gravada, nova sessão MFA | 422: perfil modular por aprovar | Não elegível | Bloqueada |
As dez categorias recuperaram dados noutra sessão autenticada. As seis com contrato definido aceitaram os cenários semânticos documentados; as quatro restantes conservaram rascunhos, sem inventar um perfil modular para as submeter. Fundiário #32 separa aprovação interna da decisão externa. Venda #33 passou depois pelo percurso editorial público, sem divulgar resumo/dados privados.
@@ -121,18 +124,19 @@ As dez categorias recuperaram dados noutra sessão autenticada. As seis com cont
Mesma matriz: **3.386 requisitos / 3.386 linhas**, **6.838 ocorrências de origem**. IDs, fontes, critérios, versões divergentes e referências anteriores conservados.
| Estado canónico | Requisitos | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos | Ocorrências de origem |
| ------------------------------- | ---------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31 e AUD-OPS-01**, em [matriz-requisitos.csv](matriz-requisitos.csv). Nenhum desses critérios visuais foi fechado por API.
<!-- qa-semantic-20261010:end -->
<!-- qa-workflow-20261010:begin -->
## Ensaio manual atual — Promotor QA e workflow
**URL inicial exato: http://127.0.0.1:18097/dashboard. Conta: Promotor QA — conta sintética 21.** Se necessário, o login normal é `/login`, com MFA Fortify. Credenciais e códigos permanecem exclusivamente no ficheiro privado local; não os copiar para a conversa. Conferir identificação QA/porta 18097; não usar `portal-investidor.test`.
@@ -152,29 +156,28 @@ Linhas principais: **AUD-OP-02/03/04, AUD-GEO-03, AUD-PROFILE-11/12/19/25/28/31
Recolher por passo apenas hora UTC, perfil/ID, URL sem tokens, ação, resultado visível e referência do registo. Omitir Cookie, X-XSRF-TOKEN, passwords, segredo/código MFA e documentos privados de capturas. C37/investidor 18 e cenários A/B continuam no roteiro existente, separados deste ensaio. Sucesso HTTP abaixo não certifica nenhum dos passos visuais.
## Incremento canónico e workflow em QA — 10/10/2026
Servidor **http://127.0.0.1:18097**; destino guardado **desk_restore_20261009_174726_test:55441**. Zero escritas na base ativa. **C37 e toda a aceitação visual deste incremento permanecem pendentes.** Props da interface, API e persistência foram verificadas; nenhum clique ou renderização no navegador foi observado.
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --- | --- | --- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
| Requisito na matriz única | Funciona / prova concreta em QA | Falta para fechar |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AUD-OP-04; AUD-PROFILE-28 | Dez categorias guardam rascunhos incompletos e recuperam noutra sessão MFA. Seis passam o contrato estrutural: investimento, imobiliário, DUAT, venda, parceria e franquia. Adapter do mesmo schema de 110 definições; condições `allOf` originais recuperadas, IDs existentes mantidos. | Semântica e editores dos objetos incompletos do §25; contrato Response integral; quatro perfis modulares aprovados; demonstração visual por categoria. |
| AUD-OP-03; PROFILE-08/11/12 | Promotor 21 criou a oportunidade **18**, submeteu; Validador 24 solicitou correção; 21 corrigiu/resubmeteu; 24 reviu gates e aprovou; Publicador 25 publicou com visibilidade interna. O número 18 identifica a oportunidade, não a conta do investidor C37. | Visual integral, todas as categorias, pareceres/incidentes e coordenação editorial completa. |
| PROFILE-09/10/12/21 | Imobiliário **19**: rejeição fundamentada por 24 → recurso reaberto pelo revisor independente 29 → nova aprovação 24 → publicação pública 25 → alteração privada sem alterar a ficha pública → suspensão com GET público 404. Autor Prom+Val+Pub e aprovador Val+Pub receberam 403. | Visual, filas institucionais e competências reais; suspensão/retoma e demais ações editoriais por todos os perfis. |
| PROFILE-19/21/22 | Tarefas existentes em `tasks`, vínculo à oportunidade por origem/ID/correlação; atribuição explícita, motivos e decisões recuperáveis. Correção/rejeição concluem revisão; resubmissão não herda atribuição; suspensão conclui tarefas pendentes. Recurso do próprio rejeitor e membro da organização negados. SLA `unconfigured`, responsável e prazo iniciais nulos. | Filas completas, reatribuição/disponibilidade, coordenação editorial e política SLA aprovada. Não foram inventados responsáveis nem prazos. |
| COUNTRY-01; GEO-03; OP-02 | Localização MZ/Cabo Delgado/distrito e documentos ligados ao mesmo contrato recuperados nas seis categorias. Oportunidade **28** publicou usando a localização principal mesmo em segundo lugar na lista. Documentos e imagem/duas derivadas verificados com ClamD real e hashes correspondentes. DUAT **20** aprovado internamente não publicou: 422 por autorização externa pendente. | Outros países/formulários, origem/filtros/estatísticas transversais, mapas renderizados, 188 correspondências cartográficas e operações documentais restantes. |
| PROFILE-30; DASH-01 | Conta **Promotor QA — conta sintética 21**, MFA normal confirmado, organização e tipos autorizados. Dashboard devolve navegação do Promotor. Permissões temporárias dos testes foram revogadas e uma nova sessão 21 recuperou o dashboard. | Dashboard → formulário → guardar → nova sessão → workflow e resultado visíveis. Auditor ou Superutilizador não substituem este ensaio. |
Os requisitos acima continuam **parciais**: nenhum passou a concluído pelo incremento. O detalhe está no [relatório do workflow](auditoria-portal/workflow-oportunidades-qa.md); fontes, versões, critérios e percursos permanecem na [mesma matriz](auditoria-portal/matriz-requisitos.csv).
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| --- | ---: | ---: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
| Estado canónico | Requisitos / linhas da matriz | Ocorrências de origem |
| ------------------------------ | ----------------------------: | --------------------: |
| parcial | 3229 | 6379 |
| não implementado | 145 | 446 |
| dependente de decisão concreta | 5 | 5 |
| implementado mas não ativado | 1 | 1 |
| concluído e demonstrado | 6 | 7 |
Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requisitos abertos**. As referências e versões anteriores foram preservadas.
@@ -182,6 +185,7 @@ Total: **3.386 requisitos = 3.386 linhas**, **6.838 ocorrências**, **3.380 requ
<!-- qa-workflow-20261010:end -->
<!-- qa-dashboard-20261010:begin -->
## Estado corrente: acesso ao dashboard C43 —10/10/2026
**C43 — causas encontradas no código/compilação:**(1)AppSidebar mostrava só o primeiro filho de cada grupo, descartando oportunidades; (2)menu Painel apontava /investidor mesmo para gestor; (3)dashboard de gestão colocava criação no fim como Criar oportunidade, sem rótulo Nova oportunidade. A secção de gestão só é devolvida pelo backend a contas verificadas em portal.managers; o seu ocultamento para investidor é autorização esperada, não motivo para conceder perfil administrativo.
@@ -200,6 +204,7 @@ Gestores QA 14/17 têm email verificado+`manage-portal`; gestor 17 possui MFA no
<!-- qa-dashboard-20261010:end -->
<!-- qa-independent-20261010:begin -->
## Estado corrente — 10/10/2026
[Estado corrente na matriz existente](auditoria-portal/matriz-requisitos.csv), [relatório](auditoria-portal/relatorio-executivo.md) e [backlog](auditoria-portal/backlog.md):3354 requisitos/5830origens;32 geometrias adicionaisQA,393 privadas no total; correspondências11/128/254 e lacunas0/31/157. Recuperação documental cifrada fundiário/parceria e loteQA demonstrados por operações específicas; países/origem renovados por formulário. Schema especializado110defs/9 contratos preparado com fonte/hash, ainda sem validaçãoruntime/workflow integrado. Maturidade7/8 no draft foi corrigida em lote posterior ao texto histórico abaixo, sem reinterpretar seis valores legados; isso não conclui publicação/workflow. C37 e A/Bvisuais continuam pendentes. Recursos ativos não instalados no último retrato conhecido, a reconfirmar antes de futura ação; ready/hashes antigos não representam a revisão atual. Nenhuma alteração ativa. Cinco fases/19 etapas e URLs/IDs/cadastros preservados.
@@ -0,0 +1,7 @@
{
"external_messages_sent": 0,
"source_diagnostics_restricted": true,
"retained_files": 279,
"handoff_file_count": 5,
"handoff_files_restricted": true
}
@@ -0,0 +1,479 @@
{
"at": "2026-10-12T19:42:40.930008+00:00",
"case": "C132",
"access_log_snapshot_sha256": "c8e35a2f157f1fc37534dc0266978983e03867fa09edab91a8ad55a0ded7b97a",
"log_lines_parsed": 1443,
"unparsed_lines": 21,
"all_request_origin_classes": {
"loopback": 1440,
"non_loopback": 3
},
"diagnostic_requests": [
{
"at": "2026-10-12T18:40:45+00:00",
"method": "GET",
"operation": "list",
"status": 200,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T18:40:45+00:00",
"method": "GET",
"operation": "detail",
"status": 200,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T18:57:50+00:00",
"method": "GET",
"operation": "list",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T18:57:51+00:00",
"method": "GET",
"operation": "detail",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T18:57:51+00:00",
"method": "GET",
"operation": "detail",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T19:11:12+00:00",
"method": "GET",
"operation": "list",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T19:11:12+00:00",
"method": "GET",
"operation": "detail",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
},
{
"at": "2026-10-12T19:11:12+00:00",
"method": "GET",
"operation": "detail",
"status": 404,
"origin_class": "loopback",
"record_id_or_query_exported": false
}
],
"successful_diagnostic_requests": 2,
"successful_requests_match_recorded_authorized_audit_time": true,
"audit_events_examined": 130,
"audit_action_counts": [
{
"source": "investment-zones",
"action": "saved",
"actor_user_id": 2,
"count": 17
},
{
"source": "investment-zones",
"action": "published",
"actor_user_id": 13,
"count": 12
},
{
"source": "investment-territory",
"action": "primary_territory_saved",
"actor_user_id": 13,
"count": 6
},
{
"source": "investment-zones",
"action": "saved",
"actor_user_id": 13,
"count": 7
},
{
"source": "investment-submission",
"action": "draft_created",
"actor_user_id": 2,
"count": 3
},
{
"source": "user-instruction",
"action": "public_disclosure_authorized",
"actor_user_id": null,
"count": 1
},
{
"source": "portal-services",
"action": "published_under_user_authorization",
"actor_user_id": 13,
"count": 4
},
{
"source": "documented-relations-repair",
"action": "documented_relations_applied",
"actor_user_id": 13,
"count": 1
},
{
"source": "partnership-exchange",
"action": "partnership_module_installed",
"actor_user_id": 13,
"count": 1
},
{
"source": "portal-management",
"action": "created",
"actor_user_id": 13,
"count": 1
},
{
"source": "portal-management",
"action": "updated",
"actor_user_id": 2,
"count": 9
},
{
"source": "virtual-desk",
"action": "desk_installed",
"actor_user_id": 13,
"count": 1
},
{
"source": "virtual-desk",
"action": "internal_service_published",
"actor_user_id": 13,
"count": 3
},
{
"source": "virtual-desk",
"action": "case_created",
"actor_user_id": 2,
"count": 1
},
{
"source": "virtual-desk",
"action": "consulted",
"actor_user_id": 2,
"count": 8
},
{
"source": "virtual-desk",
"action": "assumptions_corrected",
"actor_user_id": 2,
"count": 1
},
{
"source": "investment-submission",
"action": "draft_saved",
"actor_user_id": 2,
"count": 1
},
{
"source": "investment-submission",
"action": "submitted",
"actor_user_id": 2,
"count": 2
},
{
"source": "investment-workspace",
"action": "message_sent",
"actor_user_id": 2,
"count": 1
},
{
"source": "territory-traceability-v2",
"action": "traceability_applied",
"actor_user_id": 13,
"count": 2
},
{
"source": "territory-traceability-v2",
"action": "traceability_reversed",
"actor_user_id": 13,
"count": 1
},
{
"source": "opportunity-origin-review",
"action": "origin_classification_decided",
"actor_user_id": 13,
"count": 6
},
{
"source": "opportunity-management-install",
"action": "opportunity_management_installed",
"actor_user_id": 13,
"count": 1
},
{
"source": "organization-country-installation",
"action": "install",
"actor_user_id": 13,
"count": 1
},
{
"source": "opportunity-resources-install",
"action": "opportunity_resources_installed",
"actor_user_id": 2,
"count": 1
},
{
"source": "portal-profile-installation",
"action": "install",
"actor_user_id": 13,
"count": 1
},
{
"source": "portal-profile-installation",
"action": "bootstrap-request",
"actor_user_id": 13,
"count": 1
},
{
"source": "portal-profiles-v1",
"action": "superuser_pair_initialized",
"actor_user_id": 2,
"count": 1
},
{
"source": "portal-profile-installation",
"action": "bootstrap-confirm",
"actor_user_id": 2,
"count": 1
},
{
"source": "portal-profiles-v1",
"action": "audit_metadata_read",
"actor_user_id": 13,
"count": 2
},
{
"source": "portal-owner-staff-preparation",
"action": "staff_account_prepared",
"actor_user_id": null,
"count": 3
},
{
"source": "portal-profiles-v1",
"action": "request_denied",
"actor_user_id": 15,
"count": 3
},
{
"source": "portal-profiles-v1",
"action": "request_denied",
"actor_user_id": 17,
"count": 1
},
{
"source": "portal-profiles-v1",
"action": "operator_organization_registered",
"actor_user_id": 13,
"count": 1
},
{
"source": "portal-profiles-v1",
"action": "role_granted",
"actor_user_id": 13,
"count": 7
},
{
"source": "portal-profiles-v1",
"action": "request_denied",
"actor_user_id": 13,
"count": 14
},
{
"source": "portal-profiles-v1",
"action": "operator_organization_registration_recovered",
"actor_user_id": 13,
"count": 1
},
{
"source": "C132-incident-response",
"action": "C132_affected_MFA_rotated_and_sessions_revoked",
"actor_user_id": null,
"count": 1
},
{
"source": "C132-incident-response",
"action": "C132_anonymous_diagnostics_contained",
"actor_user_id": null,
"count": 1
}
],
"denied_profile_requests": [
{
"actor_user_id": 15,
"at": "2026-10-12 08:24:32.288003+00",
"action": "request_denied"
},
{
"actor_user_id": 15,
"at": "2026-10-12 08:25:17.157828+00",
"action": "request_denied"
},
{
"actor_user_id": 15,
"at": "2026-10-12 08:25:37.876732+00",
"action": "request_denied"
},
{
"actor_user_id": 17,
"at": "2026-10-12 08:31:59.461947+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 08:44:41.649736+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 08:45:50.898559+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 08:48:23.493772+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 08:50:55.017891+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 08:50:59.682495+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:05:41.741185+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:06:07.714158+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:06:11.320336+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:06:15.88483+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:06:16.815169+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:06:17.963057+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:08:55.433336+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:09:24.510857+00",
"action": "request_denied"
},
{
"actor_user_id": 13,
"at": "2026-10-12 09:29:39.50625+00",
"action": "request_denied"
}
],
"sensitive_route_counts": [
{
"family": "login",
"method": "GET",
"status": 200,
"count": 43
},
{
"family": "login",
"method": "GET",
"status": 308,
"count": 6
},
{
"family": "login",
"method": "POST",
"status": 405,
"count": 2
},
{
"family": "login",
"method": "POST",
"status": 302,
"count": 20
},
{
"family": "MFA",
"method": "GET",
"status": 200,
"count": 10
},
{
"family": "MFA",
"method": "POST",
"status": 302,
"count": 10
},
{
"family": "MFA_enrollment",
"method": "POST",
"status": 302,
"count": 4
},
{
"family": "MFA_enrollment",
"method": "GET",
"status": 200,
"count": 12
},
{
"family": "login",
"method": "GET",
"status": 302,
"count": 3
},
{
"family": "MFA",
"method": "GET",
"status": 302,
"count": 2
}
],
"suspicious_diagnostic_access_identified_in_available_logs": false,
"negative_result_does_not_prove_no_access": true,
"limitations": [
"Common access log is shared across vhosts and does not record Host or authenticated account; it cannot attribute every request to this portal or a person.",
"No complete diagnostic enablement history; diagnostic retention was 24 hours. Exact earlier exposure start and deleted records cannot be recovered from the available files.",
"A denied profile request is an authorization rejection, not proof of an attack. Audit has no comprehensive successful login/MFA or document-download trail.",
"Loopback source identifies a local request or proxy, not the identity of the person making it. No conclusion about earlier or unlogged downloads."
],
"raw_lines_IPs_cookies_tokens_or_payloads_exported": false
}
@@ -0,0 +1,99 @@
{
"audit_schema": [
{
"column_name": "id",
"is_nullable": "NO",
"column_default": "gen_random_uuid()"
},
{
"column_name": "source_system",
"is_nullable": "NO",
"column_default": "'investmoz'::text"
},
{
"column_name": "external_id",
"is_nullable": "YES",
"column_default": null
},
{
"column_name": "data_classification",
"is_nullable": "NO",
"column_default": "'internal'::text"
},
{
"column_name": "correlation_id",
"is_nullable": "YES",
"column_default": null
},
{
"column_name": "created_at",
"is_nullable": "NO",
"column_default": "now()"
},
{
"column_name": "actor_user_id",
"is_nullable": "YES",
"column_default": null
},
{
"column_name": "entity_type",
"is_nullable": "NO",
"column_default": null
},
{
"column_name": "entity_id",
"is_nullable": "YES",
"column_default": null
},
{
"column_name": "action",
"is_nullable": "NO",
"column_default": null
},
{
"column_name": "occurred_at",
"is_nullable": "NO",
"column_default": "now()"
},
{
"column_name": "before_data",
"is_nullable": "YES",
"column_default": null
},
{
"column_name": "after_data",
"is_nullable": "YES",
"column_default": null
}
],
"affected_accounts": [
{
"id": 14,
"name": "Aurora Chachuaio",
"email": "aurora.chachuaio@tempo.co.mz",
"two_factor_confirmed_at": "2026-10-12 08:21:11",
"portal_access_revision": 0
},
{
"id": 15,
"name": "Palmira Uamusse",
"email": "palmira.matsinhe@tempo.co.mz",
"two_factor_confirmed_at": "2026-10-12 08:23:32",
"portal_access_revision": 0
},
{
"id": 16,
"name": "Mario Melembe",
"email": "mario.melembe@tempo.co.mz",
"two_factor_confirmed_at": "2026-10-12 08:19:31",
"portal_access_revision": 0
},
{
"id": 17,
"name": "Tempo Lda",
"email": "info@tempo.co.mz",
"two_factor_confirmed_at": "2026-10-12 08:35:30",
"portal_access_revision": 0
}
]
}
@@ -0,0 +1,8 @@
<?php
ini_set('zend.exception_ignore_args','1');set_exception_handler(function(Throwable $e){fwrite(STDERR,$e::class);exit(1);});
$root=dirname(__DIR__,2);require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.'.config('database.default'));if($c['database']!=='investemoz'||(int)$c['port']!==5432)throw new RuntimeException('Target differs');
$db=new PDO('pgsql:host='.$c['host'].';port='.$c['port'].';dbname='.$c['database'],$c['username'],$c['password']);$db->exec('BEGIN READ ONLY');
$a=$db->query("SELECT column_name,is_nullable,column_default FROM information_schema.columns WHERE table_schema='public' AND table_name='audit_events' ORDER BY ordinal_position")->fetchAll(PDO::FETCH_ASSOC);
$u=$db->query('SELECT id,name,email,two_factor_confirmed_at,portal_access_revision FROM users WHERE id IN (14,15,16,17) ORDER BY id')->fetchAll(PDO::FETCH_ASSOC);$db->exec('ROLLBACK');
$d=['audit_schema'=>$a,'affected_accounts'=>$u];file_put_contents(__DIR__.'/C132-account-metadata.json',json_encode($d,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));echo json_encode($d,JSON_THROW_ON_ERROR);
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:47:48+00:00",
"account_id": 14,
"recipient": "aurora.chachuaio@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3Sg65wmTz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:47:48+00:00",
"account_id": 14,
"recipient": "aurora.chachuaio@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3Sg65wmTz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,14 @@
{
"recorded_at": "2026-10-13T07:41:04.105260+00:00",
"account_id": 14,
"source": "Owner message in conversation after individual delivery",
"exact_confirmation": "conta 14 — recebido, MFA configurado e dashboard acessível",
"mailbox_receipt_confirmed": true,
"holder_MFA_setup_confirmed": true,
"dashboard_access_confirmed": true,
"evidence_kind": "manual confirmation relayed by owner",
"secrets_or_codes_recorded": false,
"active_changes": 0,
"sessions_not_retested_or_changed": true,
"full_incident_closed": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:47:57+00:00",
"account_id": 15,
"recipient": "palmira.matsinhe@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SgJ5CxLz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:47:57+00:00",
"account_id": 15,
"recipient": "palmira.matsinhe@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SgJ5CxLz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,14 @@
{
"recorded_at": "2026-10-13T08:29:30.634159+00:00",
"account_id": 15,
"source": "Owner message in conversation after individual delivery",
"exact_confirmation": "conta 15 — recebido, MFA configurado e dashboard acessível",
"mailbox_receipt_confirmed": true,
"holder_MFA_setup_confirmed": true,
"dashboard_access_confirmed": true,
"evidence_kind": "manual confirmation relayed by owner",
"secrets_or_codes_recorded": false,
"active_changes": 0,
"sessions_not_retested_or_changed": true,
"full_incident_closed": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:48:02+00:00",
"account_id": 16,
"recipient": "mario.melembe@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SgP40Npz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:48:02+00:00",
"account_id": 16,
"recipient": "mario.melembe@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SgP40Npz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send three separate emails to respective corporate addresses with mandatory TLS",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,14 @@
{
"recorded_at": "2026-10-13T06:51:07.479650+00:00",
"account_id": 16,
"source": "Owner message in conversation after individual delivery",
"exact_confirmation": "conta 16 — recebido, MFA configurado e dashboard acessível",
"mailbox_receipt_confirmed": true,
"holder_MFA_setup_confirmed": true,
"dashboard_access_confirmed": true,
"evidence_kind": "manual confirmation relayed by owner",
"secrets_or_codes_recorded": false,
"active_changes": 0,
"sessions_not_retested_or_changed": true,
"full_incident_closed": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:40:51+00:00",
"account_id": 17,
"recipient": "info@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SW63gPfz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send email to info@tempo.co.mz, corporate manager will reply",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,8 @@
{
"at": "2026-10-12T19:37:58+00:00",
"stage": "SMTP-connect-TLS-auth",
"error_type": "RuntimeException",
"values_recorded": false,
"outcome_may_be_unknown": false,
"automatic_retry": false
}
@@ -0,0 +1,20 @@
{
"at": "2026-10-12T19:40:51+00:00",
"account_id": 17,
"recipient": "info@tempo.co.mz",
"recipient_count": 1,
"CC_BCC": 0,
"transport": "existing_corporate_SMTP",
"TLS_required_and_certificate_verified": true,
"negotiated_TLS_protocol": "TLSv1.3",
"SMTP_accepted": true,
"message_id": "4j3SW63gPfz13LZt",
"private_attachment_count": 1,
"attachment_contains_secret": true,
"attachment_or_secret_values_in_chat_or_report": false,
"owner_authorization": "Explicit owner reply: send email to info@tempo.co.mz, corporate manager will reply",
"mailbox_receipt_confirmed": false,
"holder_authentication_confirmed": false,
"notifications_flag_changed": false,
"C131_included": false
}
@@ -0,0 +1,13 @@
{
"recorded_at": "2026-10-12T19:49:32.318259+00:00",
"account_id": 17,
"recipient": "info@tempo.co.mz",
"source": "Owner message in conversation after individual delivery",
"exact_confirmation": "conta 17 — recebido, MFA configurado e dashboard acessível",
"mailbox_receipt_confirmed": true,
"holder_MFA_setup_confirmed": true,
"dashboard_access_confirmed": true,
"evidence_kind": "manual confirmation relayed by owner",
"secrets_or_codes_recorded": false,
"full_incident_closed": false
}
@@ -0,0 +1,73 @@
{
"at": "2026-10-12T18:40:45.350823+00:00",
"case": "C132",
"environment": "active",
"base": "https://portal-investidor.test",
"target_from_existing_read_only_receipt": "investemoz:5432",
"request_methods": [
"GET"
],
"authenticated": false,
"cookies_or_tokens_sent": false,
"TLS_bypass": false,
"response_bodies_saved": false,
"personal_values_saved": false,
"application_code_config_or_business_data_mutations": 0,
"incidental_server_logging_or_guest_session_metadata": "Normal effects of GET are possible; not counted as business writes.",
"index": {
"status": 200,
"json_array": true,
"entries_exposed": 445,
"metadata_keys": [
"batchId",
"component",
"id",
"method",
"redirectLocation",
"requestType",
"serverTimingMs",
"status",
"tabUuid",
"timestamp",
"url",
"utime",
"visitId"
],
"route_family_counts": {
"other": 341,
"login": 48,
"MFA": 14,
"dashboard": 15,
"management": 27
},
"post_requests_metadata": 88
},
"detail": {
"status": 200,
"entry_identifier_saved": false,
"top_level_fields": [
"__meta",
"componentPath",
"http",
"propValues",
"props",
"renderSource",
"route"
],
"request_headers_present": true,
"cookie_header_present": true,
"xsrf_header_present": true,
"request_body_present": true,
"response_body_present": true,
"prop_values_present": true,
"authenticated_user_object_present": true,
"source_paths_present": true,
"no_values_exported": true
},
"result": "exposure_confirmed",
"active_source_and_bundle_unchanged": true,
"source_hashes": {
"config/inertia.php": "45994a9035e8e10d2fbb82f9fc18756cfb1ba403c9597d334122181b6b29839b",
"public/build/manifest.json": "e21d388f2e71bcd762c476d3e0bd1ae7c608ca57cafc2381c2a8888ce5d4efbf"
}
}
@@ -0,0 +1,95 @@
"""Read protected evidence. Export counts/classification only, never captured values."""
from pathlib import Path
from datetime import datetime,timezone
from urllib.parse import urlparse,parse_qs,unquote
import json,hashlib,re,collections
OUT=Path(__file__).resolve().parent;ROOT=OUT.parents[1]
incident=Path(json.loads((OUT/'C132-private-location.json').read_text(encoding='utf-8-sig'))['private_directory'])
manifest=json.loads((incident/'evidence-manifest-private.json').read_text(encoding='utf-8-sig'))
metrics=collections.defaultdict(lambda:collections.Counter());times=[];methods=collections.Counter();families=collections.Counter();auth_ids=set();secrets=[];records=0;body_states=collections.Counter();mfa_times=[]
markers={'[REDACTED]','[UNSERIALIZABLE]','[TRUNCATED]','********','**********','[redacted]'}
def state(v):
if v is None or v=='' or v==[] or v=={}:return 'empty'
if isinstance(v,str) and (v in markers or all(c=='*' for c in v)):return 'redacted'
if isinstance(v,list) and all(state(x) in ['empty','redacted'] for x in v):return 'redacted'
return 'unredacted'
def leaf_values(v):
if isinstance(v,dict):
for x in v.values():yield from leaf_values(x)
elif isinstance(v,list):
for x in v:yield from leaf_values(x)
elif isinstance(v,str):yield v
def walk(v,path=()):
if isinstance(v,dict):
for k,x in v.items():yield path+(str(k),),x;yield from walk(x,path+(str(k),))
elif isinstance(v,list):
for i,x in enumerate(v):yield from walk(x,path+(str(i),))
elif isinstance(v,str) and v[:1] in ['{','['] and len(v)<8000000:
try:decoded=json.loads(v)
except ValueError:return
yield from walk(decoded,path+('embedded-json',))
envsecrets={}
for line in (ROOT/'.env').read_text(encoding='utf-8-sig').splitlines():
if '=' not in line or line.lstrip().startswith('#'):continue
k,v=line.split('=',1);v=v.strip().strip('"').strip("'")
if re.search(r'(?:PASSWORD|SECRET|TOKEN|PRIVATE_KEY|APP_KEY|API_KEY)$',k.strip()) and len(v)>=8:envsecrets[k.strip()]=v
config_matches=collections.Counter();headers=['cookie','set-cookie','authorization','proxy-authorization','x-xsrf-token','x-csrf-token']
for f in manifest['files']:
p=incident/'diagnostics'/f['name'];raw=p.read_bytes();assert hashlib.sha256(raw).hexdigest()==f['sha256']
if not re.fullmatch(r'[0-9A-HJKMNP-TV-Z]{26}\.json',f['name']):continue
d=json.loads(raw);meta=d.get('__meta') or {};records+=1;times.append(meta.get('timestamp'));methods[meta.get('method','unknown')]+=1
route=urlparse(str(meta.get('url',''))).path
family=next((family for prefix,family in [('/management','management'),('/perfis','profile_administration'),('/dashboard','dashboard'),('/login','login'),('/two-factor-challenge','MFA_challenge'),('/user/two-factor','MFA_setup'),('/settings','settings'),('/minhas-oportunidades','opportunities')] if route.startswith(prefix)),'other')
families[family]+=1
http=d.get('http') or {}
for bag in ['requestHeaders','responseHeaders']:
for k,v in (http.get(bag) or {}).items():
lower=str(k).lower()
if lower in headers:
metrics['header:'+lower][state(v)]+=1
if state(v)=='unredacted':secrets.append({'kind':'header:'+lower,'value':v,'entry_id':meta.get('id'),'timestamp':meta.get('timestamp')})
for key in ['requestBody','responseBody']:
if isinstance(http.get(key),dict):body_states[key+':'+str(http[key].get('status','unknown'))]+=1
# Fortify returns recovery codes as a JSON array, with no sensitive field name to trigger generic key redaction.
if route=='/user/two-factor-recovery-codes':
response=http.get('responseBody') or {};value=response.get('value') if isinstance(response,dict) else None
if isinstance(value,str):
try:value=json.loads(value)
except ValueError:pass
if isinstance(value,list):
for code in value:
metrics['MFA_recovery_code'][state(code)]+=1
if state(code)=='unredacted':secrets.append({'kind':'MFA_recovery_code','value':code,'entry_id':meta.get('id'),'timestamp':meta.get('timestamp')})
props=d.get('propValues') or {}
user=(props.get('auth') or {}).get('user') if isinstance(props,dict) and isinstance(props.get('auth'),dict) else None
if isinstance(user,dict) and isinstance(user.get('id'),int):auth_ids.add(user['id'])
for path,v in walk(d):
last=path[-1].lower().replace('-','_')
key=last.replace('_','')
kind=None
if key in ['password','passwordconfirmation','currentpassword']:kind='password'
elif key in ['token','accesstoken','refreshtoken','_token','apikey','clientsecret']:kind='token_or_secret'
elif key in ['secret','secretkey','twofactorsecret','totpsecret','mfasecret']:kind='MFA_or_other_secret'
elif key in ['recoverycode','recoverycodes','twofactorrecoverycodes']:kind='MFA_recovery_code'
elif last=='code' and family=='MFA_challenge' and 'requestBody' in path:kind='MFA_one_time_code'
if kind:
metrics[kind][state(v)]+=1
if state(v)=='unredacted':
secrets.append({'kind':kind,'value':v,'entry_id':meta.get('id'),'timestamp':meta.get('timestamp')})
if kind=='MFA_one_time_code':mfa_times.append(meta.get('timestamp'))
if isinstance(v,str) and 'otpauth://' in v:
metrics['otpauth_URI']['unredacted']+=1;secrets.append({'kind':'otpauth_URI','value':v,'entry_id':meta.get('id'),'timestamp':meta.get('timestamp')})
strings=list(leaf_values(d))
for name,value in envsecrets.items():
if any(value in s or json.dumps(value)[1:-1] in s for s in strings):config_matches[name]+=1
times=sorted(t for t in times if isinstance(t,str));mfa_times=sorted(t for t in mfa_times if isinstance(t,str))
# Potential values remain solely in the already restricted incident directory for usability assessment.
(incident/'secret-candidates-private.json').write_text(json.dumps(secrets,ensure_ascii=False),encoding='utf-8')
summary={'at':datetime.now(timezone.utc).isoformat(),'case':'C132','diagnostic_records_examined':records,'preserved_files':len(manifest['files']),
'retained_first_timestamp':times[0] if times else None,'retained_last_timestamp':times[-1] if times else None,
'retained_window_not_full_exposure_period':True,'methods':dict(methods),'route_families':dict(families),'authenticated_user_ids_in_retained_props':sorted(auth_ids),
'sensitive_field_classification':{k:dict(v) for k,v in sorted(metrics.items())},'body_capture_states':dict(body_states),
'active_config_secret_exact_matches':dict(config_matches),'MFA_code_first_timestamp':mfa_times[0] if mfa_times else None,'MFA_code_last_timestamp':mfa_times[-1] if mfa_times else None,
'unredacted_candidate_occurrences':len(secrets),'values_exported':False,'candidate_values_retained_only_in_restricted_evidence':True,
'usability_assessment_pending':bool(secrets)}
(OUT/'C132-local-analysis.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2),encoding='utf-8');print(json.dumps(summary,ensure_ascii=True))
@@ -0,0 +1,44 @@
<?php
ini_set('zend.exception_ignore_args','1');set_exception_handler(function(Throwable $e){fwrite(STDERR,'Assessment stopped: '.$e::class.' '.basename($e->getFile()).':'.$e->getLine());exit(1);});
$root=dirname(__DIR__,2);require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.'.config('database.default'));if($c['driver']!=='pgsql'||!empty($c['url'])||(int)$c['port']!==5432||$c['database']!=='investemoz'||!in_array($c['host'],['localhost','127.0.0.1'],true))throw new RuntimeException('Target mismatch');
$db=new PDO('pgsql:host='.$c['host'].';port='.$c['port'].';dbname='.$c['database'],$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$db->exec('BEGIN READ ONLY');
$identity=$db->query('SELECT current_database() as database,inet_server_port() as port')->fetch(PDO::FETCH_ASSOC);if($identity['database']!=='investemoz'||(int)$identity['port']!==5432)throw new RuntimeException('Identity mismatch');
$where=json_decode(ltrim(file_get_contents(__DIR__.'/C132-private-location.json'),"\xEF\xBB\xBF"),true,512,JSON_THROW_ON_ERROR)['private_directory'];
$candidates=json_decode(file_get_contents($where.'/secret-candidates-private.json'),true,512,JSON_THROW_ON_ERROR);
$key=config('app.key');$key=str_starts_with($key,'base64:')?base64_decode(substr($key,7),true):$key;$crypt=new Illuminate\Encryption\Encrypter($key,config('app.cipher'));
$plainString=static function(string $encrypted)use($crypt):string{
$plain=$crypt->decrypt($encrypted,false);
// Fortify encrypt() serializes strings; legacy encryptString() does not. Do not instantiate objects.
if(preg_match('/^s:\d+:"/',$plain)){$decoded=unserialize($plain,['allowed_classes'=>false]);if(!is_string($decoded))throw new RuntimeException('Unexpected envelope type');return $decoded;}
if(!is_string($plain))throw new RuntimeException('Unexpected plaintext type');return $plain;
};
$beforeSnapshot=($argv[1]??'')==='--before-snapshot';
$users=$beforeSnapshot?json_decode(file_get_contents($where.'/recovery/users-before-response-private.json'),true,512,JSON_THROW_ON_ERROR):$db->query('SELECT id,email,password,two_factor_secret,two_factor_recovery_codes,two_factor_confirmed_at,remember_token FROM users ORDER BY id')->fetchAll(PDO::FETCH_ASSOC);
$sessions=$db->query('SELECT id,user_id,last_activity FROM sessions')->fetchAll(PDO::FETCH_ASSOC);
$impacted=[];$detail=[];$types=[];
foreach($candidates as $candidate){
$kind=$candidate['kind'];$types[$kind]=($types[$kind]??0)+1;$values=is_array($candidate['value'])?$candidate['value']:[$candidate['value']];
if($kind==='otpauth_URI'){
$uri=$candidate['value'];$uri=str_replace('&amp;','&',$uri);parse_str(parse_url($uri,PHP_URL_QUERY)??'', $qs);$values=isset($qs['secret'])?[$qs['secret']]:[];
}
foreach($values as $value){if(!is_string($value))continue;
foreach($users as $user){
$matches=false;$effect=null;
if(in_array($kind,['MFA_or_other_secret','otpauth_URI'],true)&&$user['two_factor_secret']){
$secret=$plainString($user['two_factor_secret']);$matches=hash_equals(strtoupper($secret),strtoupper($value));unset($secret);$effect='current_TOTP_seed';
}elseif($kind==='password'){$matches=password_verify($value,$user['password']);$effect='current_password';}
elseif($kind==='MFA_recovery_code'&&$user['two_factor_recovery_codes']){$codes=json_decode($plainString($user['two_factor_recovery_codes']),true);$matches=is_array($codes)&&in_array($value,$codes,true);unset($codes);$effect='current_recovery_code';}
if($matches){$id=(int)$user['id'];$impacted[$id][$effect]=true;$detail[]=['user_id'=>$id,'kind'=>$effect,'entry_id'=>$candidate['entry_id'],'timestamp'=>$candidate['timestamp']];}
}
}
}
$db->exec('ROLLBACK');$detailsPrivate=['at'=>gmdate('c'),'matches'=>$detail];$privateName=$beforeSnapshot?'usability-before-snapshot-matches-private.json':(($argv[1]??'')==='--after-rotation'?'usability-after-rotation-matches-private.json':'usability-matches-private.json');file_put_contents($where.'/'.$privateName,json_encode($detailsPrivate,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));
$known=[];foreach($impacted as $id=>$effects)$known[]=['user_id'=>(int)$id,'usable_exposed_credentials'=>array_keys($effects),'active_session_count'=>count(array_filter($sessions,fn($s)=>(int)$s['user_id']===$id))];
$summary=['at'=>gmdate('c'),'target'=>$identity,'read_only'=>true,'current_credential_matches'=>$known,'current_seed_affected_user_ids'=>array_map(fn($x)=>$x['user_id'],array_values(array_filter($known,fn($x)=>in_array('current_TOTP_seed',$x['usable_exposed_credentials'],true)))),
'source_state'=>$beforeSnapshot?'Verified pre-response backup snapshot':'Current active credentials, READ ONLY',
'recovery_code_candidate_occurrences'=>count(array_filter($candidates,fn($x)=>$x['kind']==='MFA_recovery_code')),
'cookies_and_token_values_redacted_in_retained_records'=>true,'password_values_redacted_in_retained_records'=>true,'one_time_codes_expired_by_age'=>true,'secrets_or_values_exported'=>false,'MFA_not_disabled'=>true];
$output=$beforeSnapshot?'C132-usability-before-snapshot.json':(($argv[1]??'')==='--after-rotation'?'C132-usability-after-rotation.json':'C132-usability.json');
file_put_contents(__DIR__.'/'.$output,json_encode($summary,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_THROW_ON_ERROR));echo json_encode($summary,JSON_THROW_ON_ERROR);
@@ -0,0 +1,6 @@
{
"reference": "library-file:fde1_bGliZmlsZV9UTUlzQXdpYjRMMzhSeEtKLU1HdVhB_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
"sha256": "7549a744e071f6a2d1ee815cf2f265bcaeacedbaea0d134b58b0a0d63be77a21",
"file_access_confirmed": true,
"page_url": "https://chatgpt.com/space/page_dc08a603a4f0819190ead0169eb73599"
}

Some files were not shown because too many files have changed in this diff Show More