diff --git a/.env.example b/.env.example index 0eb72f1a..f2fe62ce 100644 --- a/.env.example +++ b/.env.example @@ -119,3 +119,8 @@ INVESTMOZ_TAX_RULE_APPROVERS= INVESTMOZ_TAX_RULE_PUBLISHERS= INVESTMOZ_ZONE_TERRITORY_REVIEWERS= + +# Local LibreTranslate service and installed language models. +LIBRETRANSLATE_URL=http://127.0.0.1:5000 +LIBRETRANSLATE_TIMEOUT=60 +LIBRETRANSLATE_API_KEY= diff --git a/app/Http/Controllers/Api/TranslationApiController.php b/app/Http/Controllers/Api/TranslationApiController.php new file mode 100644 index 00000000..7f4c8a59 --- /dev/null +++ b/app/Http/Controllers/Api/TranslationApiController.php @@ -0,0 +1,58 @@ +timeout(config('services.translation.timeout'))->get($this->url().'/languages'); + if ($response->successful() && is_array($response->json())) { + return response()->json($response->json())->header('Cache-Control', 'no-store'); + } + } catch (Throwable) { + } + + return response()->json(['message' => 'Serviço de tradução temporariamente indisponível.'], 503); + } + + public function translate(Request $request): JsonResponse + { + $data = $request->validate([ + 'text' => 'required|string|max:10000', + 'source_lang' => 'required|string|max:20', + 'target_lang' => 'required|string|max:20', + 'is_html' => 'boolean', + ]); + if ($data['source_lang'] === $data['target_lang']) { + return response()->json(['original_text' => $data['text'], 'translated_text' => $data['text'], 'source_lang' => $data['source_lang'], 'target_lang' => $data['target_lang']])->header('Cache-Control', 'no-store'); + } + + $payload = ['q' => $data['text'], 'source' => $data['source_lang'], 'target' => $data['target_lang'], 'format' => ($data['is_html'] ?? false) ? 'html' : 'text']; + if (config('services.translation.api_key')) { + $payload['api_key'] = config('services.translation.api_key'); + } + try { + $response = Http::connectTimeout(2)->timeout(config('services.translation.timeout'))->post($this->url().'/translate', $payload); + $translated = $response->json('translatedText'); + if ($response->successful() && is_string($translated) && $translated !== '') { + return response()->json(['original_text' => $data['text'], 'translated_text' => $translated, 'source_lang' => $data['source_lang'], 'target_lang' => $data['target_lang']])->header('Cache-Control', 'no-store'); + } + } catch (Throwable) { + } + + return response()->json(['message' => 'Serviço de tradução temporariamente indisponível.'], 503)->header('Cache-Control', 'no-store'); + } + + private function url(): string + { + return rtrim((string) config('services.translation.url'), '/'); + } +} diff --git a/app/Http/Controllers/GlobalSearchController.php b/app/Http/Controllers/GlobalSearchController.php new file mode 100644 index 00000000..ca7e97b5 --- /dev/null +++ b/app/Http/Controllers/GlobalSearchController.php @@ -0,0 +1,173 @@ +validate(['q' => ['nullable', 'string', 'max:120'], 'page' => ['nullable', 'integer', 'min:1']]); + $term = trim($input['q'] ?? ''); + $tokens = $search->tokens($term); + $results = ['data' => [], 'total' => 0, 'current_page' => 1, 'last_page' => 1, 'per_page' => 5, 'unavailable' => []]; + if ($tokens !== []) { + $factories = [ + 'Páginas e serviços' => function () use ($search, $tokens, $term) { + $pages = array_values(array_filter($this->pages(), fn ($page) => $search->matches(implode(' ', $page), $tokens))); + usort($pages, fn ($a, $b) => $search->score($b['title'], $term, $tokens) <=> $search->score($a['title'], $term, $tokens) + ?: strcmp($a['title'], $b['title']) ?: strcmp($a['url'], $b['url'])); + + return ['count' => count($pages), 'fetch' => fn ($offset, $limit) => array_slice($pages, $offset, $limit)]; + }, + 'Oportunidades' => function () use ($catalogue, $search, $tokens, $term) { + $query = $catalogue->query(['include_national' => true]); + foreach ($tokens as $token) { + $query->where(function ($match) use ($catalogue, $search, $token) { + $search->orFields($match, ['opportunities.title', 'opportunities.summary', 'opportunities.description', 'opportunities.reference', 'opportunities.province'], $token); + $match->orWhereHas('sector', fn ($sector) => $search->constrain($sector, ['name'], [$token])); + $match->orWhereExists(fn ($location) => $location->selectRaw('1')->from('geo_locations as search_location') + ->whereIn('search_location.id', app(InvestmentGeography::class)->publicReferences()->select('id')) + ->where(fn ($name) => $search->orFields($name, ['search_location.name'], $token)) + ->where(fn ($direct) => $direct->whereColumn('search_location.id', 'opportunities.primary_territory_id') + ->orWhereExists(fn ($link) => $link->selectRaw('1')->from('opportunity_locations as search_link') + ->whereColumn('search_link.opportunity_id', 'opportunities.id')->whereColumn('search_link.geo_location_id', 'search_location.id')))); + if (preg_match('/^[a-z0-9]+$/', $token)) { + $match->orWhereIn('opportunities.id', $catalogue->query(['q' => $token, 'include_national' => true])->reorder()->select('opportunities.id')); + } + }); + } + + return $this->source($query, $search, $term, $tokens, 'opportunities.title', 'opportunities.id', + fn ($r) => ['title' => $r->title, 'description' => $r->summary, 'url' => '/oportunidades/'.rawurlencode($r->slug)]); + }, + 'Negócios' => function () use ($search, $tokens, $term) { + $query = ExistingBusiness::query()->published(); + $search->constrain($query, ['public_title', 'activity_code', 'objective'], $tokens); + + return $this->source($query, $search, $term, $tokens, 'public_title', 'existing_businesses.id', + fn ($r) => ['title' => $r->public_title, 'description' => $r->objective, 'url' => '/negocios/'.rawurlencode($r->public_slug)]); + }, + 'Carteira: projectos, clusters e corredores' => function () use ($search, $tokens, $term) { + $query = InvestmentPortfolioController::visible(); + $search->constrain($query, ['investment_dossiers.title', 'investment_dossiers.content'], $tokens); + + return $this->source($query, $search, $term, $tokens, 'investment_dossiers.title', 'investment_dossiers.id', + fn ($r) => ['title' => $r->title, 'description' => $r->corridor_id ? 'Corredor' : ($r->cluster_id ? 'Cluster' : 'Projecto âncora'), 'url' => '/carteira/'.$r->id]); + }, + 'Documentos e legislação' => function () use ($search, $tokens, $term) { + $query = DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id') + ->where('r.published', true)->where('r.rights_status', '!=', 'restricted')->where('d.rights_status', '!=', 'restricted') + ->where('d.status', 'active')->where('d.data_classification', 'public')->whereNull('d.deleted_at') + ->where('d.malware_scan_status', 'clean')->whereColumn('d.malware_scanned_sha256', 'd.sha256'); + $search->constrain($query, ['r.title', 'r.description', 'r.document_number', 'd.issuer', 'r.source_reference', 'r.category', 'r.topic'], $tokens); + $query->select('r.id', 'r.title', 'r.description'); + + return $this->source($query, $search, $term, $tokens, 'r.title', 'r.id', + fn ($r) => ['title' => $r->title, 'description' => $r->description, 'url' => '/documentos/'.$r->id]); + }, + 'Artigos' => function () use ($search, $tokens, $term) { + if (! Schema::hasColumn('portal_resources', 'editorial_content')) { + return ['count' => 0, 'fetch' => fn ($offset, $limit) => []]; + } + $query = app(EditorialReading::class)->publicResources() + ->whereRaw("nullif(btrim(r.editorial_content->>'body'), '') is not null"); + $search->constrain($query, ['r.title', "(r.editorial_content->>'body')"], $tokens); + $query->select('r.id', 'r.title')->selectRaw("r.editorial_content->>'body' as body"); + + return $this->source($query, $search, $term, $tokens, 'r.title', 'r.id', + fn ($r) => ['title' => $r->title, 'description' => Str::limit(trim(strip_tags($r->body)), 220), 'url' => '/artigos/'.$r->id]); + }, + 'Sectores' => function () use ($search, $tokens, $term) { + $query = Sector::query()->where('is_active', true)->whereNotNull('published_at'); + $search->constrain($query, ['name', 'description', 'short_description'], $tokens); + + return $this->source($query, $search, $term, $tokens, 'name', 'sectors.id', + fn ($r) => ['title' => $r->name, 'description' => $r->short_description, 'url' => SectorOrganization::href($r->slug)]); + }, + 'Localizações' => function () use ($search, $tokens, $term) { + $query = app(InvestmentGeography::class)->publicReferences() + ->whereIn('location_type', ['province', 'district', 'admin_post', 'locality']); + $search->constrain($query, ['geo_locations.name', 'geo_locations.source_code'], $tokens); + $query->select('geo_locations.id', 'geo_locations.name', 'geo_locations.location_type'); + + return $this->source($query, $search, $term, $tokens, 'geo_locations.name', 'geo_locations.id', + fn ($r) => ['title' => $r->name, 'description' => ['province' => 'Província', 'district' => 'Distrito', 'admin_post' => 'Posto administrativo', 'locality' => 'Localidade'][$r->location_type], + 'url' => '/oportunidades?'.http_build_query([$r->location_type.'_id' => $r->id])]); + }, + 'Zonas de investimento' => function () use ($search, $tokens, $term) { + $query = app(InvestmentZones::class)->visible(); + $search->constrain($query, ['name', 'code'], $tokens); + + return $this->source($query, $search, $term, $tokens, 'name', 'investment_zones.id', + fn ($r) => ['title' => $r->name, 'description' => $r->code, 'url' => '/zonas/'.$r->id]); + }, + 'Parcerias' => function () use ($search, $tokens, $term) { + $query = DB::table('portal_partnerships as p')->where('p.status', 'published'); + $search->constrain($query, ['p.title', 'p.sector', 'p.province'], $tokens); + $query->select('p.id', 'p.title', 'p.sector', 'p.province'); + + return $this->source($query, $search, $term, $tokens, 'p.title', 'p.id', + fn ($r) => ['title' => $r->title, 'description' => implode(' · ', array_filter([$r->sector, $r->province])), 'url' => '/parcerias/'.$r->id]); + }, + ]; + $results = $federated->page($factories, (int) ($input['page'] ?? 1), 5, + fn ($item) => $search->score($item['title'], $term, $tokens)); + } + + return Inertia::render('portal/search', ['query' => $term, 'results' => $results]); + } + + private function source($query, SearchTerms $search, string $term, array $tokens, string $title, string $id, callable $present): array + { + $count = (clone $query)->reorder()->count(); + $query->reorder(); + $search->orderByRelevance($query, $title, $term, $tokens, $id); + + return ['count' => $count, 'fetch' => fn ($offset, $limit) => (clone $query)->offset($offset)->limit($limit)->get()->map($present)->all()]; + } + + /** Public service entry points and terms used to find them. */ + private function pages(): array + { + return [ + ['title' => 'Como investir em Moçambique', 'description' => 'Procedimentos e etapas para investir', 'url' => '/como-investir'], + ['title' => 'Iniciar ou continuar investimento', 'description' => 'Preparar uma ideia e dossier de investimento', 'url' => '/investimentos/iniciar'], + ['title' => 'Oportunidades de investimento', 'description' => 'Pesquisar por sector, localização e maturidade', 'url' => '/oportunidades'], + ['title' => 'Carteira de investimento', 'description' => 'Projectos âncora, clusters e corredores', 'url' => '/carteira'], + ['title' => 'Negócios existentes', 'description' => 'Compra, venda e participação em negócios', 'url' => '/negocios'], + ['title' => 'Sectores de investimento', 'description' => 'Actividades económicas e sectores prioritários', 'url' => '/sectores'], + ['title' => 'Zonas de investimento', 'description' => 'Zonas económicas especiais, ZEE, ZFI e parques industriais', 'url' => '/zonas'], + ['title' => 'Contextos de investimento', 'description' => 'Formas de iniciar e preparar um investimento', 'url' => '/contextos-de-investimento'], + ['title' => 'Documentos e formulários', 'description' => 'Acervo documental e formulários para investidores e empresas', 'url' => '/documentos'], + ['title' => 'Formulário do investidor', 'description' => 'Dados e contacto para investir', 'url' => '/formularios/investidor'], + ['title' => 'Formulário de empresa', 'description' => 'Dados e contacto para empresas', 'url' => '/formularios/empresa'], + ['title' => 'Legislação e incentivos', 'description' => 'Leis, decretos, benefícios e enquadramento legal', 'url' => '/legislacao'], + ['title' => 'Simulador fiscal', 'description' => 'Simular impostos e cenários fiscais de investimento', 'url' => '/simulador-fiscal'], + ['title' => 'Formulários fiscais', 'description' => 'Preparação dos formulários IVA e IRPC', 'url' => '/formularios/fiscais'], + ['title' => 'Terra e DUAT', 'description' => 'Apoio ao uso e aproveitamento da terra', 'url' => '/terra-duat'], + ['title' => 'Bolsa de parcerias', 'description' => 'Encontrar parceiros e propostas', 'url' => '/parcerias'], + ['title' => 'Apoio ao investidor', 'description' => 'Contactos e pedido de apoio', 'url' => '/apoio'], + ['title' => 'Educação para investimento', 'description' => 'Conteúdos educativos e orientação', 'url' => '/educacao'], + ['title' => 'Sobre o InvesteMoz', 'description' => 'Informação institucional do portal', 'url' => '/sobre'], + ['title' => 'Contacto', 'description' => 'Contactar o portal InvesteMoz', 'url' => '/contacto'], + ['title' => 'Política de privacidade', 'description' => 'Privacidade e tratamento de dados pessoais', 'url' => '/politica-de-privacidade'], + ['title' => 'Termos de uso', 'description' => 'Condições de utilização do portal', 'url' => '/termos-de-uso'], + ]; + } +} diff --git a/app/Services/FederatedSearch.php b/app/Services/FederatedSearch.php new file mode 100644 index 00000000..dfeb49b3 --- /dev/null +++ b/app/Services/FederatedSearch.php @@ -0,0 +1,78 @@ + $factories */ + public function page(array $factories, int $requestedPage, int $size = 5, ?callable $score = null): array + { + $sources = []; + $unavailable = []; + foreach ($factories as $label => $factory) { + try { + $sources[$label] = $factory(); + } catch (QueryException $exception) { + report($exception); + $unavailable[] = $label; + } + } + + // If a source fails after its count, remove it and recompute the page offsets. + do { + $failed = false; + $total = array_sum(array_column($sources, 'count')); + $last = max(1, (int) ceil($total / $size)); + $page = min(max(1, $requestedPage), $last); + $first = ($page - 1) * $size; + $items = []; + $positions = array_fill_keys(array_keys($sources), 0); + $buffers = array_fill_keys(array_keys($sources), []); + for ($position = 0; $position < min($total, $first + $size); $position++) { + $best = null; + $bestScore = PHP_INT_MIN; + foreach ($sources as $label => $source) { + if ($buffers[$label] === [] && $positions[$label] < $source['count']) { + try { + $batch = iterator_to_array((function () use ($source, $positions, $label, $size) { + yield from ($source['fetch'])($positions[$label], $size); + })(), false); + $positions[$label] += count($batch); + $buffers[$label] = $batch; + if ($batch === []) { + $positions[$label] = $source['count']; + } + } catch (QueryException $exception) { + report($exception); + $unavailable[] = $label; + unset($sources[$label]); + $failed = true; + break; + } + } + if ($buffers[$label] === []) { + continue; + } + $candidateScore = $score ? $score($buffers[$label][0]) : 0; + if ($best === null || $candidateScore > $bestScore) { + $best = $label; + $bestScore = $candidateScore; + } + } + if ($failed || $best === null) { + break; + } + $item = array_shift($buffers[$best]); + if ($position >= $first) { + $items[] = [...$item, 'category' => $best]; + } + } + } while ($failed); + + return ['data' => $items, 'total' => $total, 'current_page' => $page, 'last_page' => $last, + 'per_page' => $size, 'unavailable' => $unavailable]; + } +} diff --git a/app/Services/SearchTerms.php b/app/Services/SearchTerms.php new file mode 100644 index 00000000..48c1bf0c --- /dev/null +++ b/app/Services/SearchTerms.php @@ -0,0 +1,112 @@ + */ + public function tokens(string $query): array + { + $normalized = mb_strtolower(Str::ascii($query)); + $tokens = array_values(array_filter(array_unique(array_map( + fn ($word) => trim($word, ".,;:!?\"'()[]{}"), + preg_split('/\s+/u', trim($normalized), -1, PREG_SPLIT_NO_EMPTY) ?: [] + )), fn ($word) => $word !== '')); + if (count($tokens) > 1) { + $meaningful = array_values(array_diff($tokens, ['a', 'as', 'o', 'os', 'de', 'do', 'da', 'dos', 'das', 'em', 'no', 'na', 'nos', 'nas', 'para', 'por', 'e', 'como', 'qual', 'quais', 'um', 'uma'])); + + return $meaningful === [] ? $tokens : $meaningful; + } + + return $tokens; + } + + /** Known Portuguese spelling and number variants; do not infer semantic equivalence. */ + public function variants(string $token): array + { + foreach ([['sector', 'sectores', 'setor', 'setores'], ['projecto', 'projectos', 'projeto', 'projetos'], + ['investir', 'investimento', 'investimentos'], ['investidor', 'investidores'], ['oportunidade', 'oportunidades'], ['documento', 'documentos'], + ['empresa', 'empresas'], ['parceria', 'parcerias'], ['zona', 'zonas'], ['formulario', 'formularios'], + ['provincia', 'provincias'], ['corredor', 'corredores'], ['cluster', 'clusters'], ['imposto', 'impostos'], ['licenca', 'licencas']] as $group) { + if (in_array($token, $group, true)) { + return $group; + } + } + + return [$token]; + } + + public function pattern(string $token): string + { + return '%'.str_replace(['!', '%', '_'], ['!!', '!%', '!_'], $token).'%'; + } + + /** Columns are trusted application constants, never user input. */ + public function orFields($query, array $columns, string $token): void + { + foreach ($columns as $column) { + foreach ($this->variants($token) as $variant) { + $query->orWhereRaw($this->normalizedColumn($column)." LIKE ? ESCAPE '!'", [$this->pattern($variant)]); + } + } + } + + public function constrain($query, array $columns, array $tokens): void + { + foreach ($tokens as $token) { + $query->where(fn ($match) => $this->orFields($match, $columns, $token)); + } + } + + public function matches(string $text, array $tokens): bool + { + $text = mb_strtolower(Str::ascii($text)); + foreach ($tokens as $token) { + if (! array_filter($this->variants($token), fn ($variant) => str_contains($text, $variant))) { + return false; + } + } + + return true; + } + + private function normalizedColumn(string $column): string + { + return "translate(lower(coalesce({$column}::text, '')), 'áàâãäéèêëíìîïóòôõöúùûüçñ', 'aaaaaeeeeiiiiooooouuuucn')"; + } + + public function score(string $title, string $phrase, array $tokens): int + { + $title = mb_strtolower(Str::ascii($title)); + $phrase = mb_strtolower(Str::ascii(trim($phrase))); + $score = $title === $phrase ? 1000 : (str_contains($title, $phrase) ? 400 : 0); + foreach ($tokens as $token) { + if ($this->matches($title, [$token])) { + $score += 20; + } + } + + return $score; + } + + /** The same title score used for in-memory pages, with bound search terms. */ + public function orderByRelevance($query, string $titleColumn, string $phrase, array $tokens, string $tieColumn): void + { + $column = $this->normalizedColumn($titleColumn); + $phrase = mb_strtolower(Str::ascii(trim($phrase))); + $sql = "CASE WHEN {$column} = ? THEN 1000 WHEN {$column} LIKE ? ESCAPE '!' THEN 400 ELSE 0 END"; + $bindings = [$phrase, $this->pattern($phrase)]; + foreach ($tokens as $token) { + $conditions = []; + foreach ($this->variants($token) as $variant) { + $conditions[] = "{$column} LIKE ? ESCAPE '!'"; + $bindings[] = $this->pattern($variant); + } + $sql .= ' + CASE WHEN ('.implode(' OR ', $conditions).') THEN 20 ELSE 0 END'; + } + $query->orderByRaw('('.$sql.') DESC', $bindings)->orderBy($titleColumn)->orderBy($tieColumn); + } +} diff --git a/config/services.php b/config/services.php index febaaea2..892da0b1 100644 --- a/config/services.php +++ b/config/services.php @@ -28,6 +28,12 @@ return [ | */ + 'translation' => [ + 'url' => env('LIBRETRANSLATE_URL', 'http://127.0.0.1:5000'), + 'timeout' => (int) env('LIBRETRANSLATE_TIMEOUT', 60), + 'api_key' => env('LIBRETRANSLATE_API_KEY'), + ], + 'postmark' => [ 'key' => env('POSTMARK_API_KEY'), ], diff --git a/docs/investmoz/unification/traceability-and-manual.md b/docs/investmoz/unification/traceability-and-manual.md index a4e2cf51..6890642e 100644 --- a/docs/investmoz/unification/traceability-and-manual.md +++ b/docs/investmoz/unification/traceability-and-manual.md @@ -7620,1554 +7620,3 @@ Cobertura: identificação/período, 27 campos manuais IVA e 24 campos manuais M Pedido expresso da Tempo: preencher formulário de IVA ou IRPC, em vez de abrir legislação. Base preservada: entrega instalada 789fffd0, Modelo A e aquisições/apuramento já aceites, L6 M20/M22 instalado em 5aaf1a56 e incrementos de L8. Nenhuma perda confirmada neste recorte; não se apagam as aceitações nem se repetem provas fiscais anteriores. Fontes reutilizadas do inventário de 20 exemplares acessíveis em outputs/irpc-l6-values-forms/accessible-source-inventory.json da QA anterior, incluindo temporários identificados; inventário do corpus e originais preservados. M22: três páginas conferidas visualmente nesta revisão, SHA256 4b61bd83d1fbcfd3b7b5c5523cea5923f7d0f65dc4c004eff58e5db38f763c88. Modelo A: correspondência e divergências aceites em modelo-a-reconciliacao-20261021.md; sem nova validação de proveniência. Incremento em preparação QA: entrada directa em Documentos e Formulários, preenchimento manual dos campos correspondidos de IVA e subconjunto M22, identificação/período, revisão, impressão e ficheiro privado para recuperação mediante confirmação. Escolha técnica: sem persistência no servidor nem ligação automática ao dossier neste incremento; não altera schema, dados, permissões ou cálculos. Ficheiro não publicado. IRPC ajustamentos completos, outros regimes, anexos, assinatura e submissão à AT fora da cobertura; L8 permanece parcial. Ainda sem instalação deste incremento. Próximas provas apenas do delta: fidelidade da recuperação, rejeição de ficheiros incompatíveis sem perda, formatos/valores desconhecidos, acesso público e compilação. - - - -## 29/10/2026 — actividades adicionais solicitadas pela Tempo -Origem: pedido expresso nesta conversa, «acrescente nas actividades a serem realizadas ... incorporar nas matrizes de execuções». Os IDs ACT-20261029-01 a 16 identificam recortes de execução dos critérios solicitados, não novos módulos paralelos. Estado de todos: **Planeado — execução pendente**. Prioridade e responsável nominal: por atribuir; não foram inventados prazos nem alterada a ordem das reposições prioritárias já aprovada. - -Antes de executar cada recorte, reconciliar os requisitos e provas existentes pelo módulo/componente indicado, recuperar os respectivos IDs e registar essa correspondência; não duplicar trabalho nem reabrir fechos aceites. A avaliação de 29/10 foi documental/de código, não teste do portal publicado. Ausência de demonstração não significa perda de funcionalidade. Preservar dados, acessos, aprovações e entregas, incluindo os registos de instalação de 28/10. Este registo acrescenta trabalho planeado e não declara implementação ou publicação. -As 16 actividades e os critérios de aceitação estão registados na [matriz consolidada](../consolidated-review-matrix-2026-10-03.md#29102026--actividades-adicionais-solicitadas-pela-tempo) e no [backlog existente](../v2/auditoria-portal/backlog.md#29102026--actividades-adicionais-solicitadas-pela-tempo). Actualizar estes registos em conjunto por ID, com evidência, disponibilidade no destino e saldo restante. A primeira actividade transversal é reconciliar cobertura e provas; só implementar o delta confirmado. O registo documental está concluído; as actividades funcionais permanecem pendentes. - -## 29/10/2026 — ACT-20261029-01, inventário antes da verificação do incremento - -Continuação sequencial solicitada pela Tempo. Correspondência: ACT-20261029-01 reutiliza D-02 §8, clusters/cadeias e a orientação metodológica documentada em 23/10. Concluído previamente e preservado: gestão de clusters, etapas, ligações, lacunas e relações auditadas; disponibilidade instalada de carteira/âncoras e formulários fiscais conforme recibos de 28/10. Nenhuma perda nova confirmada nesta inspecção de código; não foi feita nova comparação de dados ou alegada prova do servidor. A pasta principal está em fde644af, enquanto o último recibo identifica 332c16eb instalado; reconciliar o delta sobre essa origem antes de instalar, sem substituir o destino pela pasta principal. - -Incremento em preparação: diagnóstico qualitativo das cinco forças na edição do cluster, sector/região editáveis, fonte/período/evidência/justificação/limites/oportunidade por força; indeterminação explícita, ficheiro privado transferível e recuperação com confirmação. Sem alteração de schema, dados, permissões, publicações ou motores fiscais. Persistência no servidor, ligação territorial canónica, dados sectoriais fundamentados e consulta pública permanecem por implementar; ACT-01 não está concluída. Verificação dirigida e instalação ainda pendentes neste registo inicial. Restantes ACT-02 a 16 mantêm o estado anterior e a sequência, sem trabalho SGF nesta passagem. -### ACT-20261029-01 — candidato sequencial preparado, 29/10/2026 - -Primeiro incremento implementado, **parcial e ainda não instalado**: gestão → clusters → editar → Competitividade. As cinco forças conservam fonte, período, evidência, apreciação, limites e oportunidade; sector e região explícitos, sem inferências automáticas. Transferência de rascunhos JSON e recuperação restrita ao mesmo cluster, com confirmação antes de substituir. Quatro testes frontend dirigidos, TypeScript e compilação QA passaram tanto na pasta de trabalho como no candidato baseado em 332c16eb. Guarda C132 local passou; não foram efectuados testes nem escritas na base activa. A edição existente recebe apenas a inclusão do componente; contratos e permissões existentes preservados. - -Origem reconciliada: main remoto e revisão pública conferidos em 332c16eb em 29/10. Candidato em C:/laragon/www/portal-investidor-competitiveness-qa-20261029, ramo codex/competitiveness-sequential-20261029. Consulta do estado remoto não equivale a inventário novo da base. Sessão SSH anterior encerrada; autenticação por chave recusada. Instalação requer autenticação SSH, backup fresco, restauro isolado, guarda de versão, pipeline existente e conferência posterior. Não instalar a pasta principal sobre o destino. A sequência solicitada mantém ACT-02 a 16 por iniciar após a instalação e o saldo de ACT-01; persistência no servidor, cobertura factual e consulta pública continuam pendentes. Sem declaração de conferência visual autenticada. -### 29/10/2026 — ACT-20261029-01, primeiro incremento instalado: 23ecccfa - -Estado corrente de ACT-01: **parcial — primeiro incremento instalado**, substituindo apenas o estado planeado/preparado deste recorte; ACT-02 a 16 não foram implementadas nesta entrega. Instalado por avanço normal de main e pipeline existente em https://teste-investidor.tempo.co.mz/. Entrada: Gestão → Clusters → Editar → Competitividade — cinco forças de Porter. Preparação qualitativa por sector/região, evidências/fontes/períodos/limites e oportunidades, transferência JSON e recuperação confirmada do mesmo cluster. Sem gravação no servidor nem publicação da análise. Persistência, cobertura factual, território canónico e consulta pública continuam pendentes; esta instalação não encerra o critério amplo ACT-01. - -Provas: backup fresco, restauro isolado sem rede das 176 tabelas; pipeline com lifecycle de schema (3.106 asserções), 59 testes Unit/320 asserções e 1.180 testes frontend sem falhas, tipos e compilação; quatro ficheiros do incremento conferidos por SHA-256 no instalado; C132 no destino passou. Comparação após instalação: todas as 176 tabelas de domínio preservadas, diferenças operacionais apenas em cache/sessões; 369 ficheiros/configuração idênticos. Acesso anónimo ao catálogo privado recusado HTTP401. Zero migrações/importações, nenhuma nova divulgação nem mudança de permissões; versão anterior 332c16eb preservada. Conferência visual autenticada permanece pendente. Recibo: `docs/investmoz/unification/competitiveness-sequential-qa-20261029.json`, em docs/investmoz/unification. As provas aceites anteriores foram reutilizadas; não foram reabertas por esta entrega. -### 29/10/2026 — ACT-01, persistência e aprovação: execução em curso - -Ordem confirmada pela Tempo: 1) gravar/validar/recuperar na gestão com permissões e histórico, 2) consultar publicamente apenas conteúdo aprovado, 3) restantes alterações. A instalação da interface 23ecccfa e os 1.180 testes anteriores são provas desse incremento, não prova de persistência. Sem perda nova confirmada; preservar a versão pública anterior e os recibos de backup/restauro. O problema dos filtros provinciais permanece **separado e aberto**, sem declaração de correcção por estes trabalhos. - -Escolha técnica: reutilizar snapshots cifrados nos eventos append-only de auditoria, já usados pelo portal; bloqueio transaccional do cluster, controlo de versão e histórico imutável. Sem alteração de schema/permissões. Guardar rascunho e recuperar histórico não publica; aprovação explícita fixa a versão consultável, edições seguintes preservam a aprovação anterior até nova decisão. Rascunhos parciais são guardáveis; aprovação exige os fundamentos das cinco forças. Recuperação/conflito não deve sobrescrever edições inadvertidamente. Acesso público continua limitado às fichas publicadas. Implementação e provas específicas de persistência/consulta ainda em preparação; restantes ACT mantêm o estado anterior. -### ACT-01 — prova específica antes da instalação, 29/10/2026 - -Sete testes Feature/93 asserções passaram na base restaurada competitiveness_persistence_20261029_test, porta 55441: gravação e leitura HTTP entre pedidos, retorno pela edição da gestão, histórico cifrado, validação de campos/cluster/forças, normalização do formato recuperável, conflitos sem sobrescrita, aprovação fixa, rascunhos posteriores sem divulgação, recuperação histórica como nova versão, retirada e exclusão do conteúdo não aprovado na consulta pública. Utilizadores sem permissão e pedidos anónimos foram recusados na gestão. O teste público percorreu a ficha publicada e confirmou 404 da ficha não publicada. Zero escritas na base activa. Esta prova não afirma conferência visual autenticada nem correcção dos filtros provinciais, que permanecem abertos. Recibo: docs/investmoz/unification/competitiveness-persistence-qa-20261029.json. Compilação QA, tipos e quatro testes frontend dirigidos passaram; instalação ainda pendente. -### 29/10/2026 — ACT-01, gravação/recuperação e consulta aprovada instaladas: b81f477b - -Instalado pelo avanço normal de main e pipeline existente, preservando 23ecccfa para retorno. Gestão → Clusters → Editar → Competitividade agora recupera o rascunho do servidor e permite gravar, consultar a versão actual, confirmar recuperação e recuperar uma versão histórica como nova gravação. Versões cifradas e imutáveis na auditoria existente, com bloqueio transaccional do cluster e controlo de versão; conflitos conservam a versão guardada e os campos do editor. Reutilizada a permissão existente de gestão, sem novos papéis ou aprovadores. Rascunhos incompletos podem ser guardados; a aprovação exige âmbito e fundamentos das cinco forças. - -**Percurso da gestão:** preencher → Guardar rascunho no servidor → voltar à edição para recuperar → consultar histórico quando necessário. Para comparar com outra gravação, usar Consultar versão actual do servidor e confirmar antes de substituir os campos; transferir primeiro edições que se queira conservar. Recuperar o histórico cria nova versão e mantém o histórico e a aprovação pública existente. A aprovação ou retirada é expressa, com evidência/motivo registado. A ficha pública de um cluster publicado mostra exclusivamente a análise aprovada; novas gravações privadas não alteram essa versão. Uma ficha não publicada continua indisponível ao público. Não houve aprovação nem divulgação automática de análises. - -**Prova específica:** sete testes Feature/93 asserções na base restaurada e isolada competitiveness_persistence_20261029_test, porta55441. Abrange gravação/recuperação HTTP, retorno na gestão, validação e formato, histórico cifrado, conflito, acesso recusado, aprovação fixa, rascunho posterior privado, recuperação, retirada e consulta pública/404 de ficha não publicada. Os 1.180 testes frontend não são apresentados como prova substituta de persistência. Pipeline: tipos, compilação, lifecycle de schema1/3106, Unit59/320 e frontend1180 sem falhas. Dez ficheiros de código/testes do instalado conferidos por SHA-256 com os da QA; C132 no destino passou. - -**Preservação e limites:** backup fresco/restauro isolado176; comparação posterior de176 tabelas sem alterações de domínio, apenas diferenças operacionais de cache/sessões; 369 ficheiros/configuração idênticos. Ligação real teste_investidor_app conferida em leitura, com privilégios existentes de SELECT/INSERT em auditoria e bloqueio do cluster; endpoint de gestão anónimo HTTP401. Nenhuma escrita sintética na base activa, migração, importação, mudança de permissões ou nova publicação. A conferência visual autenticada no instalado permanece pendente; não foi simulada uma decisão real de conteúdo no activo. ACT-01 tem agora persistência e consulta aprovada implementadas/instaladas, mantendo parcial a cobertura factual por sector/região. Recibo: docs/investmoz/unification/competitiveness-persistence-qa-20261029.json. - -**Filtros provinciais: separado e aberto.** Esta entrega não alterou a lógica dos filtros nem demonstra a correcção relatada de Agronegócio/Maputo Província no portal. Preservam-se as provas e os estados históricos; não encerrar V2-07/V2-10 ou ACT-02 por causa da persistência de Competitividade. Restantes alterações permanecem na sequência posterior. - -Origem de continuidade: C:/laragon/www/portal-investidor-competitiveness-qa-20261029, ramo codex/competitiveness-persistence-20261029, instalado b81f477b. A pasta principal anterior não deve substituir esta versão sem reconciliação do delta. -### 29/10/2026 — V2-07/V2-10 / ACT-02, diagnóstico dos filtros provinciais em curso - -Separação confirmada pela Tempo: a equipa executará e registará a conferência visual autenticada de Competitividade (continua pendente); o Codex prossegue no código/API dos filtros. Provas aceites preservadas, sem repetição das suites fiscais ou de Competitividade. Nenhuma perda de dados confirmada nesta passagem. - -Reprodução pública em b81f477b: Agronegócio/Maputo Província por province_id na API /api/v1/investment/search devolve5 oportunidades (IDs60–64). O mesmo nome em province devolve0, tanto nessa API como em /api/v1/opportunities/search. A API antiga ignora province_id e devolve34, incluindo outras províncias. São lacunas de normalização/compatibilidade entre entradas, não prova de eliminação nem falha demonstrada da expansão hierárquica já existente. Corrigir apenas os deltas: resolver nomes provinciais públicos inequívocos para a mesma hierarquia e aplicar o filtro territorial na API antiga, preservando outros filtros, versões públicas, localização real e dados. Demonstrar todos os níveis inferiores por pedidos HTTP em QA isolada; província apenas contextual ou declarada não deve ganhar distrito. O problema permanece aberto até às provas específicas e à conferência da API instalada; não encerrar a conferência visual da equipa por testes técnicos. -### 29/10/2026 — duas frentes e diagnóstico local Edge - -A equipa executa directamente e regista a conferência visual autenticada de Competitividade (editar → guardar → reabrir → conferir versão aprovada); estado pendente até execução. O Codex prossegue com código/API dos filtros provinciais, independentemente do navegador. Provas aceites preservadas. - -Ligação identificada: com.openai.codexextension, manifesto stdio válido, extensão Edge instalada e activa no perfil detectado, host executado como filho do Edge; named pipes do browser-use presentes e servidor registado nos logs do cliente. Inspeccionados os listeners/processos sem libertar portas. Não foi identificado conflito TCP nem um serviço de extensão parado. Não foi encontrado erro de permissões no recorte de logs consultado, sem excluir outros pontos. A descoberta desta sessão continua a indicar access host indisponível; o runtime exige caminho do pipe e identidade verificadora, ausentes na shell. Falha de passagem de contexto é uma hipótese delimitada, não conclusão de porta ocupada. O registo de erros do service worker não ficou acessível pela ligação de navegador indisponível. A recuperação suportada, limitada à abertura do perfil Edge detectado, não restabeleceu a leitura do URL. Não foram terminados processos, reinstalados hosts nem alteradas permissões/políticas. InvesteMoz e SGF continuam em execução. Relatório local: outputs/edge-bridge-diagnostic-20261029/report.json. Não declarar recuperada a ligação nem concluída a conferência visual. - -Correcção provincial preparada no ramo codex/province-search-20261029; validação QA/instalação pendentes. A sessão SSH anterior expirou. O lançamento automático de nova consola foi recusado pela revisão automática com indicação genérica blocked by policy, sem razão adicional; foi pedido arranque/autenticação manual no helper existente. Nenhuma escrita no activo ou novo ensaio remoto ocorreu por essa tentativa. -### 29/10/2026 — filtros provinciais: correcção candidata, pendente de QA - -Reproduzido no portal instalado b81f477b: /api/v1/investment/search por province_id de Maputo Província devolve5; por province textual devolve0 nas duas APIs; a API antiga com province_id ignora o parâmetro e devolve34 de Agronegócio. Preparada correcção no ramo codex/province-search-20261029, preservando a expansão de descendentes existente e aplicando a mesma selecção territorial à API antiga. Nomes provinciais só são resolvidos quando a correspondência pública exacta é inequívoca. Declarações provinciais antigas são consideradas sem atribuir distrito, posto, localidade ou coordenadas, e não prevalecem sobre territórios explícitos contraditórios. Nenhum dado cadastral é actualizado por esta correcção. - -Quatro testes HTTP preparados para província/distrito/posto/localidade e localizações adicionais, onze províncias e exclusão de vizinhas/privados/eliminados, preservação das localizações e consistência de catálogo/mapa/exportação. Sintaxe PHP e diff conferidos; testes ainda não executados e candidato ainda não instalado. Recibo: docs/investmoz/unification/province-search-qa-20261029.json. A sessão SSH expirou e a nova consola automática foi recusada pela revisão de aprovação com blocked by policy (sem razão específica adicional); pedida autenticação manual no helper outputs/province-search-20261029/ssh-session.py. Não substituir ausência de ensaio por declaração de correcção concluída. - -A conferência visual de Competitividade fica a cargo da equipa e permanece pendente até execução/registo; provas técnicas aceites preservadas. Ligação Edge diagnosticada separadamente: extensão/manifesto/host activos, stdio/named pipes, leitura do URL não restabelecida pela recuperação suportada do perfil. Nenhum processo terminado nem porta libertada/reconfigurada. InvesteMoz e SGF preservados. Relatório local: outputs/edge-bridge-diagnostic-20261029/report.json. Os filtros mantêm-se abertos até QA e confirmação da API instalada. -### 29/10/2026 — filtros provinciais, prova HTTP específica em QA - -Quatro testes Feature/364 asserções passaram na base restaurada province_search_20261029_test, porta55441, candidato e0987afb. Seleccionar só a província, por nome público inequívoco ou ID, inclui registos provinciais, distritais, de posto e localidade e localizações adicionais, nas duas APIs; confirmada cobertura das11 províncias e exclusão de vizinhas. Privados/eliminados não entram; distrito seleccionado não recebe oportunidades apenas provinciais. Declaração provincial antiga não supera localização explícita noutro território. Maputo Província por nome/ID, página do catálogo, mapa e exportação concordam nas5 oportunidades do contexto aprovado; sem coordenadas ou distrito inventados. Campos e relações guardados permanecem inalterados. Zero escritas no activo; nenhuma migração nem alteração de permissões. O conjunto inclui provas novas da hierarquia HTTP, sem reabrir as provas aceites de Competitividade/fiscalidade. - -Recibo: docs/investmoz/unification/province-search-qa-20261029.json. Instalação e confirmação da API no portal continuam pendentes; não declarar encerrado o problema por QA isolada. A conferência visual autenticada de Competitividade permanece separada, pendente de execução e registo pela equipa. A sessão SSH foi reaberta a pedido expresso da Tempo e ficou autenticada; a recusa anterior da abertura automática não constitui bloqueio actual. - -### 29/10/2026 — filtros provinciais corrigidos e confirmados por API no portal: fde73438 - -**Estado deste recorte V2-07/V2-10 / ACT-02:** correcção de código/API implementada, instalada e confirmada em https://teste-investidor.tempo.co.mz/. Avanço normal de main e pipeline existente, versão anterior b81f477b preservada. A selecção provincial por nome público inequívoco ou identificador usa a mesma hierarquia nas APIs /api/v1/investment/search e /api/v1/opportunities/search. Inclui localizações dos níveis inferiores e localizações adicionais; preserva publicação/sector e exclui registos privados, eliminados e outras províncias. Declaração provincial legada não ganha localização distrital nem prevalece sobre território explícito contraditório. Nenhum cadastro foi alterado por esta correcção. - -**Prova HTTP específica:** quatro testes/364 asserções na QA restaurada province_search_20261029_test, porta55441: província/distrito/posto/localidade, localizações adicionais, onze províncias, exclusões, invariância dos dados, catálogo/mapa/exportação. Candidato QA e0987afb; código instalado coincide por SHA-256 com o testado (delta posterior documental). Não substituir esta prova pelos 1.180 testes frontend do pipeline. Pipeline habitual passou schema1/3106, Unit59/320, frontend1180, tipos e compilação. - -**Confirmação no instalado:** comparadas as quatro entradas (duas APIs × nome/ID) para cada uma das11 províncias, com resultados idênticos por província. Agronegócio/Maputo Província: todas devolvem agora5 oportunidades, IDs60–64, corrigindo0 por nome e34 na API antiga que ignorava o ID. Continuam identificadas como contexto provincial do corredor, com district e primary_territory_id nulos; mapa conserva5 sem ponto utilizável e não gera coordenadas. O export respondeu. A inclusão efectiva de níveis inferiores foi demonstrada com fixtures sintéticas exclusivamente na QA, não com dados fictícios no activo. Inhambane devolve0 neste recorte cadastral Agronegócio, de forma consistente nas quatro entradas; isto não é conclusão de ausência de potencial económico. - -**Preservação:** backup fresco/restauro isolado176; comparação posterior de176 tabelas sem alterações de domínio, apenas diferenças operacionais de cache/sessões;369 ficheiros/configuração idênticos. Os4 ficheiros do incremento e10 ficheiros das provas aceites de Competitividade foram conferidos por hash no instalado; C132 passou e catálogo privado anónimo permanece HTTP401. Zero migrações/importações, novas divulgações, mudanças de permissões ou escritas sintéticas no activo. Recibo completo: docs/investmoz/unification/province-search-qa-20261029.json. Autenticação SSH renovada após reabertura expressamente pedida pela Tempo; a recusa anterior do lançamento automático não é bloqueio corrente. - -**Separação mantida:** este resultado encerra a lacuna técnica de compatibilidade/expansão provincial descrita acima, sem declarar conferência visual dos controlos e sem encerrar os requisitos amplos ACT-02/V2-07/V2-10. A conferência visual autenticada de Competitividade continua **pendente — execução e registo pela equipa**. As provas aceites dessa funcionalidade não foram reabertas nem substituídas pela correcção dos filtros. Diagnóstico da ligação Edge continua separado; leitura de URL não declarada recuperada. Nenhum processo local foi terminado nem porta libertada; InvesteMoz e SGF preservados. - -Para o registo da equipa: no cluster autorizado, editar conteúdo legítimo → Guardar rascunho no servidor → sair e reabrir → comparar campos/versão recuperados → conferir na ficha pública exclusivamente a versão aprovada. Registar utilizador/âmbito autorizado, URL/cluster, versão instalada, versões guardada/aprovada, resultado e divergências. Uma nova gravação não deve substituir a aprovação pública existente; nova aprovação depende da decisão de conteúdo aplicável. Sem exemplar aprovado disponível, manter essa parte da conferência pendente em vez de publicar dados sintéticos. - -### 29/10/2026 — correcções e validação automática local após reconciliação - -Validação técnica local concluída na branch `codex/investemoz-reconciliation-20261029`, a partir de `63147312`. Cobertura conferida contra o inventário completo: **798 testes PHP** (91 Unit, 706 Feature em 216 classes e 1 ensaio de schema com 3106 asserções) e **1190 testes frontend**. Tipos TypeScript, PHPStan nível 7 sem erros, Pint, lint/formatação, compilação e os controlos positivos/negativos C132 passaram. Resultados de repetições consolidados por identificador de teste, sem duplicar contagens e sem novos skips. - -Correcções incluem contratos de dados e falhas explícitas de leitura/hash, continuidade do contexto do dossier no simulador, invalidação do cache actual da página inicial, leitura de originais antes do carregamento do catálogo opcional e directório mínimo de contas na administração autorizada. A classificação territorial reutiliza directamente o âmbito público existente, eliminando a subconsulta recursiva redundante; a varredura de rotas com o catálogo territorial completo passou em cerca de 35 segundos, com limite QA de 20 segundos por consulta. Mantidos os testes de exclusão de referências privadas/não aprovadas. Fixtures alinhadas com autenticação, MFA recente, publicação explícita e separação dos snapshots pessoal/económico. O fake HTTP de assets também isola manifestos de fontes mutáveis. - -Execução exclusivamente em bases QA isoladas em `127.0.0.1:55441`, com contextos vazios ou clones preparados conforme as guardas originais. Os 28 originais editoriais foram recuperados de arquivo local e conferidos por SHA-256; seis testes editoriais passaram com scanner real. Preservados os originais, arquivos de fontes, ferramentas históricas, chave da aplicação, dados activos e históricos. Zero migrações/importações/escritas na base activa, push ou deployment. A alteração inclui formatação abrangente do código mantido; o manifesto de hashes identifica os ficheiros validados. - -**Conferência visual autenticada pendente:** a revisão automática interrompeu Computer Use por não conseguir determinar com confiança o URL actual do Chrome. Não foi declarado aceite visual de Competitividade nem encerramento transversal de ACT-01, ACT-02 ou V2-07/V2-10. Recibo e provas: [local-validation-20261029.json](local-validation-20261029.json). - -### daf86234 — âmbito funcional da entrega e conferência visual dirigida - -Delta conferido contra o pai `63147312`. Revisão validada localmente; envio e instalação continuam sem confirmação. A aceitação visual está pendente por bloqueio da ferramenta, que não demonstra falha do portal. - -| Área afectada | Correcção funcional incluída | Conferência visual dirigida | -|---|---|---| -| Dossier → simulador | Ao abrir um dossier sem seleccionar uma oportunidade, o snapshot conserva as oportunidades guardadas como proveniência. Localização, regime e requisitos específicos continuam dependentes da oportunidade escolhida. | Dossier com várias oportunidades: abrir simulador, escolher cada oportunidade, guardar e reabrir; conferir escolhas, contexto específico e edições deliberadas. | -| Manifestação de interesse | A repetição do mesmo envio devolve uma confirmação estável, mesmo após evolução do pedido, sem reabrir o seu estado. A participação relativa a um negócio usa o título público correcto. A chave de envio é validada como UUID obrigatório; essa obrigação já existia antes deste commit. | Enviar interesse numa oportunidade e num negócio; repetir o envio e conferir referência, título e estado actual no acompanhamento, sem duplicação. | -| Página inicial | A gravação ou eliminação de sectores/oportunidades invalida também a chave de cache actualmente usada pela página inicial, em português e inglês, evitando apresentação de dados anteriores. | Após alteração autorizada de um sector ou oportunidade, actualizar a página inicial e conferir a informação apresentada nos idiomas afectados. | -| Classificação territorial | A selecção de localizações reutiliza directamente a consulta territorial pública existente, eliminando uma subconsulta recursiva redundante. Mantém a exclusão de referências privadas, não aprovadas ou com ascendência não pública. | Nos formulários que usam a classificação/localização da oportunidade, abrir as opções e conferir carregamento, selecção e exclusão de referências não autorizadas. A varredura QA de rotas terminou em cerca de 35 segundos; isso não é uma medição do portal instalado. | -| Consulta pública e contacto | Pedidos anónimos deixam de consultar a governação de perfis no middleware de sessão. O POST JSON de contacto deixa de carregar a navegação Inertia, evitando essa dependência de base de dados; mantém os restantes controlos da rota. | Sem autenticação, abrir as entradas públicas afectadas e enviar o formulário de contacto; conferir confirmação e apresentação dos erros de validação. | -| Leitura de artigos de agronegócio | O artigo original continua legível quando o sector/catálogo opcional de oportunidades de agronegócio ainda não foi carregado. Nessa situação, a ausência de ligações de oportunidades deixa de impedir a leitura. | Conferir o artigo de agronegócio e as suas ligações publicadas. A variante sem catálogo é ensaiada apenas em QA, sem remover cadastros do destino. | -| Administração de perfis | Repõe o directório mínimo de contas existentes e as sugestões de selecção nas atribuições e substituições: identificador, nome, email e indicadores de confirmação/MFA. A consulta continua sujeita à administração autorizada e não inclui palavras-passe ou segredos MFA. | Com administrador autorizado e MFA, conferir as sugestões de contas nas atribuições e substituições; verificar também a recusa de acesso por perfil não autorizado, sem efectuar atribuições fictícias no activo. | - -Robustez transversal: Leitura, hash e tamanho de ficheiros e divisões por expressão regular passam a tratar falhas explicitamente. Colecções preservam os seus elementos e rejeitam formas inválidas; valores estruturados indevidos em campos de texto aparecem como valor não textual em vez de [object Object]. Há ainda correcções de contratos de respostas, cabeçalhos, resultados de consultas e verificações de valores ausentes. - -Formatação abrangente do código mantido, tipos, contratos de colecções/consultas/respostas, limpeza de lint e refactorizações auxiliares não constituem novas funcionalidades de negócio. - -Fixtures de autenticação/MFA/publicação, isolamento de bases e ficheiros QA, isolamento dos manifestos de fontes e correcções das expectativas dos testes são suporte da validação, sem novas regras organizacionais. - -Quatro migrações editoriais/de navegação existentes passam a aceitar também a guarda QA isolada já existente. Não são quatro migrações funcionais novas nem prova de execução no destino. - -Competitividade e a compatibilidade dos filtros provinciais já estavam reconciliadas no pai 63147312; não são anunciadas como novas funcionalidades de daf86234. - -Os totais de testes demonstram a validação técnica registada; não comprovam push, instalação, publicação editorial ou aceitação visual. - -A conferência visual é limitada aos ecrãs/percursos afectados e pode ser realizada pela equipa, com registo na mesma matriz: revisão instalada, URL/percurso, perfil/âmbito autorizado, acção, resultado e evidência. O bloqueio da ferramenta não demonstra falha do portal. - -Mantêm-se os estados dos requisitos amplos ACT-01, ACT-02 e V2-07/V2-10. - -Ficheiros e testes por correcção: campo `delivery_scope` do [recibo existente](local-validation-20261029.json). Este aditamento documenta o commit de implementação; não altera código executável nem repete a validação técnica já registada. - -### Entrega Git de daf86234 e 52faf89 — envio confirmado, visual e instalação pendentes - -Branch enviada e SHA remoto conferido: `codex/investemoz-reconciliation-20261029` em `52faf89a2cbd5fa70fb55a42835248e77014d4ae`. `origin/main` actualizado por fetch permanece `fde7343894964043fa633e3d4d07385a6cb7e039`: é antepassado da candidata, com zero commits em falta e 81 commits de histórico reconciliado à frente. `main` não foi avançado nem o instalador accionado. As provas automáticas aceites foram reutilizadas. - -**Delta de entrega conferido:** o pai `63147312` conserva também o incremento anterior `d1551dab` de IVA/P001: campos 05/06/07, agregação exclusiva, contagem única no campo 14 e reutilização dos campos 01/02 actuais. São quatro ficheiros de runtime e dois de testes além da documentação herdada; não atribuir esta alteração a `daf86234` nem a omitir da comparação com o destino. Reutilizar as provas fiscais já aceites e conferir apenas o delta ainda diferente no instalado. - -**Compatibilidade do instalador:** o último contrato de schema registado difere da candidata em cinco hashes de migrações históricas. A comparação estrutural confirmou corpos de operações `up` e `down` equivalentes a main, descontando as quatro guardas QA já validadas; o quinto ficheiro tem apenas formatação. Zero novos caminhos de migração. O pipeline existente recusa diferenças deste contrato: a proposta de cinco hashes está preparada, mas não foi aplicada ao servidor nem houve SQL no activo. Conferir contrato actual e reconciliar pelo processo existente antes de instalar; não contornar a guarda. - -**Conferência visual dirigida: pendente, execução pela equipa.** O conector foi novamente consultado e devolveu browser access host indisponível, sem browsers acessíveis. Usar os sete percursos da tabela anterior e, se ainda integrar o delta do destino, a correspondência/recuperação IVA/P001. Registar na mesma matriz revisão ensaiada, URL QA/percurso, perfil e âmbito autorizado, acção, esperado/observado, evidência e data. Este estado não demonstra falha do portal e não reabre a avaliação de todo o portal. - -**Instalação: pendente conforme a sequência pedida.** O ficheiro antigo de sessão SSH indicava connected_ready, mas o respectivo processo já não está operativo; a tentativa não interactiva com chave de host fixada foi recusada. A revisão instalada, capacidade actual e novo backup/restauro ainda não foram confirmados nesta entrega. Após o registo visual: sessão autenticada, alvo/capacidade/contrato/delta actuais, backup consistente e restauro isolado, avanço normal de main e pipeline existente, preservação da release anterior e verificação final de revisão/hashes/C132/dados/ficheiros/permissões. Sem migrações, importações ou alterações de permissões solicitadas no activo. - -Detalhes, cinco hashes e proposta: campo `git_delivery` do recibo existente `local-validation-20261029.json`. Este registo actualiza o estado de entrega; os resultados e recibos históricos da validação mantêm o seu contexto temporal. - -### 29/10/2026 — preparação autenticada: preservação e contrato concluídos, visual pendente - -Sessão SSH reaberta e autenticada pelo utilizador no terminal. Conferência actual do destino: release `fde7343894964043fa633e3d4d07385a6cb7e039`, symlink correcto, pipeline inactivo e C132 positivo. Cerca de 67 GiB livres e 51 GiB de memória disponível no ensaio, 12 CPUs lógicas; mantida a verificação existente de 5 GiB do instalador. - -Backup fresco consistente de `teste_investidor:5432`, criado em 29/10/2026 às 22:25:27 (Africa/Johannesburg), em `/var/backups/investmoz-validated-delivery-20261029T202505Z/backup`: 200 tabelas de schemas não sistémicos e 369 ficheiros/configurações verificados. Restauro isolado sem rede, porta interna55441: contagens e checksums iguais nas 200 tabelas; contentor temporário removido. O inventário de 200 inclui os outros schemas além das 176 tabelas públicas dos recibos anteriores; não indica perda nem invalida essas provas. Hash do dump: `89739eb0ac022b90423ab30194d4fcc7a81a1fffc97af260a43f9e902f3f1ea9`. - -**Contrato reconciliado no servidor:** alterados apenas os cinco hashes revistos, após confirmar que as cinco migrações já estão no ledger e que a cópia anterior coincide com o instalado. Corpos de operações equivalentes; nenhuma migração repetida e nenhum SQL de alteração na base activa. Pipeline byte a byte preservado, incluindo a comparação estrita do contrato. Contrato anterior conservado no backup; recibo auditável em `schema-contract-reconciliation.json` na pasta superior. C132 voltou a passar após a reconciliação. - -**IVA herdado conferido contra o instalado:** os quatro ficheiros de runtime instalados coincidem por SHA-256 com `main` e ainda não contêm o incremento `d1551dab`. O âmbito de entrega é a correspondência 05/06/07, pertença exclusiva das operações, contagem única no campo14 e reutilização actual dos campos01/02. Não cria tratamento positivo06, não infere estrangeiro=06 nem transforma desconhecido em zero. Provas IVA/P001 aceites reutilizadas, com preservação de histórico, snapshots e edições deliberadas. - -**Continua pendente a conferência visual dirigida da candidata**, pela equipa, com registo nesta matriz. O conector permanece sem browser acessível. Não houve avanço de main, troca de release, importações ou alteração de permissões. Após o resultado visual, reconferir que o destino e a base de preservação continuam actuais antes do avanço normal e do pipeline existente; preservar quaisquer alterações legítimas entretanto ocorridas. As provas automáticas de 798 testes PHP e1190 frontend mantêm-se aceites, sem repetição integral. Detalhes no campo `git_delivery.authenticated_preparation` do recibo existente. - - -### 29/10/2026 — revisão dirigida de erros e inconsistências após a preparação - -Corrigidos dois defeitos sobre `4f72751b`: uma oportunidade explícita fora de um dossier sem escolhas era descartada silenciosamente, passando a contexto geral; agora é recusada com HTTP422. O directório de contas assinalava MFA apenas pela data de confirmação; agora exige também segredo existente e projecta apenas o booleano, sem carregar nem divulgar o segredo. Não foram alteradas permissões nem dados de contas. - -Ambos reproduzidos antes da correcção. Passaram 3 testes Unit novos (5 asserções) e 20 testes Feature existentes dirigidos (461 asserções), incluindo os estados MFA incompletos. PHPStan e Pint passaram no âmbito registado no recibo. Reutilizadas as provas históricas de 798 PHP e 1190 frontend: não se afirma uma nova execução integral. Conferidos os 32 ficheiros de provas anteriores, sem divergências; contrato de migrações mantém-se compatível, sem novo delta de schema. - -Diagnóstico autenticado apenas de leitura às 20:40:29 UTC: destino continua em `fde73438`, nenhum erro Laravel datado de hoje no conjunto limitado examinado (até quatro logs recentes, últimos 2MiB por ficheiro), nenhum índice não sistémico inválido e nenhuma conta com confirmação MFA sem segredo em `teste_investidor:5432`. Não é uma auditoria histórica completa. Nenhuma instalação ou escrita na base activa. Conferência visual dirigida da candidata continua pendente; incluir estes dois comportamentos nos percursos já afectados. Evidências e hashes do novo delta no campo `targeted_error_consistency_review` do recibo existente. - - -### 29/10/2026 — percurso adaptativo: situação e próxima acção visíveis no resumo - -Incremento de apresentação sobre `fb9a363e`, nos requisitos existentes V2-07/V2-10 e na orientação da Tempo de 23/10: com preparação activa, a situação do pedido, próxima acção e informação em falta passam a estar visíveis antes da secção fechada de detalhe. O investidor mantém a ligação existente para continuar o formulário; fontes, documentos e histórico sem aplicação continuam consultáveis. A preparação inactiva não passa a exigir passos novos. O componente partilhado cobre o percurso do investidor, a avaliação de contexto e a comparação de impacto. A alteração não edita declarações nem altera regras de enquadramento, cálculo, permissões ou schema. - -Conferência dirigida: seis testes frontend existentes passaram; 22 verificações SSR cobriram os três modos, rótulos de dados em falta, preparação inactiva/ausente, ligação de continuação, histórico preservado e imutabilidade da origem. Tipos, formatação, lint e compilação QA passaram. Provas anteriores reutilizadas. Recibo no campo `adaptive_summary_increment` de `local-validation-20261029.json`. - -**Conferência visual pendente pela equipa:** na candidata, abrir o resumo de preparação activo, conferir situação/próxima acção/dados em falta sem expandir detalhes, continuar pelo formulário e consultar histórico/fontes; verificar também preparação inactiva e ausência de dados em falta. Registar revisão, perfil, percurso e resultado nesta matriz. SSR não comprova apresentação no navegador. Sem instalação ou avanço de main; este incremento não encerra os requisitos transversais. - - -### 29/10/2026 — percurso adaptativo: documentos em falta e recuperação das associações - -Continuação sobre `d662e634`, nos requisitos existentes V2-07/V2-10 e na decisão adaptativa da Tempo de 23/10. O resumo distingue documentos obrigatórios por associar, documentos associados cujo conteúdo continua por conferir e exigências documentais ainda por determinar; o histórico sem aplicação não é contado como pendência. Com dados completos e âmbito/período cobertos, a acção de continuação conduz à secção existente de documentos. Nos restantes estados mantém o destino do formulário. São decisões de apresentação/navegação; não criam novas condições de negócio. - -No editor, os documentos ainda por associar mantêm-se visíveis; os já associados ficam em «Documentos já associados — consultar ou alterar». A retirada deliberada permanece por confirmar na comparação de impacto e não é substituída pelo identificador guardado. O agrupamento usa o estado recuperado, conservando o controlo durante a edição. Dados, documentos originais, histórico, regras fiscais, backend, schema e permissões preservados. - -Passaram oito testes frontend dirigidos: seis existentes e dois novos para encaminhamento conforme contexto, distinção entre associação/aprovação/indeterminação, controlos recuperados editáveis, retirada explícita, recuperação sem mutação do original e estado desactivado dos controlos. Tipos, lint, formatação e compilação QA passaram. Recibo e hashes no campo `adaptive_documents_increment` de `local-validation-20261029.json`; provas integrais aceites não foram repetidas. - -**Visual continua pendente, execução pela equipa:** na candidata, conferir contagens e destino com/sem dados em falta; abrir documentos já associados, alterar/retirar uma associação, comparar impacto antes de confirmar e verificar recuperação. Incluir também âmbito/período não cobertos e exigências indeterminadas, sem interpretar associação como aprovação. Registar revisão, perfil, percurso, esperado/observado e evidência nesta matriz. Sem instalação ou avanço de main; requisitos transversais continuam parciais. - - -### 29/10/2026 — comparação de impacto: alterações das associações documentais - -Continuação sobre `181a9883`, nos requisitos existentes V2-07/V2-10 e na decisão adaptativa de 23/10: explicar divergências e impacto antes da confirmação. Lacuna reproduzida na revisão anterior: a comparação mostrava apenas alterações de estado, omitindo a troca de documento quando ambos mantinham «associado». O texto de vínculo preservado também não distinguia substituição de conservação. - -Corrigido no componente existente: comparação por estado e identificador documental, com substituição, associação e retirada explícitas; nomes anterior/novo quando disponíveis, nome indisponível identificado sem inventar o ficheiro, e vínculo preservado apenas quando o identificador permanece. A ausência de alterações é expressamente limitada às exigências/associações documentais. O plano anterior/posterior já fornecido pelo backend e a confirmação de impacto mantêm-se; não há escrita em dados, mudança de schema, permissões ou cálculo. - -Dois novos casos falharam contra o código anterior e passaram na candidata. Dez testes frontend dirigidos passaram, cobrindo também troca com o mesmo nome, retirada, nova associação, nome indisponível, histórico sem aplicação, ausência de alterações e preservação da origem. Tipos, lint, formatação e compilação QA passaram. Provas históricas aceites reutilizadas, sem repetição integral. Recibo e hashes no campo `adaptive_document_impact_increment` de `local-validation-20261029.json`. - -**Visual pendente pela equipa:** na candidata e num dossier autorizado, preparar troca/retirada de documento, comparar antes de confirmar e conferir nomes/estado anterior e posterior; confirmar que associação mantida não surge como substituição e que o histórico permanece. Não é necessário confirmar uma alteração real para observar a prévia. Registar revisão, percurso, perfil, esperado/observado e evidência nesta matriz. Nenhuma instalação ou avanço de main; o incremento não encerra o percurso adaptativo transversal. - - -### 29/10/2026 — comparação de contexto: proteger edições e recusar prévias desactualizadas - -Continuação sobre `a10dd83d`, nos requisitos existentes V2-07/V2-10 e na orientação adaptativa da Tempo de 23/10. Alguns controlos de declarações, adição de oportunidade e substituição explícita continuavam editáveis durante o pedido de comparação. A resposta podia tornar confirmável um plano anterior às escolhas apresentadas; iniciar outra comparação também conservava o plano precedente em caso de falha. - -Corrigido no editor existente: os controlos referidos acompanham o estado ocupado dos restantes; uma nova comparação invalida o plano e corpo de confirmação anteriores; antes de aceitar a resposta compara-se o snapshot do rascunho pedido com o actual. Se diferirem, a resposta não pode ser confirmada e as edições posteriores ficam conservadas, com pedido explícito para comparar de novo. É consistência técnica da confirmação existente, sem nova condição organizacional e sem alteração de backend, schema, permissões ou cálculo. - -Três casos novos falharam contra a revisão anterior e passaram na candidata: bloqueio/recuperação dos controlos durante comparação, recusa de resposta para rascunho alterado preservando a edição, e falha de nova comparação sem reutilização do plano anterior. Treze testes frontend dirigidos passaram. Tipos, lint, formatação e compilação QA passaram; provas históricas aceites reutilizadas, sem repetição integral. Detalhes/hashes em `context_preview_consistency_increment` do recibo existente `local-validation-20261029.json`. - -**Conferência visual pendente pela equipa:** na candidata, comparar dados de um dossier autorizado, conferir bloqueio temporário e reposição dos controlos; preparar nova edição e repetir a comparação, garantindo que só a prévia actual permite guardar. Em falha de comunicação, os valores permanecem e exige-se nova comparação. Não gravar dados sintéticos no activo para este ensaio. Registar revisão, perfil, percurso, esperado/observado e evidência nesta matriz. Sem instalação ou avanço de main; os requisitos transversais continuam parciais. - - -### 29/10/2026 — recuperar a versão guardada sem repetir a confirmação - -Continuação sobre `26f6a0d3`, nos requisitos existentes V2-07/V2-10 e na orientação adaptativa da Tempo de 23/10. Reproduzida a diferença entre gravação e leitura: uma confirmação bem-sucedida seguida de falha na consulta era apresentada como falha genérica, com a prévia anterior ainda disponível. O rascunho consumido também podia ser reenviado ao sair antes da recuperação. - -O editor invalida a prévia/corpo de confirmação e consome os parâmetros de entrada logo após resposta positiva da gravação. Até recuperar a versão guardada, suspende edição e envio de rascunho antigo. Se a leitura falhar, informa que os dados foram guardados e disponibiliza «Recuperar dados guardados», que repete apenas a consulta. A recuperação repõe valores/versão actuais e a edição normal, sem novo POST de confirmação. Se a própria gravação for recusada, conserva os dados e a possibilidade de tentar novamente sem afirmar sucesso. Mantida a confirmação/idempotência do backend; nenhuma mudança de schema, permissões ou regras fiscais. - -Dois casos novos: um reproduziu a lacuna no código anterior e o caso de gravação recusada já passava. Na candidata passaram ambos e os treze casos existentes, total de quinze testes frontend dirigidos. Verificados consulta repetida sem regravação, prévia consumida, conservação do hash do URL, ausência de envio do rascunho antigo em pagehide, valores recuperados e uso da nova versão na comparação seguinte. Tipos, lint, formatação e compilação QA passaram. Provas aceites reutilizadas; recibo/hashes em `context_saved_recovery_increment` de `local-validation-20261029.json`. - -**Visual continua pendente pela equipa:** na candidata QA, conferir gravação normal e recuperação após falha apenas da leitura, verificando mensagem, bloqueio temporário e recuperação sem nova gravação; distinguir de gravação recusada. Usar ensaio de falha controlado em QA, sem criar dados sintéticos no activo. Registar revisão, perfil, percurso, esperado/observado e evidência nesta matriz. Sem instalação ou avanço de main; o requisito transversal permanece parcial. - - -### 29/10/2026 — rascunhos: transporte por bytes, concorrência e contexto extenso - -Continuação sobre `fa2ece10`, nos requisitos existentes V2-07/V2-10 e na orientação adaptativa da Tempo de 23/10. A escolha de keepalive usava caracteres em vez de bytes UTF-8; pedidos concorrentes não partilhavam orçamento local; ao sair, um rascunho com 60000 caracteres ou mais era simplesmente ignorado. Três regressões reproduzidas contra o código anterior: texto multibyte, concorrência e saída com cem oportunidades. - -O transporte existente serializa uma vez, conserva o corpo integral e decide por bytes UTF-8, incluindo os pedidos keepalive de contexto ainda em curso. A reserva é libertada em sucesso ou erro. O envio automático e a saída delegam essa decisão no transporte; corpos maiores seguem pelo fetch normal, sem truncagem nem repetição automática de gravações. Os 60000 bytes são uma margem técnica local abaixo dos 64KiB agregados previstos na [especificação Fetch](https://fetch.spec.whatwg.org/#http-network-or-cache-fetch), não um novo limite funcional do dossier. Autenticação, métodos e tratamento dos conflitos HTTP mantidos. - -Cinco testes novos e quinze existentes passaram, total de vinte testes frontend dirigidos. Cobertura: corpo Unicode integral, caracteres versus bytes, concorrência/libertação de reserva, falha sem repetição de escrita, GET/POST/CSRF/conflito e rascunho de cem oportunidades entregue integralmente ao transporte ao sair. Tipos, lint, formatação e compilação QA passaram; provas históricas aceites reutilizadas. Recibo/hashes em `context_draft_transport_increment` de `local-validation-20261029.json`. - -**Limite da prova:** fetch normal após a saída continua a ser tentativa de melhor esforço; o orçamento local não reserva capacidade usada por outro código no navegador. Não se declara gravação garantida ao fechar imediatamente a página. Mantêm-se o envio automático normal, o estado do rascunho e a tentativa explícita após falha. Conferência visual pela equipa permanece pendente: na candidata QA, preparar texto acentuado e selecção extensa, aguardar «Rascunho guardado», sair/regressar e conferir valores e oportunidades recuperados. Registar revisão, perfil, percurso e evidência nesta matriz. Sem instalação, avanço de main ou escrita no activo; backend, schema, permissões e cálculo preservados. - - -### 29/10/2026 — envio automático: sequência própria e respostas de rascunhos antigos - -Continuação sobre `ed96fd10`, nos requisitos existentes V2-07/V2-10 e na orientação adaptativa da Tempo de 23/10. O temporizador obtinha a sequência quando disparava, podendo emparelhar um corpo antigo com uma sequência posterior. Um corpo já ultrapassado também podia continuar na fila; a comparação apenas pelo conteúdo permitia assinalar como guardada uma revisão posterior que tivesse voltado aos mesmos valores. - -O editor captura corpo e sequência em conjunto. Antes do envio em fila e da apresentação de sucesso/erro, exige correspondência do corpo e da sequência actuais, sem recuperação de contexto guardado pendente. Os envios ultrapassados são descartados sem pedido nem indicação de gravação; o envio da revisão actual mantém a sequência própria. A protecção existente do servidor contra versões/sequências antigas foi consultada e preservada, não relaxada. Nenhuma mudança de backend, schema, permissões ou cálculo. - -Dois casos novos falharam contra o código anterior e passaram na candidata. Vinte e dois testes frontend dirigidos passaram: temporizador antigo após edição, envio ultrapassado em fila, resposta tardia depois de A→B→A, sequência crescente e confirmação somente do rascunho actual. Tipos, lint, formatação e compilação QA passaram; provas históricas aceites reutilizadas, sem repetição integral. Recibo/hashes em `context_autosave_ordering_increment` de `local-validation-20261029.json`. - -**Visual pendente pela equipa:** em QA, editar sucessivamente enquanto um envio automático aguarda, incluindo regressar ao valor inicial; aguardar a confirmação da revisão actual, sair/regressar e conferir os últimos valores recuperados. Usar atraso controlado de rede em QA, sem alterações sintéticas no activo. Registar revisão, perfil, percurso, esperado/observado e evidência nesta matriz. A prova com temporizadores/fila não substitui a sessão no navegador. Sem instalação ou avanço de main; requisitos transversais permanecem parciais. - - -### 29/10/2026 — ACT-20261029-02: camadas existentes e cobertura explícita do mapa - -Incremento funcional sobre `87b74f0c`, reutilizando o mapa, as APIs e os filtros territoriais existentes (V2-07/V2-10). Antes da execução foi conferida a matriz e o contrato de `InvestmentCatalogue::map`: pontos, áreas/limites, registos sem coordenadas, fonte/data, limite de resposta e contagens já estavam disponíveis. Não houve perda confirmada nem se reabriu a correcção provincial instalada. - -O painel permite ocultar/repor independentemente pontos e áreas/limites, ambos visíveis por defeito. As opções não mudam filtros, não fazem nova consulta nem eliminam registos. O novo resumo mostra marcadores/áreas recebidos, falta de fonte/data e investimentos sem ponto utilizável, incluindo camadas ocultas; mantém as ligações às fichas. Distingue investimento de marcador: um investimento pode ter vários locais. O total passa a usar `matched_count` da API, em vez de somar marcadores como investimentos; fallback deduplica os identificadores. A indicação de truncagem é agora aviso de cobertura, não falha de ligação. Fontes/datas vazias não passam a comprovadas; ausência de registos não é ausência de investimento. - -Dois testes frontend dirigidos passaram: contagens/proveniência desconhecida/resposta limitada/ausência de dados e ocultação/reposição sem perder registos, filtros ou fichas. O exemplo contém dois marcadores do mesmo investimento e distingue o total encontrado do subconjunto recebido. Tipos, lint, formatação e compilação QA passaram. Provas territoriais e das funcionalidades anteriores reutilizadas, sem repetição integral. Recibo/hashes no campo `map_layer_coverage_increment` de `local-validation-20261029.json`. - -**ACT-02 permanece parcial:** este recorte implementa controlo das camadas já existentes e explicitação de cobertura. Não cria camadas factuais de recursos, infra-estruturas, mão-de-obra ou potencial económico, nem declara completa a cobertura provincial/distrital. Backend, geometrias, divulgação, permissões, fontes, datas e cálculo preservados; sem importações ou escrita no activo. - -**Visual pendente pela equipa:** na candidata, conferir os mapas da ficha de oportunidade, carteira e zona de investimento; ocultar/repor cada camada e ambas, conferir contagens de investimentos/marcadores, fonte/data ausentes e fichas sem coordenadas, e mudar filtros territoriais. Registar revisão, perfil, percurso, esperado/observado e evidência nesta matriz. O painel de contexto administrativo separado mantém o seu âmbito. Sem instalação ou avanço de main. -### 02/11/2026 — histórico administrativo dos formulários do Balcão - -AUD-CHECKLIST-01, incremento local parcial: o editor permite consultar definições anteriores, dez por página, com perguntas, condições, fonte, data, motivo e identificadores dos intervenientes quando registados. Inclui serviços históricos retirados da configuração actual, exclusivamente para consulta; não os torna novamente publicáveis. A consulta reutiliza a autorização administrativa existente e não devolve respostas dos requerentes. Pedidos anteriores conservam a versão e o conteúdo submetido. Respostas tardias de outro serviço/página não substituem a selecção actual; falha, histórico vazio e repetição têm estados distintos. - -Provas: quatro testes Feature/91 asserções (`storage/logs/desk-service-history-feature-20261102.log`), três testes frontend do editor/histórico, PHPStan sem erros, tipos e lint/formatação aprovados. A conferência visual permanece pendente pela limitação do controlo do navegador já registada. Sem instalação, alterações no activo ou encerramento da parametrização transversal. - -Reconciliação da integração: a repetição fiscal com referências preparadas em QA resultou em 162 testes, 106 aprovados, nove falhas e 47 erros (`integration-fiscal-reference-retry-20261102.log`). Persistem dependências de acervos/identidades históricas e casos a investigar; não constitui aprovação global. Conferidos por SHA-256 os 63 artefactos históricos protegidos: quatro alterados pelos ensaios foram repostos, preservando separadamente os resultados novos; zero divergências finais (`integration-output-reconciliation-20261102.json`). Não foram inventadas oportunidades publicadas ou decisões para satisfazer testes. ACT-16: o proprietário respondeu «ainda nao» quanto a prioridades e traduções de línguas nacionais; essa definição continua pendente, sem impedir os restantes desenvolvimentos. - -### 02/11/2026 — perguntas encadeadas e preenchimento conforme a versão do formulário - -AUD-CHECKLIST-01, continuidade local: reproduzidos dois erros no código anterior. Uma resposta conservada num campo oculto activava uma pergunta descendente na página e tornava-a obrigatória no servidor. A avaliação percorre agora as condições dos antecessores, independentemente da ordem das perguntas; ocultar uma pergunta conserva os valores, e voltar a activar o ramo recupera-os. Perguntas efectivamente aplicáveis continuam obrigatórias na submissão, com rascunhos incompletos permitidos. Não se alteram as definições ou submissões históricas. - -A criação de pedidos também preenchia `title`, `description` e `regime` mesmo depois de retirados da nova definição, e podia escolher `unknown` quando essa opção já não existia. O preenchimento respeita agora os campos e opções da versão utilizada; a reutilização do contexto só aplica valores compatíveis com a validação do campo. Não escolhe arbitrariamente outra opção. A validação de dados introduzidos pelo requerente permanece no servidor, incluindo a recusa de campos não configurados. O ensaio operacional reproduziu a falha anterior e demonstrou criação, gravação e submissão das novas versões, opção obrigatória por escolher e preservação integral do pedido antigo. - -Provas: regressões anteriores em `storage/logs/desk-request-conditions-before-20261102.log` e `desk-schema-prefill-before-20261102.log`; quatro testes frontend do pedido/editor/histórico aprovados, PHPStan, tipos, lint/formatação e compilação local aprovados. Resultados Feature individuais: 21 testes/382 asserções no Balcão após a correcção das condições e um teste/34 asserções do percurso de preenchimento por versão. A verificação conjunta final usa `desk-forms-combined-feature-20261102.log`. As provas são técnicas e sintéticas em bases descartáveis, porta 55441; não equivalem a conferência visual ou aceitação por requerentes reais. Sem instalação ou escrita no activo; outras checklists, consumidores e critérios transversais continuam parciais. - -Verificação conjunta final deste incremento: **22 testes Feature/416 asserções aprovados** em `storage/logs/desk-forms-combined-feature-20261102.log`. Os quatro testes frontend, PHPStan, tipos, lint sem avisos e compilação também passaram. Recibo e SHA-256 das fontes em `desk_forms_increment_20261102` de `local-validation-20261029.json`; resultados anteriores preservados nos campos próprios. Não altera o estado parcial do requisito nem substitui as verificações visuais pendentes. - -### 02/11/2026 — verificações e recibos respeitam as perguntas aplicáveis - -Continuidade local de AUD-CHECKLIST-01 e do percurso adaptativo de 23/10: reproduzidos avisos para completar financiamento em formulários sem essas perguntas e bloqueio da submissão por valores conservados em perguntas financeiras ocultas. A análise passa a utilizar a definição imutável do pedido e a mesma avaliação dos antecessores usada na validação. Só compara investimento/financiamentos quando as três perguntas se aplicam; não solicita localização ausente ou não aplicável. As diferenças financeiras aplicáveis continuam a impedir submissão, e dados aplicáveis em falta continuam indeterminados, sem substituição por zero. - -O recibo HTML distingue os dados aplicáveis das respostas conservadas de perguntas não aplicáveis, preservando todos os valores e o escape de conteúdo. Usa as condições e rótulos da versão submetida, mesmo após publicação de outra versão. A descarga técnica original, o conteúdo cifrado da submissão e as permissões permanecem preservados. Consumidores que renderizam directamente a vista continuam a funcionar com o contrato anterior. Esta separação é uma apresentação do histórico, não a eliminação das respostas. - -Corrigida também a possibilidade de publicar uma definição impossível de preencher: conservar a localização retirando a sua fonte, ou fazendo a fonte depender de condições mais restritas. A publicação exige que a fonte esteja disponível sempre que a localização se aplica, permitindo as mesmas condições, condições de antecessores mais abrangentes ou ausência de condição. Retirar ambas as perguntas continua permitido. A exigência de fonte da localização já existia no servidor; este incremento valida a sua coerência antes da publicação, sem criar uma nova competência ou regra organizacional. Uma localização conservada num ramo não aplicável não exige fonte oculta; quando aplicável, mantém essa exigência. - -Provas técnicas em QA descartável, porta 55441: **25 testes conjuntos/467 asserções**, um teste de compatibilidade do recibo/seis asserções e um teste de localização condicional/cinco asserções, todos aprovados. PHPStan sem erros e Pint aprovados. Logs: `desk-analysis-schema-combined-20261102.log`, `desk-receipt-compatibility-20261102.log`, `desk-location-applicability-20261102.log` e `desk-analysis-schema-phpstan-20261102.log`, em `storage/logs`. Falhas anteriores reproduzidas nos logs `desk-form-analysis-before-20261102.log` e `desk-location-schema-before-20261102.log`. Referências territoriais do teste reutilizam o pacote já verificado pelo seeder existente; não representam uma implantação real. Recibo e hashes em `desk_analysis_scope_increment_20261102` de `local-validation-20261029.json`. - -Reutilizadas as provas anteriores de tipos, frontend e compilação: este delta só altera PHP, vistas Blade e testes. Conferência visual dos recibos e do percurso permanece pendente pela limitação de controlo do navegador registada. Não houve instalação, novas permissões, migração de schema ou escrita no activo. O requisito transversal continua parcial; esta prova não encerra outras checklists nem a integração fiscal global. - -### 02/11/2026 — ACT-20261029-11: preferências e alertas do catálogo público - -Incremento local de ACT-11 e MASTER-471012ab-0124: as notificações de manifestações já existentes foram preservadas e passaram a receber também correspondências do catálogo público de oportunidades. Em `/investidor/notifications`, cada conta verificada pode activar voluntariamente, escolher sector, província e modalidade, definir frequência, recuperar/alterar preferências e cancelar. O servidor utiliza sempre a conta autenticada, valida os códigos contra as opções divulgáveis e exige confirmação para activar; cancelar exige apenas a versão, sem depender de opções entretanto retiradas. Preferências cifradas, versão, consentimento e auditoria nominativa; repetição da mesma gravação não cria outra versão. Alterações concorrentes incompatíveis devolvem conflito, sem substituir silenciosamente a configuração guardada. - -O gerador reutiliza `InvestmentCatalogue::query`, incluindo hierarquia territorial, publicação, exclusão de exemplos, dados privados e publicações futuras. A activação, reactivação ou mudança de critérios regista as identidades actualmente públicas como ponto de partida, sem avisos retroactivos. As novas disponibilizações compatíveis geram uma notificação por conta/oportunidade, mesmo quando a data documental de publicação é anterior à activação; não se usa essa data como cursor de descoberta. A correspondência conserva fonte, data publicada quando disponível, versão e critérios usados, sem copiar dados privados ou afirmar rentabilidade/elegibilidade. Uma oportunidade retirada deixa de aparecer ou ser aberta através da notificação; o registo e o histórico não são apagados. Referência territorial/sectorial entretanto indisponível suspende apenas a correspondência afectada, com informação visível e possibilidade de cancelar; não bloqueia os restantes subscritores. - -Frequências implementadas: próxima verificação, intervalos de 24 horas ou de sete dias. Canal disponível: notificações no próprio portal. `investmoz:dispatch-opportunity-alerts` está registado no agendador existente a cada cinco minutos, sem sobreposição; a execução periódica depende do agendador da instalação. O limite técnico de 200 correspondências por conta e execução mantém o restante lote pendente para a execução seguinte, sem o consumir. A entrega e o marcador de descoberta partilham transacção; falha não consome a oportunidade nem avança a próxima execução. Cancelamento e geração serializam a alteração da mesma preferência; notificações anteriores e acompanhamento de manifestações permanecem disponíveis. - -Migração instalável `2026_11_02_190000_investment_opportunity_alerts.php`: estende as notificações existentes com uma origem alternativa, preserva as linhas antigas e cria preferências/marcadores de descoberta. A origem de cada notificação é exactamente uma manifestação ou oportunidade. A reversão recusa eliminar preferências ou histórico de alertas existentes. O ensaio de actualização foi executado com uma notificação anterior não vazia e conservou todos os seus valores. Sem migração, a página antiga permanece operacional; a instalação do incremento segue as migrações normais do produto, não caminhos ou contas de desenvolvimento. - -Âmbito ainda parcial: esta entrega não integra concursos ou incentivos de outros catálogos, não disponibiliza email/SMS, não confirma canais externos e não instala o agendador no destino. Esses percursos e a conferência visual continuam pendentes; a geração no portal não os substitui. Desenvolvimento e dados sintéticos apenas em QA isolada, porta 55441. Sem instalação, mensagens externas, novas competências organizacionais ou alterações no activo. Provas técnicas e hashes conservados no campo `opportunity_alerts_increment_20261102` do recibo existente `local-validation-20261029.json`. - -Verificação final: **16 testes Feature/253 asserções**, incluindo os nove testes existentes da área de manifestações, e **dois testes frontend**, todos aprovados. PHPStan, tipos, lint sem avisos, formatação e compilação passaram; `git diff --check` sem erros. Logs em `storage/logs/opportunity-alerts-verified-feature-20261102.log`, `opportunity-alerts-frontend-20261102.log`, `opportunity-alerts-verified-phpstan-20261102.log`, `opportunity-alerts-final-types-20261102.log`, `opportunity-alerts-final-check-20261102.log` e `opportunity-alerts-final-build-20261102.log`. Fonte candidata fixada por hashes no recibo; provas anteriores preservadas, sem revisão do estado do activo por inferência. - -### 02/11/2026 — pesquisa rápida: «plantio de algodao» - -Pedido específico da Tempo durante a continuidade: a barra «Pesquisa rápida de oportunidades» deve trazer os resultados solicitados; exemplo fornecido pelo proprietário, «plantio de algodao». A barra já encaminhava `q` para `/oportunidades`, mas os motores tratavam a frase inteira como uma substring e distinguiam a acentuação. A correspondência territorial pelo texto também não abrangia o caso de uma oportunidade localizada num distrito cujo nome provincial só estivesse no cadastro. - -O motor comum `OpportunityTextSearch` é agora usado pelo catálogo e pela API anterior: combina todas as palavras significativas, ignora preposições/artigos correntes, normaliza maiúsculas e acentos e reconhece as variantes delimitadas plantio/plantação/cultivo/semeadura. Não usa «produção» isolada como sinónimo de plantio: produção de óleo, fiação e descaroçamento não passam a cultivo por essa aproximação. Procura apenas os campos publicados, sectores e relações/territórios públicos autorizados; uma província abrange os seus descendentes documentados. `%` e `_` introduzidos pelo utilizador são caracteres literais, não curingas de SQL. Os filtros adicionais, ordenação, paginação, publicação, privacidade e exclusão de exemplos continuam a aplicar-se. - -Quando todos os termos não têm correspondência e existe um termo de cultivo acompanhado de assunto/localização, a página pode apresentar até seis fichas relacionadas com o assunto numa secção separada. O total principal continua zero e os filtros não são alargados. As fichas são identificadas como relacionadas, com resumo visível e possibilidade de consultar explicitamente essa pesquisa; não são reclassificadas como plantio. Nas fontes incluídas em `corridor-investment-opportunities.json`, as três entradas de algodão descrevem descaroçamento, fiação/óleo ou transformação, não uma ficha específica de cultivo. Nenhuma nova oportunidade, parcela, disponibilidade, promotor ou aprovação foi inventada para preencher resultados. - -A barra usa o valor efectivo do formulário, incluindo preenchimento automático do navegador, e conserva o limite de 120 caracteres do servidor. O formulário possui destino GET próprio para funcionar também sem a intercepção JavaScript. O texto pesquisado acompanha a consulta e o regresso das fichas relacionadas; resultados relacionados anteriores ficam ocultos durante carregamento ou erro. - -Provas dirigidas: três testes Feature/93 asserções em QA descartável, incluindo o exemplo do proprietário, variantes de cultivo, acentos, palavras em campos distintos, província/distrito, duas APIs, página, mapa, exportação, fonte privada/futura/eliminada, curingas literais e separação entre cultivo e transformação. Mais seis testes de compatibilidade existentes/112 asserções passaram na QA com as referências já preparadas; dados protegidos permaneceram intactos. Cinco testes frontend passaram, cobrindo barra/autofill/destino nativo, apresentação dos relacionados e transporte/paginação existentes. PHPStan, tipos, formatação e lint sem avisos aprovados. Logs `quick-opportunity-search-*20261102.log` em `storage/logs`; recibo final e hashes em `quick_opportunity_search_increment_20261102` de `local-validation-20261029.json`. - -Âmbito local: testes com fichas sintéticas, sem alteração de cadastros ou publicações no activo, sem instalação remota e sem nova prova visual. O incremento não declara existir uma oportunidade real de plantio quando a fonte não a fornece. A integração dos alertas de concursos estava em desenvolvimento quando este pedido recebeu prioridade; o incremento anterior de alertas de oportunidades conserva a sua prova própria e o alargamento a concursos ainda não é declarado concluído. - -Compilação final deste recorte de pesquisa aprovada (`quick-opportunity-search-build-20261102.log`), com os avisos de fontes/chunks já conhecidos. Resultado final: nove testes Feature/205 asserções e cinco frontend aprovados, PHPStan/tipos/lint/formatação aprovados; recibo `quick_opportunity_search_increment_20261102` emitido com os hashes das dez fontes directamente alteradas. O exemplo «plantio de algodao» foi conferido novamente na fonte final. Sem instalação no activo nem declaração de nova oportunidade real por inferência. - -### 02/11/2026 — ACT-11: alertas de concursos integrados nas preferências existentes - -Retomado o incremento interrompido pela correcção da pesquisa rápida. A pendência de concursos do recorte anterior passa a ter implementação local demonstrada: em `/investidor/notifications`, a pessoa escolhe oportunidades, concursos ou ambos, com confirmação explícita. Preferências anteriores continuam exclusivamente em oportunidades; a migração não acrescenta subscrições. Sector e província são comuns; modalidade de oportunidade só se aplica a oportunidades e regime só a concursos. O servidor remove os filtros sem aplicação e valida a fonte escolhida. Cancelar conserva as notificações e não depende da disponibilidade do catálogo ou das opções antigas. - -`Procurement::publicQuery` concentra a consulta pública já utilizada pelo catálogo, agora partilhada com o gerador. Mantém filtros, hierarquia territorial, configuração de disponibilidade e a ligação à versão publicada; rascunhos e alterações ainda não publicadas ficam fora dos alertas. O gerador considera o acto actualmente publicado de cada concurso, não promete entregar todos os actos intermédios que possam ser substituídos entre verificações. A activação, reactivação ou alteração de fontes/critérios estabelece como ponto de partida as versões actualmente públicas, sem avisos retroactivos. Cada conta/versão de acto tem uma identidade de entrega única. Não cria acompanhamentos em `portal_tender_watches`, propostas, candidaturas ou decisões. - -O aviso conserva concurso, versão/acto, referência, origem, data de publicação e versão/critérios da preferência. Usa uma projecção fixa do conteúdo público, sem notas internas, contactos não autorizados, rascunhos ou anexos. A consulta distingue data de publicação e recepção do aviso, liga ao concurso e pede a leitura das condições actuais. Actos anteriores continuam legíveis enquanto o concurso tem publicação pública, sem substituir os respectivos avisos por dados da versão nova. Retirada da publicação ou indisponibilidade do módulo oculta os avisos afectados e impede a leitura pela rota de marcação; o histórico permanece guardado. Indisponibilidade de concursos não suspende as oportunidades seleccionadas. - -Mantidos canal no portal, frequência escolhida, autorização da própria conta e motor transaccional existentes. Cada catálogo tem um lote limitado a 200 correspondências por execução; ambos recebem processamento no mesmo ciclo, evitando que uma fila de oportunidades impeça concursos. Restantes itens continuam pendentes, sem avanço silencioso. Falha da entrega de concursos reverte também as entregas/marcadores de oportunidades desse ciclo da pessoa e permite repetir sem duplicações. O comando e agendador existentes continuam a ser usados, sem segundo serviço de notificações. - -Migração adicional `2026_11_02_200000_investment_tender_alerts.php`: fontes seleccionadas, origem alternativa da notificação e marcador por versão de concurso. Preserva o conteúdo, versão, consentimento, identificador e fontes anteriores; a origem de cada notificação continua exactamente uma. Reversão recusa eliminar preferências de concursos ou histórico. A sequência de actualização/reversão das duas migrações foi conferida com preferências e notificações anteriores não vazias, sem converter o ensaio sintético em aceitação real. - -Provas finais: **21 testes conjuntos/315 asserções**, **um teste de processamento de lotes/sete asserções** e **oito testes de compatibilidade do módulo de concursos/285 asserções**, todos aprovados: 30 testes distintos/607 asserções. O teste de lotes usa 201 oportunidades e um concurso, confirma entrega de concurso no primeiro ciclo e conservação da oportunidade restante. Seis testes frontend (quatro de alertas e dois da pesquisa rápida), PHPStan, tipos, lint sem avisos, Pint e compilação aprovados. Logs `tender-alerts-verified-feature-20261102.log`, `tender-alerts-batch-fairness-20261102.log`, `tender-alerts-procurement-compatibility-20261102.log`, `tender-alerts-frontend-20261102.log`, `tender-alerts-verified-phpstan-20261102.log`, `tender-alerts-final-types-20261102.log`, `tender-alerts-final-check-20261102.log` e `tender-alerts-build-20261102.log`, em `storage/logs`. Recibo/hashes em `tender_alerts_increment_20261102` de `local-validation-20261029.json`. - -ACT-11 permanece parcial: incentivos de outros catálogos e canais externos não implementados neste incremento. Disponibilização, activação do agendador no destino e conferência visual permanecem pendentes. Somente código local e ensaios sintéticos em bases isoladas na porta 55441; sem instalação, dados reais, mensagens externas, novas competências ou alteração da configuração activa. As provas anteriores de pesquisa, oportunidades e concursos mantêm o seu âmbito; o saldo de concursos do recorte anterior foi actualizado, sem apagar o histórico. - -### 02/11/2026 — AUD-FUND-01: núcleo do catálogo de fundos em desenvolvimento - -Criados serviço FundingProgrammes e migração 2026_11_02_210000_funding_programme_catalogue.php, ainda sem instalação no activo. Rascunho separado de versões publicadas imutáveis, prévia vinculada por hash, controlo de concorrência, publicação idempotente, retirada auditada e interesses privados por pessoa/programa, conservando a versão guardada. Usa a competência editorial existente; não atribui competência para concessão de financiamento. Critérios distinguem correspondência, divergência, informação desconhecida e não aplicabilidade, sem excluir automaticamente ou enviar candidatura. Janelas históricas encerradas não representam encerramento do próprio fundo. Cobertura territorial e sectores rejeitam combinações incoerentes. - -Documentos são incorporados por identificador, versão e checksum. A resolução de descarga confere novamente publicação, direitos e segurança na biblioteca e reutiliza VerifiedDocumentBinary; a substituição do documento não altera silenciosamente o binário citado. Este percurso ainda precisa de testes específicos de descarga e ligação HTTP. - -Prova local sintética em PostgreSQL isolado: FundingProgrammesTest, dois testes/dez asserções aprovados (storage/logs/funding-programmes-feature-20261102.log). Cobrem publicação repetida sem duplicação, rascunho sem alteração da versão pública, nova versão sem reescrever interesse anterior, remoção limitada à própria pessoa, janela histórica, aplicabilidade desconhecida e bloqueio de publicação de conteúdo explicitamente demonstrativo. PHPStan sem erros (funding-programmes-phpstan-20261102.log), Pint e git diff --check aprovados. Não constituem prova de todo o catálogo. - -AUD-FUND-01 continua incompleto: faltam controladores/rotas, catálogo e editor pela interface, filtros, testes de autorização/conflitos/documentos e validação visual. Referências reais FDEL ainda não incorporadas nem publicadas; não inferir janela aberta ou condições financeiras de páginas demonstrativas. Próxima acção: completar o percurso público/editorial e as provas, mantendo ACT-12 e alertas de incentivos pendentes até integração efectiva. - -### 02/11/2026 — AUD-FUND-01: primeiro percurso HTTP público - -Ligadas rotas /fundos, ficha por UUID, conferência de critérios, guardar/remover interesse autenticado e descarga por programa/versão/recurso. Controlador FundingProgrammeController e páginas funding/index/show reutilizam a estrutura visual e o transporte CSRF existentes. Consulta publicada paginada, palavras-chave e tipo de apoio; critérios por tipo de candidato e janela seleccionada, respostas não persistidas, explicação e fonte por critério. A ficha distingue janela encerrada de programa, mostra datas e canal externo documentados, disponibilidade dos documentos e versão privada guardada, incluindo indicação de publicação posterior. Respostas HTTP com estado pessoal ou resultados de conferência usam private/no-store. Não existe envio externo ou candidatura automática. - -Provas incrementais: FundingProgrammesTest com dois testes/25 asserções aprovados, incluindo rotas públicas, pesquisa sem resultado, exigência de autenticação para guardar e divergência de critério. PHPStan do serviço/controlador e types:check aprovados. Logs funding-programmes-http-20261102.log, funding-programmes-http-phpstan-20261102.log e funding-programmes-types-20261102.log. A compilação e lint são registados separadamente após conclusão; não deduzir aprovação do arranque. - -Continua em desenvolvimento: editor editorial, lista dos interesses, navegação, filtros territoriais/sectoriais explicados e respectivos testes, testes de descarga/versionamento/conflitos, referências reais FDEL e validação visual. Nada publicado ou migrado no activo. Este incremento não encerra AUD-FUND-01, ACT-12 ou a auditoria geral. - -### 02/11/2026 — AUD-FUND-01: lista privada e navegação - -Implementada /fundos/guardados, autenticada e verificada, paginada e limitada no servidor à pessoa da sessão. Lista conserva título e versão efectivamente guardados, sem projectar rascunho ou substituir a referência pela publicação nova. Após retirada pública conserva apenas a referência privada mínima, informa indisponibilidade e permite remoção. Não expõe corpo/documentos da publicação retirada. Guardar continua distinto de candidatura ou contacto externo. Links no catálogo/ficha e navegação; menu público depende da instalação das tabelas, link da lista privada depende também de autenticação. - -FundingProgrammesTest: dois testes/71 asserções aprovados, incluindo isolamento entre contas, versão preservada, indisponibilidade pública após retirada e remoção pela própria conta. PHPStan serviço/controlador sem erros, log funding-programmes-saved-phpstan-20261102.log; testes HTTP em funding-programmes-saved-20261102.log. A compilação iniciada no incremento anterior terminou com código zero (funding-programmes-build-20261102.log); não comprova automaticamente os ficheiros posteriores desta lista. Verificações frontend finais deste incremento registadas nos logs funding-navigation-20261102.log e funding-programmes-saved-*. Mantêm-se pendentes editor, filtros geográficos/sectoriais, testes de documentos/conflitos/permissões e validação visual; sem instalação no activo. - -### 02/11/2026 — AUD-FUND-01: edição editorial ligada ao catálogo - -Implementadas gestão paginada, criação/edição de rascunhos, prévia, publicação e retirada em /management/fundos. Reutiliza DocumentManagementAccess::catalogueEditor no servidor em cada operação; não atribui competência financeira nem depende da activação de concursos. Referências limitadas a cadastros e documentos autorizados/públicos; formulário reutiliza entidade gestora, sectores, territórios e biblioteca, com critérios comuns e critérios por janela, fonte/edição/data, âmbito e datas aplicáveis. Mudança para janela desconhecida/contínua limpa datas inaplicáveis. Publicação exige rascunho guardado, prévia conferida, confirmação expressa, motivo e hash válido; efeitos sobre versões e interesses explicados. Histórico de publicação disponível no editor. Link de gestão no catálogo só para competência efectiva. - -Publicações recebem sequência própria crescente quando a prévia muda por actualização autorizada do cadastro, mesmo sem alteração do rascunho; snapshots anteriores não são reescritos. O hash da prévia inclui os dados efectivamente reutilizados. Controlo de versão do rascunho continua independente e obrigatório. - -Prova: FundingProgrammesTest passou quatro testes/91 asserções (funding-editor-feature-20261102.log), incluindo formulários/gestão, editor sem módulo de concursos, recusa de conta sem autoridade, hash incorrecto, gravação obsoleta e nova publicação com alteração do nome no cadastro sem colisão ou reescrita histórica. Tipos aprovados (funding-editor-final-types-20261102.log); verificação estática final, lint após correcção de um aviso de tipagem e compilação ainda em acompanhamento. A compilação anterior da lista privada terminou com código zero; não comprova automaticamente este editor. - -Ainda pendentes: filtros territoriais/sectoriais com tratamento explícito de desconhecidos, ensaios completos de documentos/versões/concorrência e visual, referências FDEL reais e integração de incentivos nos alertas. Editor implementado localmente não encerra AUD-FUND-01 ou ACT-12. Sem migração, publicação ou alteração de contas no activo. - -Fecho das verificações do editor em 02/11/2026: PHPStan sem erros, lint/formatação sem avisos e compilação terminaram aprovados (funding-editor-final-phpstan-20261102.log, funding-editor-final-check-20261102.log e funding-editor-build-20261102.log). Tipos aprovados no processo final 44973. Matriz AUD-FUND-01 reconciliada como parcial, preservando histórico; recibo funding_editor_increment_20261102 com hashes das fontes/prova, sem declaração de cobertura integral. Próxima acção: filtros territoriais/sectoriais e testes específicos de documentos/versionamento. - -### 02/11/2026 — AUD-FUND-01: filtros territoriais e sectoriais - -Catálogo público passou a filtrar por sector, local, situação de uma janela e inclusão explícita de âmbitos desconhecidos. Cobertura nacional abrange os locais; cobertura provincial permite pesquisar os seus distritos; um programa restrito a distrito aparece como cobertura parcial quando se pesquisa a província. Origem por confirmar é assinalada e pode ser excluída pela opção «apenas âmbito documentado». Não transforma ausência de informação em correspondência confirmada nem concessão de elegibilidade. - -O filtro territorial/sectorial refere-se ao programa, não a todas as chamadas. O texto da interface explica a distinção e o filtro de estado significa pelo menos uma janela nesse estado, sem confirmar abertura no local escolhido. Janelas fechadas, futuras, com data-limite no próprio dia e sem data confirmada são tratadas separadamente; programas sem janelas entram apenas no estado por confirmar. Fontes territoriais/sectoriais utilizadas são preservadas por versão, incluindo nomes e caminhos hierárquicos, sem reescrever snapshots quando o cadastro muda. A ficha mostra os locais e sectores efectivamente incorporados, também nas janelas locais. - -Prova inicial: cinco testes/184 asserções aprovados em funding-filters-feature-20261102.log, abrangendo os quatro testes anteriores e as combinações dos filtros; PHPStan, tipos e lint sem avisos aprovados (funding-filters-phpstan-20261102.log, funding-filters-types-20261102.log, funding-filters-check-20261102.log). Teste adicional de documentos em acompanhamento; primeira execução corrigida por campo obrigatório ausente na fixture sintética, sem mudança de regra do produto. Compilação em acompanhamento. Sem escrita no activo. - -Fecho do incremento de filtros/documentos, 02/11/2026: **seis testes/204 asserções aprovados**, incluindo o teste específico de descargas (funding-filters-documents-feature-20261102.log). Binário alterado sem nova análise, metadados de análise pendente/checksum divergente, direitos restritos, classificação privada, recurso retirado e versão substituída recusados; prévia anterior à mudança do documento rejeitada, publicação nova distinta e snapshot anterior conservado. Estes estados são fixtures sintéticas, não prova de execução de antivírus real. PHPStan, tipos, lint sem avisos/formatação e compilação aprovados; processos terminais conferidos, logs funding-filters-*. Recibo funding_filters_increment_20261102 com hashes, matriz AUD-FUND-01 reconciliada sem apagar provas anteriores. Ainda não demonstra concorrência com trabalhadores simultâneos, fontes reais incorporadas, visual ou instalação no destino. Próxima acção: preparar as referências oficiais FDEL já identificadas, distinguindo programa de chamada histórica, e completar os ensaios restantes; incentivos nos alertas continuam pendentes. - -### 02/11/2026 — AUD-FUND-01: referência oficial FDEL preparada pela interface - -Incluído pacote instalável database/data/funding-references.json e serviço FundingProgrammeReferences, com edição, URLs, referências, datas efectivas de consulta e hashes dos exemplares. Usa o Decreto 4/2025 (BR I/43, 05/03/2025) e aviso municipal CMCT com prazo 20/10/2025. Um programa com chamada histórica associada; não cria duas fichas, não transforma o aviso numa chamada actual e não atribui o município a toda a província. Vínculo cartográfico municipal e associação ao cadastro sectorial permanecem explícitos por completar. Não foram transportadas taxas ou montantes para motores financeiros/fiscais; critérios são um extracto informativo com acesso às fontes completas. - -Percurso /management/fundos/referencias/fdel: prévia legível das condições/fontes, seguida de preparação de rascunho pela competência editorial existente. Hash vincula o pacote exibido; referência alterada exige nova prévia. Código estável e bloqueio transaccional reutilizam ficha existente sem sobrescrever edições ou acrescentar chamadas. Preparação auditada conserva edição, hash do pacote e hashes das fontes; publicação continua separada no editor existente. Não há consulta remota obrigatória no cliente, novas contas, destinatários ou envio de candidatura. - -Exemplares recolhidos e conferidos em storage/app/private/funding-sources-20261102 (manifest.json); PDF e HTML com SHA-256 correspondente ao pacote. São cópias privadas de desenvolvimento, sem afirmação de antivírus executado e sem publicação automática na biblioteca. A página municipal falhou no leitor web mas a recolha HTTP directa devolveu o conteúdo esperado (título, prazo e requisitos); não confundir falha de ferramenta com indisponibilidade da fonte. - -Prova: FundingProgrammesTest passou sete testes/235 asserções (funding-references-feature-20261102.log), incluindo preparação sem publicação, recusa de hash errado, chamada histórica fechada, referência cartográfica desconhecida, proveniência auditada, repetição sem duplicação/substituição e conta sem competência recusada. PHPStan e lint/formatação sem avisos aprovados; tipos e compilação ainda em acompanhamento nos respectivos processos. Continuidade: verificar os resultados terminais, manter concorrência e visual pendentes, completar a correspondência territorial/sectorial pelas fontes autorizadas e integrar os incentivos nos alertas. Sem alteração no activo. - -Fecho das verificações das referências em 02/11/2026: sete testes/235 asserções, PHPStan, tipos, lint sem avisos/formatação e compilação aprovados, com processos terminais conferidos. Logs funding-references-*; recibo funding_references_increment_20261102 inclui hashes e manifesto de origem. AUD-FUND-01 continua parcial, com concorrência, visual, vínculos ao cadastro, alertas e disponibilização ainda pendentes. Próxima acção: ensaiar concorrência/repetição em base descartável e completar os restantes percursos, sem alterar o activo. - -### 02/11/2026 — AUD-FUND-01: concorrência real e impasse corrigido - -Criado tools/verify-funding-concurrency.php, exclusivamente CLI, com ambiente testing, PostgreSQL em 127.0.0.1:55441 e nome ancorado funding_concurrency_20261102[a-z]?_test. Confere ligação efectiva, recusa configuração em cache, obtém a guarda de execução QA e exige base sem pessoas/fichas antes de criar cenário. Não repõe, apaga ou redefine registos existentes; contexto de cada trabalhador fica privado e vinculado à mesma base e identidade sintética. Recusa sem ambiente explícito e recusa de repetição numa base não vazia foram verificadas. Migrações apenas em três bases novas descartáveis, mantendo os resultados anteriores. - -Cinco cenários, cada um com dois processos PHP e sessões PostgreSQL independentes: preparação da mesma referência, gravação com a mesma versão, publicação da mesma prévia, guardar interesse da mesma pessoa e retirada contra interesse da mesma pessoa. O controlador de ensaio mantém um bloqueio até observar ambos os processos à espera no PostgreSQL; só depois liberta. A primeira tentativa do verificador falhou por reter o snapshot estatístico na transacção de observação; foi corrigida com pg_stat_clear_snapshot, preservando o log inicial em vez de declarar falha do produto. - -Com a observação corrigida, reproduzido **SQLSTATE 40P01** no quinto cenário: interesse conservava bloqueio FOR UPDATE na conta enquanto esperava pela ficha, e retirada conservava a ficha enquanto a inserção de auditoria precisava de KEY SHARE na conta. A correcção técnica usa **FOR NO KEY UPDATE** para serializar interesses/remover interesse pela pessoa, permitindo a referência de auditoria, sem mudar competências, decisões ou chaves da conta. A base de reprodução e o log de falha permanecem preservados. - -Após a correcção, os cinco cenários passaram em funding_concurrency_20261102c_test: uma referência, uma versão publicada, um interesse e uma auditoria por preparação/publicação/interesse/retirada. A gravação concorrente recusou uma versão obsoleta; retirada concluiu e o interesse concorrente recebeu indisponibilidade, preservando a referência anterior. Consulta final confirma uma referência privada válida e nenhuma publicação activa. São pares de processos com sobreposição observada, não prova de carga nem de todas as intercalações possíveis. - -Provas: funding-concurrency-before-20261102.log (verificador inicial), funding-concurrency-baseline-20261102.log (impasse do produto), funding-concurrency-after-20261102.log (cinco cenários aprovados), funding-concurrency-preservation-20261102.json, e logs guard-environment/guard-existing. Sete Feature/235 asserções de compatibilidade aprovados (funding-concurrency-feature-20261102.log), PHPStan sem erros e Pint/sintaxe/diff aprovados. Frontend não alterado; conservadas provas de tipos/lint/compilação do incremento anterior. Matriz e recibo funding_concurrency_increment_20261102 reconciliados. Sem alterações no activo. Próxima acção: integração dos fundos/incentivos nos alertas existentes; vínculos de referência, visual e disponibilização continuam pendentes. - -### 02/11/2026 — ACT-11 / AUD-FUND-01: alertas de fundos, programas e incentivos publicados - -Integrado o catálogo de fundos no motor existente InvestmentOpportunityAlerts, nas preferências/notificações existentes e no mesmo comando/agendador. Nova migração 2026_11_02_220000_investment_funding_alerts.php acrescenta origem por versão pública e marcador único por pessoa/versão; preserva as fontes, critérios cifrados e notificações anteriores. Nenhuma conta é inscrita automaticamente. Alterar/activar fontes ou critérios toma os IDs públicos existentes como ponto inicial, sem avisos retroactivos; rascunhos e versões intermédias já substituídas não são tratados como novas publicações disponíveis. - -Escolha explícita de fundos/apoios, âmbito documentado ou inclusão assinalada de desconhecidos, e estado de uma janela. Reutiliza os filtros do catálogo, com sector/local do programa distintos da cobertura de cada chamada. O aviso não garante elegibilidade ou candidatura aberta e não é candidatura enviada. Regista versão, fonte/referência/data de consulta, data de publicação, preferências aplicadas, explicação do âmbito e estados de janela na data do aviso; não copia respostas, documentos ou rascunhos. Link vai à ficha pública e preserva a fonte da edição notificada. Alteração das datas sem nova versão publicada não gera segundo aviso. - -Leitura e marcação conferem a própria conta, disponibilidade do catálogo e publicação actual da ficha. Avisos de versões públicas anteriores conservam o conteúdo original enquanto a ficha tem publicação pública; retirada oculta avisos e impede leitura sem apagar dados. Indisponibilidade de fundos não impede as outras fontes ou o cancelamento. Lote máximo de 200 por fonte/ciclo; fila restante mantém execução devida e não impede a outra fonte. Falha na entrega de fundos reverte também os avisos/marcadores das outras fontes daquela pessoa nesse ciclo. Bloqueio da conta nas preferências usa NO KEY UPDATE, preservando serialização e compatibilidade com referências de auditoria/notificações; concorrência específica do gerador ainda precisa de ensaio com processos. - -Provas finais de servidor: **36 testes/612 asserções aprovados** (funding-alerts-verified-feature-20261102.log): sete novos testes de fundos e compatibilidade com alertas de oportunidades/concursos, catálogo e manifestações. Cobrem escolha das três fontes, ausência de inscrição automática, ponto inicial, âmbitos desconhecidos, datas, versões/retirada, propriedade dos avisos, fonte indisponível, cancelamento, lote com 201 fundos e uma oportunidade, reversão de entregas e migração/reversão com dados anteriores preservados. Seis testes frontend aprovados, incluindo selecção voluntária, campos aplicáveis, fonte e ligação/estado histórico do aviso (funding-alerts-verified-frontend-20261102.log). PHPStan e lint/formatação sem avisos aprovados; tipos e compilação finais em acompanhamento. Reutilizadas as provas anteriores de concorrência do catálogo; não as confundir com concorrência do gerador. - -Sem instalação, activação de preferências, envio externo ou alteração no activo. ACT-11 continua parcial para canais externos/outras fontes e disponibilização/agendador no destino; fundos/incentivos aqui significa exclusivamente versões publicadas no catálogo do portal. Visual, vínculos de referência e restantes requisitos agregados continuam pendentes. - -Fecho das verificações do incremento de alertas de fundos, 02/11/2026: 36 testes/612 asserções e seis frontend, PHPStan, tipos, lint sem avisos/formatação e compilação aprovados, com processos terminais conferidos. Logs finais funding-alerts-verified-*, funding-alerts-final-* e funding-alerts-build-20261102.log; recibo funding_alerts_increment_20261102 com hashes. Matriz AUD-FUND-01 e MASTER-471012ab-0124 reconciliadas como parciais, sem apagar provas históricas. Próxima acção: ensaiar concorrência do gerador e das preferências com processos, e rever perguntas aplicáveis no percurso de conferência de critérios. Sem alterações no activo. - -### 02/11/2026 — ACT-11 / AUD-FUND-01: concorrência do gerador e critérios aplicáveis - -Estendido tools/verify-funding-concurrency.php com quatro cenários de alertas, conservando os cinco anteriores. Execução em funding_concurrency_20261102d_test, base nova e descartável, com duas sessões por cenário e bloqueios efectivamente observados. Dois geradores concorrentes entregam um aviso; duas gravações idênticas das preferências conservam uma só revisão; cancelamento com precedência impede entrega; gerador com precedência conclui uma entrega antes do cancelamento efectivo e nenhuma depois. Reactivação usa a publicação existente como ponto inicial, sem aviso retroactivo. Nove cenários aprovados, sem novo impasse. Não equivale a ensaio de carga ou de todas as intercalações possíveis. - -Conferência final directa: uma ficha, quatro versões imutáveis, um interesse com referência válida, dois avisos e respectivos marcadores, preferências na versão cinco desactivadas. Auditoria com três gravações efectivas de preferências e dois cancelamentos, sem duplicação pelas repetições. Provas em funding-alert-concurrency-20261102.log e funding-alert-concurrency-preservation-20261102.json. Não houve mudança adicional de regras de negócio ou publicação no activo. - -No formulário público de conferência, perguntas específicas só aparecem depois de escolher pessoa singular/entidade, e perguntas de outro tipo não são apresentadas. Respostas locais ficam conservadas ao alternar tipo/janela, mas apenas respostas aplicáveis são enviadas. Campos de janela não aparecem quando não há janelas. Selecções/edições limpam resultado e erro anteriores; mudar ficha/versão reinicia a conferência, evitando transportar respostas/resultados para outra edição. Servidor e critérios imutáveis existentes mantêm a distinção desconhecido/não aplicável, sem concessão automática de elegibilidade. Extraída uma única implementação em funding-criteria-assessment.tsx, removendo a anterior da página. - -Oito testes frontend aprovados (dois novos de conferência e seis de alertas), logs funding-assessment-frontend-20261102.log. Tipos e lint/formatação sem avisos aprovados; compilação em acompanhamento. Sem alteração no PHP da aplicação neste incremento, reutilizadas as provas anteriores de 36 Feature/612 asserções e PHPStan; o script CLI foi formatado e executado nos nove cenários. Visual, vínculos sectorial/cartográfico da referência e disponibilização/agendador no destino continuam pendentes; canais externos permanecem fora da integração demonstrada. - -Fecho do incremento em 02/11/2026: nove cenários concorrentes e oito frontend aprovados; tipos, lint sem avisos/formatação e compilação terminaram aprovados. Verificados hashes actuais do PHP da aplicação contra a prova anterior antes de reutilizar os 36 Feature/612 asserções. Matriz reconciliada e recibo funding_assessment_concurrency_increment_20261102 com fontes, logs e limites. Nenhum processo de validação ficou pendente. Mantêm-se visual, vínculos de referência e disponibilização; o objectivo global de auditoria continua activo. Próxima acção: voltar à matriz consolidada para seleccionar a próxima lacuna funcional autorizada e verificar os vínculos já existentes antes de acrescentar novos dados. - -### 02/11/2026 — AUD-EDU-01: rascunhos privados das declarações de Educação - -Reconciliados matriz, código e provas: procura de trabalhadores/capacidade formativa já têm submissão, revisão independente e análise; faltava guardar informação incompleta. Implementado o núcleo de rascunhos, ainda sem ligação à interface. Migração 2026_11_02_230000_education_declaration_drafts.php: origem por pessoa/tipo, chave de repetição, versão, dados cifrados, estado e referências com FK para uma única declaração submetida. Reversão recusa eliminar rascunhos/história. Guardas reutilizam activação de Educação e administração efectiva existentes; nenhuma competência ou acreditação nova. - -API sob /management/education/drafts/{demands|capacities}: listar apenas os próprios, criar, recuperar, editar com versão e submeter. Respostas privadas/no-store. Permite informação incompleta e quantidade zero apenas em rascunho; não entra nas tabelas/indicadores de trabalhadores ou vagas antes da submissão válida. Dados de outro destino são excluídos; campos de decisão, revisão ou não declarados são recusados. Repetição da mesma chave/payload não cria outra ficha/revisão; comparação estrita preserva diferenças deliberadas em texto numérico. - -Extraídas as regras já existentes para EducationDeclarationRules, partilhadas pela submissão directa e pelo rascunho. Ao submeter: mesma validação de referências, datas, quantidade e fonte; criação de uma única declaração com estado submitted e autor, mantendo a revisão por outro gestor. Transacção conserva corpo e snapshot cifrado dos cadastros efectivamente utilizados; alteração futura do nome de projecto não reescreve o snapshot. Rascunho submetido não é editado ou ressubmetido com dados diferentes. Histórico de rascunho/auditoria não expõe texto livre ou empregador em claro no evento. - -Provas: **14 testes/291 asserções aprovados**, cinco novos de rascunho e nove existentes de Educação (education-drafts-verified-feature-20261102.log). Cobrem recuperação pela própria conta em novo contexto, isolamento entre gestores, cifragem, repetição, versão obsoleta, tipo distinto, dados incompletos, exclusão de campos não aplicáveis, validação de curso retirado, submissão única, revisão própria recusada, snapshot conservado e guarda de reversão. PHPStan sem erros e Pint/sintaxe/diff aprovados (education-drafts-verified-phpstan-20261102.log). Ensaios só em PostgreSQL isolado 127.0.0.1:55441 *_test; não migrado no activo. - -Saldo explícito: faltam interface para guardar/abrir/continuar rascunhos, apresentação da submissão/snapshot, painéis e restantes perfis previstos no requisito, testes de concorrência e visual. Não declarar AUD-EDU-01 concluído pela disponibilidade da API. Próxima acção: ligar os controlos ao formulário existente, conservando edições e regras, e validar o percurso recuperável pela interface. - -Fecho das provas do núcleo de rascunhos em 02/11/2026: 14 testes/291 asserções e PHPStan aprovados, processos terminais conferidos. Pint/sintaxe/diff passaram. Matriz AUD-EDU-01 actualizada e recibo education_drafts_increment_20261102 com hashes. Interface continua por ligar e não foi declarada concluída. Próxima acção mantém-se no formulário existente; não criar outro roteiro ou alargar competências por conveniência técnica. - -### 02/11/2026 — AUD-EDU-01: rascunhos ligados aos formulários existentes - -Interface de procura de trabalhadores/capacidade formativa ligada ao núcleo anterior. Botão de guardar é independente da validação HTML obrigatória da submissão; conserva dados incompletos sem criar declaração. Resposta guardada actualiza identidade/versão local sem navegar ou apagar o outro formulário. Submissão de rascunho usa o seu ID/versão e os campos actuais, preservando validação e revisão existentes. Após sucesso, mostra os dados e cadastros históricos, sem outro formulário de envio, e actualiza declarações/indicadores por recarga parcial que conserva o estado dos formulários. - -Lista privada paginada na página de Educação, limitada no servidor ao actor, com tipo, qualificação, data, estado e versão. Reabre por /management/education?draft=UUID; mantém campos em falta vazios, quantidade como declarada e caminho territorial recuperado. Referência fora da lista não é eliminada; local retirado é explicado para reconciliação antes de submeter. Submissões derivadas do rascunho mostram o snapshot preservado, incluindo nome de projecto/curso e local utilizados, separado do estado de revisão actual. A lista não pretende reunir todas as declarações antigas feitas pelo percurso directo. - -Conflito de versão mantém as edições locais e orienta recuperação da versão guardada. Navegação que descartaria estado e fecho da página têm protecção para alterações não guardadas; recarga parcial de indicadores não substitui os campos. Campos ficam desactivados durante a gravação. Respostas HTTP privadas/no-store e histórico Inertia cifrado; lista projecta apenas metadados próprios, sem corpo integral dos rascunhos. Datas devolvidas em ISO para consumo consistente pelos navegadores. Quando a migração não existe, os controlos de rascunho não aparecem e o percurso directo anterior mantém-se. - -Provas finais: **14 testes/333 asserções** aprovados (education-drafts-ui-verified-feature-20261102.log), incluindo os nove testes anteriores de Educação, recuperação autenticada sintética, rejeição de rascunho de outro gestor pela página, lista privada e snapshot de submissão. **Cinco frontend** aprovados (education-drafts-ui-verified-frontend-20261102.log): página completa/lista e ambos os formulários, gravação incompleta/continuidade/submissão pela mesma identidade, conflito sem sobrescrever edições, caminho territorial estável e snapshot sem novo envio. A verificação de tipos apanhou uma mensagem de recuperação fora do formulário; corrigida e acrescentado ensaio da página completa. PHPStan, tipos, lint/formatação sem avisos, Pint e compilação aprovados, com processos terminais conferidos. - -Verificações técnicas não substituem observação visual ou login real; não foram declarados aceites. Restam concorrência deste percurso, visual, painéis dos restantes perfis e disponibilização. Sem migração na base activa. Próxima acção: ensaiar gravação/submissão concorrente em base descartável e conferir o saldo dos restantes actores sem criar competências ou acreditações por inferência. - -Fecho da ligação à interface em 02/11/2026: 14 testes/333 asserções, cinco frontend, PHPStan, tipos, lint sem avisos/formatação, Pint e compilação aprovados; processos terminais conferidos. Matriz AUD-EDU-01 e recibo education_drafts_ui_increment_20261102 actualizados com hashes. Reutilizada a limpeza de histórico existente no LogoutResponse (AppServiceProvider), sem novo mecanismo de autenticação. Interface implementada localmente não equivale a aceitação visual ou por contas reais. Próxima acção: concorrência de gravação/submissão em base descartável, preservando as provas actuais e os rascunhos/submissões existentes. - -### 02/11/2026 — AUD-EDU-01: concorrência real dos rascunhos e submissões - -Criado tools/verify-education-draft-concurrency.php, exclusivamente CLI e limitado a testing/PostgreSQL 127.0.0.1:55441, nome ancorado education_draft_concurrency_20261102[a-z]?_test, URL de ligação vazia e identidade/base efectivas conferidas. Reutiliza a guarda de execução QA; exige base sem pessoas, rascunhos ou declarações antes de criar cenário sintético. Recusa de ambiente não explícito e de repetição numa base já não vazia verificadas, sem reset ou remoção de registos. Base usada: education_draft_concurrency_20261102_test, mantida com as provas. - -Dez cenários, cinco por tipo (procura de trabalhadores/capacidade formativa), com dois processos PHP e sessões PostgreSQL independentes. O processo de controlo mantém o bloqueio até observar ambos os trabalhadores à espera no PostgreSQL; limpa o snapshot de estatísticas entre observações. Casos: mesma chave de criação, edições diferentes com a mesma versão, repetição da submissão, gravação com precedência sobre submissão e submissão com precedência sobre gravação. Todos passaram. A gravação vencedora fica conservada e a submissão obsoleta recebe conflito; no inverso, a declaração/snapshot submetidos ficam imutáveis e a edição é recusada. - -Conferência final directa: seis rascunhos (dois abertos e quatro submetidos), duas declarações de procura e duas de capacidade, quatro snapshots e quatro vínculos válidos ao respectivo autor. Auditoria com dez gravações efectivas de rascunho e quatro submissões. Repetições não duplicaram rascunho, revisão ou declaração; todas as quatro declarações continuam submitted, sem reviewed_by, mantendo a revisão independente. As linhas pertencem a casos técnicos distintos, não a procura ou capacidade reais. - -Provas em education-draft-concurrency-20261102.log e education-draft-concurrency-preservation-20261102.json, com guardas em logs guard-environment/guard-existing. Script executado/formatado e sintaxe/diff aprovados. Não houve delta no PHP/JS da aplicação; provas anteriores de 14 testes/333 asserções, cinco frontend e verificações estáticas/compilação são reutilizadas após conferir hashes. São pares de processos nos casos delimitados, não ensaio de carga nem de todas as intercalações possíveis. Visual, painéis/perfis restantes e disponibilização continuam pendentes; não alterar o estado agregado para concluído. - -Próxima acção: retomar o saldo da matriz e confrontar os restantes consumidores/perfis com o código e permissões existentes, avançando nas lacunas independentes sem inventar papéis ou decisões institucionais. Nenhuma migração, conta ou dado foi alterado na base activa. - -Fecho da concorrência de Educação, 02/11/2026: dez cenários aprovados e conferência de dados/auditoria concluída. Aplicação sem alterações neste incremento; hashes conferidos contra a prova anterior de 14 testes/333 asserções, cinco frontend e verificações estáticas/compilação. Matriz e recibo education_drafts_concurrency_increment_20261102 actualizados. Guardas de ambiente/base não vazia recusaram execução sem apagar dados. Nenhum processo pendente. Próxima acção: seleccionar o próximo saldo funcional autorizado na matriz, mantendo visual e restantes perfis/painéis como pendências concretas, sem declarar a auditoria global concluída. - - -### 02/11/2026 — AUD-MARKET-01: pesquisa de negócios por raio, sector e classificação - -Reutilizados o UUID/catálogo público de negócios, classificação divulgada e cartografia existentes. O detalhe oferece comparação por raio quando a ficha tem ponto primário marcado público e precisão exacta. A consulta aceita referência pública por UUID e raio de 0,1 a 2000 km (limite técnico da consulta interactiva, sem nova regra organizacional). O selector de similares oferece distâncias usuais; no catálogo é possível indicar qualquer valor dentro desse intervalo. Retirar o raio recupera o filtro de área; no comparador o raio substitui a área, conservando modalidade, sector e classificação. No catálogo a área adicional restringe também os resultados. Paginação, abertura da ficha, regresso e manifestação de interesse conservam os filtros efectivamente aplicados. Editar a próxima pesquisa não altera o contexto das fichas já apresentadas. - -BusinessProximitySearch usa PostGIS/geography (distância geodésica em linha recta, sem itinerário rodoviário). Só utiliza geometrias Point válidas/não vazias/4326 com longitude/latitude nos limites e sinalização pública exacta; não transforma polígonos em centróides, não geocodifica nomes e não usa pontos privados/secundários ou fichas expiradas, futuras, eliminadas ou não publicadas. Referência sem ponto utilizável é recusada explicitamente, sem alargar a pesquisa silenciosamente. A API projecta distância arredondada e data de registo, nunca geometria/EWKT/coordenadas, payload ou titular privado. - -PublicBusinessLocations centraliza divulgação e precisão: um distrito guardado numa localização com precisão apenas provincial deixa de permitir inferir esse distrito por filtro. Referências retiradas/privadas nos níveis divulgados não alimentam o ponto ou a projecção; campos mais finos não divulgados não apagam a província ainda pública. A lista explica a fonte interna, data de registo da localização, cobertura com/sem ponto utilizável antes do raio e limites. Cobertura considera os restantes filtros e pode incluir a própria referência; o painel de similares retira a própria ficha dos seis resultados. Registo/publicação não são datas comprovadas dos dados de origem, nem verificação da localização real. - -Provas finais: 11 Feature/384 asserções em business-proximity-final-feature-20261102.log, incluindo os quatro cenários novos de proximidade, quatro anteriores do catálogo público e três da pesquisa rápida. Casos sintéticos com distância próxima/fora do raio, ordenação/paginação, sector/modalidade/classificação combinados, área combinada com raio, ponto privado/secundário, polígono, coordenada fora dos limites, referência sem cobertura, vigência/publicação e precisão territorial. Dez frontend aprovados: controlos e troca de referência, classificação/raio, recuperação de área, cobertura/datas/distância, respostas tardias ou malformadas, filtros aplicados versus edição e pesquisa rápida com preenchimento automático. PHPStan, tipos, lint/formatação sem avisos, Pint e compilação aprovados; logs/hashes no recibo business_proximity_increment_20261102. - -O exemplo do proprietário «plantio de algodao» foi revalidado: com/sem acentos e variantes de cultivo, sem apresentar transformação como plantio. Se só existem fichas de transformação, a pesquisa mostra-as separadamente como relacionadas e conserva os restantes filtros. Não foi inventada oportunidade para completar o resultado. - -Estado parcial: não há demonstração de cobertura real de pontos públicos exactos, alimentação desse cadastro pela gestão, visual no navegador ou disponibilização no destino. A localização existente não guarda citação/data própria da fonte; updated_at é identificado apenas como data de registo. Não foi criada outra origem, geometria ou correspondência territorial no activo; nenhum schema, pessoa ou dado activo foi alterado. Próxima acção: confrontar o percurso editorial de localizações com os cadastros/fontes autorizados e acrescentar rastreabilidade e edição reutilizando a mesma identidade, sem divulgação automática. Manter as demais lacunas da matriz activas. - - -### 02/11/2026 — AUD-MARKET-01: ponto preparado no formulário e publicado pelo roteiro existente - -Verificação inicial encontrou território, precisão e fontes no formulário, mas nenhum escritor de existing_business_locations. A alimentação foi ligada ao mesmo formulário/UUID, sem novo editor, rota, perfil ou ordem de aprovação. O suplemento é opcional: território específico/múltiplo, localização conhecida, precisão exacta e escolha explícita de preparar o ponto. Para vários caminhos, escolhe-se uma das localizações já declaradas; a primeira não é inferida. Reutiliza-se a fonte da etapa Fontes quando também sustenta o ponto, ou indica-se uma fonte diferente. Coordenadas WGS84 com limites, referência e data são conservadas no payload cifrado. Rascunho incompleto continua gravável; campos sem aplicação ficam reservados/preservados e não activam ponto. Asteriscos assinalam os campos necessários ao suplemento activo. - -Guardar/submeter/rever/aprovar não altera o cadastro geográfico público. ExistingBusinessIntake valida o candidato na submissão e novamente na publicação; o escritor só corre após as competências, versão e independência já exigidas, na mesma transacção com bloqueio do negócio. A publicação cria ou substitui o ponto primário, conserva o UUID existente e as localizações secundárias. Prévia privada distingue local já cadastrado e ponto proposto e explica o efeito da substituição. O journal cifrado preserva a geometria/fonte anterior, valores/fontes/nomes territoriais utilizados e a nova localização; alterações posteriores de nomes/cadastros não reescrevem esse histórico. Sem opt-in, o cadastro anterior é conservado. Anúncios já publicados conservam o seu percurso anterior de alteração; este incremento não lhes concede edição ou reabertura. - -Migração aditiva 2026_11_03_000000_existing_business_location_sources acrescenta referência pública opcional, data real da fonte, origem do adaptador e versão do payload usada. Não preenche dados históricos nem publica localizações. Rollback recusa perda de fontes preenchidas; sem as colunas, o catálogo mantém projecção nula da fonte, e um suplemento escolhido não é publicado silenciosamente: exige actualização do destino. O ponto só divulga a referência se a escolha expressa o permitir; a fonte integral continua no processo reservado. Data em falta fica desconhecida, sem usar published_at/updated_at como substituto. A interface pública mostra referência/data da origem separadas da data de registo, sem transmitir geometria ou coordenadas cruas. Datas só de calendário são apresentadas em UTC para evitar recuar um dia em fusos a oeste. - -Provas finais: **28 Feature/677 asserções** em business-point-publication-final-feature-20261102.log: oito cenários do suplemento, pesquisa por raio e percursos anteriores de intake/wizard/catálogo público. Incluem publicação por actor independente, versão obsoleta, coordenadas inválidas, referência territorial retirada entre aprovação/publicação, fonte reservada/data desconhecida, caminho múltiplo explícito, substituição com histórico/UUID/locais secundários e preservação sem opt-in. **17 frontend** aprovados: formulário real e mesma API de gravação, caminho/declaração múltipla, fonte reutilizada/diferente, campos condicionais preservados, selecção retirada visível, resumo preparado/publicado, datas/cobertura e consumidores anteriores. Tipos, lint/formatação sem avisos, Pint e compilação aprovados. PHPStan falhou primeiro na criação de uma pasta da cache global; passou com a mesma configuração incluída e cache privada isolada, sem supressões ou alteração das regras. O limite textual das coordenadas foi separado do limite numérico após o ensaio detectar max:16 aplicado como tecto numérico. - -Provas e hashes no recibo business_point_publication_increment_20261102. Bases exclusivamente sintéticas em investmoz_test, loopback PostgreSQL55441, guardas anteriores mantidas. Nenhuma migração no activo, fonte oficial real importada, conta real ou mensagem externa. Não há prova visual no navegador, cobertura real de pontos ou disponibilização no destino. Coordenadas declaradas e caminhos não certificam a correspondência espacial. Estado agregado parcial; próxima acção: retomar o saldo da matriz e as restantes funcionalidades/actores, preservando estes percursos e distinguindo cobertura real, aceitação visual e disponibilização de desenvolvimento em falta. - - -### 02/11/2026 — AUD-CHECKLIST-01: entrada em vigor das versões do Balcão - -Conferido o saldo contra o código e as provas anteriores: o editor/histórico já existiam e foram preservados. A lacuna deste incremento era a escolha da edição aplicável por data; todas as publicadas eram anteriormente oferecidas imediatamente. Acrescentada a data opcional de entrada em vigor à publicação, com calendário/fuso da aplicação indicado, prévia do efeito, confirmação invalidada quando a data muda e distinção entre última edição publicada, edição actualmente disponível e futuras edições agendadas. Ao editar uma edição futura, o formulário conserva essa data até alteração deliberada. A passagem do calendário não transforma um formulário sem alterações numa nova publicação; a alteração apenas da data tem de ser escolhida expressamente. - -DeskServiceAvailability é a única selecção usada no catálogo, dossier, percurso do investidor e criação de pedidos. Considera publicação efectuada e início já atingido; prevalece a data de início mais recente e, na mesma data, o maior número de versão. As linhas históricas sem data permanecem fallback, com ordem por versão, sem inventar datas ou reescrever a história. Uma correcção para hoje não cancela edições com início posterior; a gestão lista a edição futura vencedora por cada data. Para corrigir uma edição futura, publica-se nova edição com essa mesma data. É escolha técnica de selecção apresentada na prévia, sem alterar a sequência, as competências ou os critérios de decisão existentes. - -A criação de pedidos partilha o bloqueio transaccional da publicação. Um identificador futuro ou já substituído não cria um novo pedido; devolve erro no campo para conferir a versão actual. A interface actualiza apenas os serviços, conserva os outros formulários e torna explícita uma escolha que saiu da lista. Repetir uma criação já efectuada recupera o mesmo pedido, mesmo após mudança da edição corrente; respostas, fonte e snapshot continuam vinculados à FK original. Uma data passada é recusada numa publicação nova, mas a repetição da mesma publicação anterior continua idempotente. Repetição imediata e repetição agendada são distinguidas pela intenção registada no evento, preservando a data/autoria iniciais e recusando uma intenção diferente sobre a mesma base obsoleta. - -A migração 2026_11_03_010000_desk_service_effective_dates é aditiva, com data nullable e índice; não preenche versões antigas. Rollback recusa perda de datas preenchidas. Sem a coluna, o percurso imediato anterior continua a funcionar e o servidor recusa agendamento não suportado. A publicação inicial dos modelos também regista a data quando suportada. O ensaio desta rota revelou duplicação por comparação estrita da ordem de chaves JSONB; a comparação normalizada do editor foi reutilizada, conservando a primeira versão, autoria e data em repetição. A falha anterior está preservada em desk-effective-dates-final-feature-20261102.log e desk-effective-dates-complete-feature-20261102.log; não é uma perda de dados demonstrada no activo. - -Provas finais: **21 testes Feature/314 asserções** em desk-effective-dates-ready-feature-20261102.log, dez casos temporais/compatibilidade mais onze anteriores do editor, condições, preenchimento, localização, análise e recibo. Verificados calendário na fronteira da data, correcção imediata/edição futura, desempate na mesma data, data sem mudança de perguntas, selecção forjada, recuperação de criação anterior, snapshots/submissões preservados, datas inválidas/passadas, autoridade, fallback legado/rollback e integração real com o percurso do investidor. **Nove frontend** aprovados: data/confirmar/edição futura, calendário sem alteração implícita, lista agendada, actualização parcial e escolha retirada, metadados no catálogo e regressões do editor/histórico/perguntas condicionais. Tipos, lint/formatação sem avisos, Pint, PHPStan (mesmas regras com cache privada) e compilação aprovados; processos terminais conferidos. - -O fingerprint de instalação passa a incluir também editor, selector, controlador, histórico e migração temporal, para não reutilizar prova de código anterior para este comportamento. Não houve instalação no destino nem migração na base activa; apenas QA sintético PostgreSQL loopback55441, com guardas anteriores mantidas. As datas são avaliadas na leitura/criação e não dependem de agendador ou IA. A decisão permanece interna e não equivale a licença ou acto oficial. Estado transversal parcial: outros tipos/contextos de checklists, observação visual e disponibilização ainda por conferir; não se declara toda a aplicação parametrizável. Próxima acção: continuar os restantes saldos autorizados da matriz, conservando as versões e provas aqui delimitadas. - - -### 02/11/2026 — AUD-EDU-02: reconciliação com os rascunhos de Educação já demonstrados - -[EDUCATION-DRAFT-RECONCILIATION-20261102] AUD-EDU-02 é também coberto pelos incrementos já registados em AUD-EDU-01: rascunho incompleto privado de procura/capacidade, dono/tipo/versão, guarda/recuperação pela interface, conflitos, submissão única e revisão independente; sem zeros/datas fictícios ou inclusão nos agregados. Reutilizadas provas de 14 Feature/333 asserções, cinco frontend e dez cenários reais de concorrência em QA, com hashes das seis fontes UI/serviço/testes e sete logs conferidos em02/11. Recibos education_drafts_ui_increment_20261102 e education_drafts_concurrency_increment_20261102. Não é desenvolvimento novo ou instalação no activo. A indicação antiga de ausência na linha AUD-EDU-02 e nos planos anteriores é histórica e fica superada por estas provas, conservadas sem reexecução. A matriz/backlog foram corrigidos para parcial local. O saldo deste requisito é visual/disponibilização; AUD-EDU-03/01 conservam os restantes perfis e painéis. Nenhuma alteração no código, dados ou competências foi necessária para esta reconciliação. - - -### 02/11/2026 — AUD-ESTABLISHMENT-01: listas privadas preservadas e conferência das pendências - -Reconciliação com prova aceite de28/10/2026: importação privada específica já entregue, com361464 observações administrativas,147165 repetições conservadas e214299 projecções distintas; nenhum destes números é contagem de empresas únicas. Recibo proactive-supply-git-delivery-20261028.json e motores prepare/export/load-proactive-supply.py preservados. Os estados anteriores a essa entrega são históricos, não prova de ausência actual. - -O saldo da matriz dizia não existir importador. Essa formulação foi reconciliada com a entrega posterior já aceite: preparação, exportação, carregamento idempotente, hashes/linhas/fontes e consulta privada por território já existiam. O inventário histórico abrange13 ficheiros e o recorte tem quatro fontes aceites. O recibo de28/10 contém a prova de replay, backup/restauro, autorização/RLS e entrega Git; não se repetiu o lote nem se apresentou essa entrega como desenvolvimento novo. A leitura actual do código e os hashes dos originais foram confrontados com esse acervo. As361464 observações,205608 sem correspondência territorial e demais contagens desse recibo são a fotografia histórica, não um novo censo ou medição actual do destino. - -Lacuna concreta corrigida: a pesquisa territorial não conseguia recuperar linhas sem território, incluindo ambiguidades. A rota privada /minhas-oportunidades/oferta-interna/revisao, acessível pela consulta interna da preparação de oportunidades, permite conferir todas as linhas retidas por origem, texto sem acentos, estado e referência. Mostra origem/SHA256, folha/linha, data original, período e data da importação separadamente; os valores originais de província/distrito não são substituídos pela referência canónica actual. Datas Excel em formato serial mantêm-se como na fonte; importação recente não confirma actualidade da actividade. Repetições ligam à observação original mesmo entre fontes; paginação e ligações conservam os filtros aplicados e o contexto da ficha. A forma de pesquisa usa os valores efectivamente submetidos pelo navegador e acompanha a navegação entre filtros. - -Os totais por origem antecedem os filtros de texto/estado/linha; indicadores sobrepostos são identificados e não somados como empresas únicas. Distinguem-se ausência de correspondência, ambiguidade, referência canónica actualmente indisponível, designação de actividade em falta, denominação em falta, identificador com nomes divergentes e projecção repetida. Nenhuma destas situações é fundida ou corrigida automaticamente. Ausência de resultados significa informação insuficiente. A página não altera linhas, cria empresas, publica listas ou aplica georreferenciação. Os motores e o histórico existentes continuam únicos. - -A mesma autorização interna é verificada antes da validação/consulta de fichas, preservando também o âmbito de leitura da ficha quando fornecido. A leitura reutiliza o contexto RLS existente e os cabeçalhos private/no-store; a projecção exclui entity_key, fingerprint, recibo privado, contactos, identificadores fiscais e geometria. Nomes canónicos provêm apenas das referências públicas disponíveis. O componente territorial foi corrigido para não pintar resultados de uma localização ou ficha anterior após mudança/abort, nem substituir resultados novos com um erro tardio. A conferência independente da política SQL com papel sem privilégios confirma ausência de linhas sem contexto e acesso ao recorte sintético com o contexto esperado; não concede novas competências. - -Provas finais: **nove Feature/138 asserções** em proactive-supply-review-final-feature-20261102.log e **seis frontend** em proactive-supply-review-final-frontend-20261102.log. Cobrem linhas sem território, ambiguidade, repetições, conflitos, privacidade da projecção, âmbito/autorização antes de enumerar fichas, caracteres literais/acentos, paginação/referências, rota Inertia, origem das comparações e política RLS; na interface, escape, datas desconhecidas, filtros/contexto, navegação e respostas/erros tardios. PHPStan com as mesmas regras/cache privada, tipos, lint/formatação, Pint e build aprovados. As onze tabelas inventariadas na QA mantêm contagem e checksum de todas as linhas após rollback dos cenários; ver recibos before/after. São ensaios sintéticos exclusivamente em proactive_investment_20261027_test, PostgreSQL loopback55441, com guardas mantidas; não são aceitação por utilizadores reais. Não houve migração, importação de lote ou escrita no activo. - -O primeiro ensaio do cenário antigo falhou no fixture que exige sectores não existentes nesta QA; log proactive-supply-review-feature-20261102.log preservado. Isso não demonstra eliminação de sectores no activo nem revoga a aceitação anterior. Os novos testes usam actores, referências geográficas e observações explicitamente sintéticos dentro de transacções revertidas, sem semear permanentemente cadastros para mascarar o ambiente. A suite antiga completa não foi declarada verde. - -Estado parcial: falta reconciliação/consolidação rastreável de entidades e extensão a outros formatos/lotes concretos. Observação visual e instalação deste delta continuam pendentes; a limitação anterior da ferramenta de navegador permanece registada, sem substituir prova visual por testes técnicos. Não foi criado outro backlog nem condicionada a fonte aceite a nova validação genérica. Próxima acção: prosseguir os saldos autorizados da matriz, reutilizando importadores, referências e provas preservados. - - -### 02/11/2026 — reconciliação das vistas principais de Fundos e Educação - -O quadro inicial e as secções15/20 da visão consolidada ainda descreviam estes motores como ausentes, apesar dos incrementos e recibos posteriores. Foram reconciliados com as provas existentes, conferindo os hashes do código abrangido. Fundos conserva catálogo/editor, critérios, filtros/guardados/alertas e concorrência; Educação conserva o rascunho privado, interface/snapshot e concorrência. Os saldos de fontes, painéis/perfis, visual e destino continuam explícitos. Não houve testes, código de aplicação, dados ou disponibilização novos nesta reconciliação, nem outro backlog. - - -### 02/11/2026 — AUD-OP-05: maturidade na publicação e na limpeza de uma etapa opcional - -O cadastro de oito etapas e a pesquisa consciente da versão já existiam; foram preservados, sem outro catálogo ou conversão de números históricos. A leitura do código delimitou um risco na republicação quando não há etapa. O primeiro ensaio confirmou que a simples omissão no pedido conserva a etapa pelo merge do rascunho; não era uma perda demonstrada nesse percurso. O cenário com null explícito reproduziu a falha: a nova publicação perdia a versão/código da etapa mas mantinha o número e a designação anteriores. Assim, podia continuar a mostrar um valor que o autor tinha limpo e, nos números1–6, ser interpretada pelo filtro histórico. Logs iniciais conservados; não foi declarada regressão no activo. - -OpportunityProfileWorkflow passa a distinguir as respostas na projecção aprovada. Uma etapa indicada usa o catálogo spec-v2 existente. Uma etapa opcional explicitamente limpa publica valor/designação/código null e mantém a identificação de spec-v2, sem adivinhar uma etapa ou nível histórico. Se não foi fornecido esse campo, o valor anterior conservado mantém também os metadados anteriores, incluindo fichas preparadas por editores antigos. O histórico de publicação conserva integralmente a versão/código/valor/designação anteriores. A edição do rascunho continua privada e não altera a publicação até à revisão, aprovação e publicação competentes; nenhuma etapa de decisão foi removida ou automatizada. - -Provas dirigidas: **15 Feature/371 asserções**. Os oito códigos passaram pelo formulário HTTP de rascunho, submissão, revisão técnica/jurídica, aprovação independente, publicação, suspensão/revisão e republicação após limpeza. Verificados a designação/posição de cada etapa, o resultado do filtro por etapa antes/depois, ausência de correspondência histórica indevida e histórico anterior conservado. Seis cenários adicionais conservam cada valor/designação legado sem campo de etapa e distinguem o filtro histórico do actual; um código desconhecido é recusado no campo pelo validador de rascunho já existente, sem destruir a preparação anterior. As publicações de ensaio mantêm visibilidade interna e não entram nos consumidores públicos; são testes da projecção e do filtro partilhado, sem os apresentar como publicação pública ou aceitação visual. A prova anterior de pesquisa pública com escalas separadas continua no manual/manifesto opportunity-search-qa-manifest.json. - -Pint e PHPStan aprovados para o delta PHP. Não houve alteração de interface ou de rotas nesta etapa; a compilação e os testes frontend anteriores não foram repetidos sem necessidade. A QA exclusiva maturity_publication_20261102_test em PostgreSQL loopback55441 foi criada vazia para estes ensaios, com as guardas de teste e bloqueio mantidas. Não se reiniciou nenhuma base de provas anterior nem se alterou o activo. As localizações/actores/documentos são fixtures explicitamente sintéticas; a indicação antimalware no fixture de política não é novo scan real. O primeiro erro de cenário, por falta do pai territorial sintético, foi corrigido apenas no fixture deste recorte, sem relaxar a hierarquia ou atribuir localizações reais. - -O ensaio inicial de código desconhecido encontrou a rejeição já existente no rascunho, mais cedo que a hipótese inicial; foi corrigida a expectativa do teste, mantendo esse validador. A primeira execução alargada passou três etapas e recusou as cinco a partir de Viabilidade por faltar o cenário/indicadores/modelo exigidos. O fixture foi completado com valores declaradamente sintéticos e documento de política já pertencente ao cenário, sem enfraquecer a regra ou apresentar esses valores como cálculo/negócio real. Logs de falhas intermédias não são resultados de produção nem prova de ausência das funcionalidades já entregues. Recibo maturity_publication_increment_20261102 contém fontes e hashes dos logs finais/intermédios. - -Estado transversal parcial: faltam adopção explícita de legados, restantes variantes/categorias, observação visual e disponibilização do delta. Não se declara toda a maturidade/publicação do portal concluída pelo recorte interno. Próxima acção: continuar o confronto dos saldos autorizados com o código e provas existentes, conservando classificações, submissões e decisões anteriores. - - -### 02/11/2026 — AUD-COMPANY-01: comparador societário informativo e recuperação no dossier - -Conferido o requisito contra código/matriz e o exemplar confirmado de segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5. Leitura apenas, sem alterar o original ou produzir outro DOCX; 907 parágrafos OOXML conservam os locators, incluindo vazios. A primeira extracção auxiliar contava só 889 parágrafos não vazios; foi corrigida antes de usar os locators. A secção 9/§§9.1–9.6 não constitui modelos de contratos entregues. O comparador e os modelos mantêm IDs próprios, sem transformar propostas em código existente. - -A base legal aceite foi recuperada da [edição republicada do Código Comercial no portal do Tribunal Superior de Recurso de Maputo](https://tsrm.gov.mz/wp-content/uploads/2025/10/Dec_Lei_1_2022.pdf), 76 páginas, BR 99/I Série/3.º Suplemento de 25/05/2022. A nota da Imprensa Nacional identifica a republicação; a conferência delimitou a edição, sem voltar a exigir aceitação genérica da fonte oficial. Original privado conservado em company-sources-20261102/commercial-code-republished-20220525.pdf, SHA256 8009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f. Não foi importado/publicado como novo recurso da biblioteca e não se atribuiu scan antimalware novo ao ficheiro; a interface referencia o exemplar oficial externo. As fontes/artigos e a data de consulta acompanham cada resultado; não se declara cobertura de todas as alterações ou legislação especial. - -Consulta pública em /formas-juridicas, acessível de Como Investir e do perfil; o dossier oferece /investimentos/{id}/forma-juridica. As perguntas recolhem apenas preferências codificadas e dados novos da preparação: finalidade, participantes, participações, capital, gestão, responsabilidade, Bolsa, regras específicas e alternativa a aprofundar. Não repetem nome, NUIT, residência, orçamento ou identidade da entidade. Gestão permite esclarecer poderes dos sócios e nomeação da administração em conjunto, sem falsa alternativa exclusiva. Desconhecidos são permitidos e indicados como questões por esclarecer; cada pergunta produz uma explicação ou preparação aplicável. - -A comparação distingue empresário individual dos quatro tipos societários enumerados na edição citada. As modalidades unipessoais são identificadas no respectivo âmbito. Incompatibilidades documentadas são mostradas sem esconder a preferência do utilizador, aprovar constituição ou criar uma pontuação. Representação de sociedade estrangeira e cooperação têm encaminhamento próprio; não são novas formas societárias. As perguntas sem aplicação ficam ocultas e fora da avaliação, conservando os valores para futura recuperação. A interface apresenta fundamentos, fonte, limites e próximos pontos a preparar. Este recorte não gera contratos nem certifica registo, responsabilidade pessoal, habilitação, financiamento ou admissão em Bolsa. - -Escolher um dossier transporta os códigos pelo percurso existente de autenticação; o middleware conserva o URL pretendido. O utilizador pode escolher dossier existente ou criar um novo com título/consentimento habituais. A criação não grava automaticamente a comparação: as respostas chegam como preparação e Guardar no dossier é explícito. Os testes de HTTP/estado não são prova de login real no navegador. Em erro, as respostas continuam no formulário; Reabrir com estas respostas faz GET com os valores actuais, permitindo recuperar sessão/versão sem os descartar. Nenhum nome ou contacto privado é colocado nesse transporte de códigos. - -CompanyComparison é o único avaliador. Reutiliza autorização e bloqueio de linha de VirtualDesk, a versão de desk_cases e os eventos cifrados existentes. Não criou tabela, entidade ou competência paralela. Guardar congela respostas, perguntas/opções, resultado, edição/hash/artigos da fonte, autoria e data. A edição anterior permanece no evento; a lista é paginada e recupera edições antigas pelo identificador no âmbito do mesmo dossier. Resultados/perguntas de uma edição anterior não seguem silenciosamente o motor actual. Preparar nova comparação a partir de uma edição histórica é explícito e cria outra revisão, preservando a anterior. Mudanças da configuração do comparador não reescrevem o cadastro, as declarações de empresa, o dossier anterior ou as etapas do percurso. - -Repetir a mesma operação e conteúdo recupera a revisão original, inclusive quando as perguntas da edição actual já mudaram. A normalização dessa repetição usa a definição congelada na operação anterior; versões inteiras recebidas como número ou texto são normalizadas após validação. Reutilizar a chave com respostas diferentes é recusado. Uma nova operação sem alteração de respostas/resultado reutiliza a edição existente, sem aumentar a versão, criar outro evento ou aviso redundante. Operações novas com versão obsoleta/dossier fechado são recusadas; a repetição de uma gravação anterior não escreve num dossier fechado. A permissão efectiva é conferida novamente; revogação de coeditor impede leitura, repetição e gravação na sessão anterior. Um membro só de consulta não ganha edição. - -Provas finais: **14 Feature/385 asserções**, dez casos novos e quatro anteriores de InvestorPath, em company-comparison-finalized-feature-20261102.log. Cobrem consulta pública sem IA, incompletude, códigos inválidos, efeitos das perguntas, conflitos/unipessoalidade, campos inactivos, gravação/cifragem, ausência de alterações nos cadastros/etapas, repetição/no-op/conflito, fonte/perguntas históricas após nova versão, 26 edições/paginação, âmbito, coedição/revogação, encerramento, escolha/criação de dossier e retorno. **Seis frontend** aprovados: escape, fonte e formulário GET real; visibilidade com recuperação; transporte dos valores efectivamente presentes no navegador; falha sem perder edições e recuperação por GET; leitura histórica com perguntas próprias; gravação/retorno e links no mesmo âmbito. Tipos, lint/formatação sem avisos, PHPStan com regras herdadas/cache privada, Pint e compilação aprovados, processos terminais conferidos. - -QA exclusiva company_comparison_20261102_test, PostgreSQL loopback 55441, guardas existentes mantidas; a conferência final regista zero utilizadores, dossiers, organizações e declarações de empresa após rollback. São cenários sintéticos de política e interface técnica, sem pessoas reais ou aceitação por clientes. Não houve migração nova/activa, importação no activo, mensagem externa, publicação de modelos ou disponibilização remota. Os primeiros avisos de tipos e de tratamento de FormData foram corrigidos no código, sem supressões ou relaxamento de autorização. - -Estado parcial: observação visual e login real continuam pendentes devido à limitação de navegador já registada, bem como disponibilização e casos especiais/redacções adicionais. AUD-COMPANY-02 conserva o saldo de exemplares específicos, versionamento e derivadas dos modelos; a biblioteca genérica e esta comparação não os substituem. Próxima acção: continuar os saldos autorizados da matriz, reutilizando esta comparação e os mecanismos documentais existentes quando o recorte concreto de modelos/guiões for implementado. - - -### 02/11/2026 — AUD-COMPANY-02: preparação factual privada, exemplares pendentes - -Foi lido o complemento fornecido, SHA256 b20c6517784b6d44aa22beb67748d3f3b224f58c60a7dcb378a185669c2c543e, sem alterar o DOCX original. O documento propõe sete minutas e oito requisitos; não contém os sete exemplares. A orientação final permite desenvolver a estrutura/formulário sem publicar cláusulas não fornecidas. A pesquisa nas pastas conhecidas não localizou os modelos. O proprietário informou «nao tenho neste momento a url»; pendência de fonte registada, sem nova solicitação repetida e sem a converter em bloqueio dos outros desenvolvimentos. Propostas ou prompts incluídos no documento não foram tratados como ordens executáveis, provas de implementação ou competências outorgadas. - -/investimentos/{id}/preparar-empresa reutiliza o dossier e as autorizações existentes. Sete secções: forma, intervenientes/papéis, nome/sede, actividades, capital/participações, administração/forma de obrigar e conferência. Nome, sede e poderes são propostas. Não se recolhem NUIT, documento de identidade, assinatura, morada residencial ou contactos repetidos. As origens disponíveis são o proponente conservado na criação e a declaração de empresa já associada ao dossier; a escolha é explícita. O servidor resolve os valores, referência e versão, ignora a tentativa de trocar identidade através de um nome enviado e recusa snapshots forjados. Uma origem já utilizada na mesma linha mantém os valores congelados mesmo que outro contexto ou cadastro mude. Não há fusão por igualdade de nome; cada linha tem identificador próprio e duplicação de uma origem é assinalada. Sócio, administrador, representante e beneficiário efectivo declarado são papéis distintos/acumuláveis; a representação exige identificar outra linha na conferência. Não se validou identidade nem se atribuiu qualquer desses papéis de autoridade automaticamente. - -Aritmética decimal exacta com a dependência Brick Math já instalada pelo framework; sem floats, câmbio, mínimos legais ou prazos inventados. Valores ausentes não são zero. Entradas em dinheiro e espécie compõem a subscrição; realização declarada é distinta de prova de pagamento. São conferidos soma versus capital, realização acima da subscrição e, nas formas em acções, número vezes nominal por participante e total. Trabalho fica separado e não integra capital (artigo 266 da edição já citada no comparador). A ficha incompleta/inconsistente é um rascunho guardável, com questões visíveis. Capital é ocultado no percurso individual e valores de outras escolhas são preservados, fora dos totais aplicáveis. Actos de administração, objecto e origem não se convertem em poderes, licenças ou registo. - -CompanyPreparation conserva facts/definição/fonte/conferência/autoria/data por revisão nos payloads cifrados de desk_cases/desk_events. Reutiliza locks de linha, versão do dossier e eventos/notificações existentes. A auditoria não contém nomes ou valores da ficha. Repetir uma operação confirmada devolve a revisão original; a repetição usa as formas/definição congeladas, mesmo depois de mudar a configuração actual. Mesma chave com outro conteúdo, versão obsoleta e nova escrita em dossier fechado são recusadas; uma repetição anterior não escreve no dossier fechado. Novo pedido sem mudança reutiliza a revisão existente. Histórico de 25 com cursor permite recuperar revisões antigas no mesmo dossier; ID de revisão de outro dossier não é aceite. Revogação de coeditor é efectiva antes de leitura, replay ou validação, e membro de consulta não ganha escrita. A gravação não altera o cadastro, as etapas, os contratos ou os pedidos do Balcão. - -Interface usa profileJson/XSRF e lê valores reais do formulário incluindo preenchimento automático. Em falha conserva dados; consulta privada da edição actual permite comparação legível e adopção explícita da nova versão antes de voltar a guardar. Os dados privados não são transportados na querystring. Edição histórica e consulta têm campos só de leitura. Não houve prova de sessão expirada/login real no navegador. - -Provas finais: **18 Feature/343 asserções**, oito casos novos e dez do comparador anterior; **12 frontend**, seis novos e seis anteriores. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build passaram. A primeira ronda revelou uma chamada incorrecta à API decimal e a análise de tipo de uma colecção; corrigidas sem supressões. Um valor esperado num cenário extremo de acções foi corrigido após conferir o produto exacto. Só as provas finais aprovadas sustentam este recibo. QA exclusiva company_preparation_20261102_test, loopback 55441, guardas intactas, rollback conferido com zero pessoas/dossiers/organizações/declarações/pedidos. Não se ensaiou concorrência em dois processos como nova prova nem se importaram dados no activo. - -**Cobertura parcial:** preparação factual e histórico demonstrados; sete exemplares, biblioteca específica, cláusulas/derivadas contratuais, catálogo de actividades/licenciamento integrado, revisão profissional e percursos de assinatura/submissão/registo continuam pendentes. Não foi criado aprovador jurídico ou motor documental paralelo. Não se declara minuta pronta, contrato assinado, sociedade constituída, aceitação por cliente, observação visual ou instalação remota. Próxima acção: continuar os outros saldos autorizados; integrar os exemplares na biblioteca existente quando disponíveis, preservando estes dados e revisões. Recibo company_preparation_increment_20261102. - - -### 02/11/2026 — AUD-CAPITAL-01: guia público de capitalização e referência privada recuperável - -Incremento iniciado em 02/11/2026; provas finais encerradas em 03/11/2026 (Africa/Johannesburg). As datas dos exemplares e o identificador do incremento mantêm a consulta original. - -Confrontados matriz/código/provas e segmentar processos v1.docx, original SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo 154 e bloco CAP-001 (702–708). O roteiro financeiro existente não continha o guia público e referência recuperável pedidos. Não se criou outro roteiro nem se contou a lacuna de evidência como desaparecimento das etapas financeiras. O incremento societário anterior e respectivos recibos permanecem preservados. - -Guia em /guias-investimento/capitalizacao, acessível de Como Investir e Documentos do dossier. Distingue capital próprio/entrada de sócios, private equity/capital de desenvolvimento, dívida e híbridos/convertíveis. Expõe conceitos, riscos e pontos a discutir, preparação/documentos, elegibilidade por entidade, fontes/edição/locators/data/hash e próximos passos. A selecção organiza os cartões, sem pontuação ou recomendação. Sem selecção, consulta-se o conjunto. Exemplos de BNI/IFC pertencem às respectivas entidades; nenhum montante, prazo, taxa ou percentagem é convertido em condição universal. O artigo educativo Chase suporta conceitos gerais de dívida/capital e riscos, não regras dos EUA aplicadas a Moçambique. Não há promessa de retorno, aprovação, produto disponível ou adequação a um caso concreto. - -Fontes primárias efectivamente lidas: [BNI Capital de Risco](https://www.bni.co.mz/banca-de-investimento/capital-de-risco/), [IFC Equity Investments](https://www.ifc.org/en/what-we-do/products-and-services/equity-investments), [IFC Loans](https://www.ifc.org/en/what-we-do/products-and-services/loans), [IFC How to Apply](https://www.ifc.org/en/what-we-do/products-and-services/how-to-apply-for-financing) e [Chase Debt vs Equity](https://www.chase.com/business/knowledge-center/grow/debt-vs-equity-financing). Cinco HTML originais em capital-guidance-sources-20261102, privados, com SHA256 conferidos no recibo. São exemplares da consulta de 02/11; não foi inventada uma data editorial. O guia conserva síntese própria e referências, não serve estes HTML ou scripts nem publica originais na biblioteca sem o percurso documental existente. Não se atribuiu scan novo ou direito de redistribuição ao arquivo auxiliar. O PDF IFC de 1999 foi encontrado mas não serve de norma vigente ou condição de produto; páginas BVM com mínimos de 2024 até 31/03/2025 não foram usadas como limites de 2026. Autenticidade oficial anteriormente aceite não foi novamente posta em aprovação genérica; fonte/edição/período continuam distintos. - -Escolher/criar dossier passa pelo InvestorPath.contexts e autenticação normal. Só códigos, slug e hash da edição seguem na URL. O servidor valida a edição antes de criar um dossier e não guarda a referência por arrasto. Criar contexto e confirmar referência são acções distintas. Selecção vazia é explicitamente transportada para não recuperar inadvertidamente uma escolha anterior. Não são repetidos nome, NUIT, contactos, morada, orçamento ou dados financeiros. A única informação livre adicional é uma nota opcional da preparação, introduzida no dossier privado e enviada por POST/XSRF. Não houve prova de login real no navegador. - -InvestmentGuides conserva a referência cifrada em desk_cases.payload.investment_guides e desk_events, com guia/fontes integrais da edição, instrumentos, nota, autor/data, âmbito dossier_reference e revisão/hash do contexto. A fonte externa pode mudar, mas o conteúdo guardado não é reescrito. Nova edição é explícita; escolhas que deixaram de existir são identificadas e permanecem no histórico. Referência histórica/antiga/retirada fica em consulta. Remover o guia actual não apaga a referência privada. Histórico paginado de 25, filtrado pelo mesmo guia/dossier; ID de revisão alheia é recusado. Alteração do contexto é visível e não reescreve a revisão anterior. Não se anexou por nome uma empresa, projecto, documento ou oportunidade de outro contexto. - -Permissões do dossier, bloqueio de linha e versão são reutilizados. Coeditor revogado não pode ler/repetir/validar na sessão anterior; membro só de consulta não ganha escrita. Mesma operação/conteúdo devolve a revisão original mesmo com guia alterado/retirado, usando a definição congelada. Mesma chave com outra nota é recusada; nova operação sem mudança não duplica evento/versão/aviso. Versão obsoleta e nova escrita em dossier fechado são recusadas; replay anterior não escreve. Falha conserva nota/escolhas, permite consultar a edição guardada e exige conferência explícita antes de adoptar outra versão do dossier. Se o guia tiver mudado ou sido retirado durante a preparação, não se confirma silenciosamente uma edição antiga. Auditoria e avisos existentes não expõem a nota. - -21 Feature/524 asserções: sete casos novos e 14 anteriores de InvestorPath/comparador; 13 frontend, sete novos e seis anteriores. Cobertura: consulta pública sem IA, instrumentos válidos/inválidos, fonte/hash, percurso HTTP de autenticação/escolha/criação, fonte desactualizada sem dossier extra, dados cifrados sem mudança de cadastro/etapas/pedidos, replay/no-op/conflito/encerramento, fontes/edições/retirada, 26 revisões/paginação, âmbito de histórico, mudança de contexto e revogação/consulta. Interface técnica: escape/fontes/edições, cartões, selecção vazia, valores reais incluindo preenchimento automático, gravação privada, recuperação de erro sem URL privada, escolha de dossier e leitura histórica/retirada. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build passaram, processos terminais conferidos. O primeiro cenário de contexto preparava uma chave de payload errada; fixture corrigida para a estrutura real, sem enfraquecer produção ou autorização. A revisão final acrescentou protecção da selecção vazia e recuperação perante guia alterado. - -QA exclusiva capital_guidance_20261102_test, PostgreSQL loopback 55441, guardas intactas; zero utilizadores/dossiers/organizações/declarações/pedidos após rollback. São cenários sintéticos. Sem migração nova, escrita no activo, contacto externo, submissão, intermediação, concessão, cálculo fiscal/financeiro ou mudança de etapas. Não foi alegada nova prova de concorrência em dois processos. - -Estado parcial local: o guia base e referência recuperável estão implementados. Restam observação visual/login real e disponibilização; condições particulares e decisões pertencem às contrapartes. AUD-CAPITAL-02 continua distinto: recuperar Código do Mercado de Valores Mobiliários e regulamentos por segmento, conferir artigos/redacção/períodos/alterações e explicitar intervenientes e lacunas sem usar mínimos expirados. Não apresentar o guia de capitalização como guião de admissão à Bolsa concluído. Recibo capital_guidance_increment_20261102. - - -### 03/11/2026 — AUD-CAPITAL-02: guião BVM por segmento, fontes e recuperação no dossier - -Confrontados matriz, fontes e código. O guião bolsista estava efectivamente ausente; o guia de capitalização entregue no recibo capital_guidance_increment_20261102 e o seu mecanismo de referências foram reutilizados. Não se criou outro percurso, serviço de negociação, tabela de admissão ou competência de decisão do portal. O pedido de segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo155/bloco CAP-002, mantém o ID existente. - -Seis PDF BVM recuperados e conservados por hash em bvm-guide-sources-20261103: CMVM/DL4/2009 (68p), admissão1/2010 (28p), Segundo Mercado2/2010 (13p), Terceiro04/2021 (6p), mínimos01/2024 (2p) e Central25/2006 (10p). Reutilizado, sem duplicar original ou pedir nova aprovação da autenticidade, o Código Comercial republicado de25/05/2022, BR99/I Série/3.ºSuplemento,76p e SHA2568009ef95a352dc02283e671cd717449ec8ad747a8995153cd3122ea16aa22a0f. A data de aprovação em Conselho de02/06/2009 do exemplar do CMVM foi distinguida da publicação de24/07/2009 identificada no DL1/2022. Art.4 desse diploma altera arts.8 e52 do CMVM; o art.444 do Código Comercial limita as acções SAS. Não foi feita uma consolidação silenciosa dos dois textos. - -Skill PDF aplicada apenas a leitura/extracção/renderização, sem editar/criar PDF ou executar marcador de autoria. PyMuPDF/pypdf instalados em dependências privadas de leitura; a instalação terminou correctamente, apesar do wrapper PowerShell assinalar a notificação de nova versão pip em stderr. As imagens do Terceiro Mercado e dos mínimos não contêm texto extraível; todas as seis/duas páginas foram conferidas visualmente. Pontos críticos do CMVM, anexos de documentos, Segundo Mercado, Código Comercial e Central também foram vistos em imagem;20 PNG inspeccionados estão identificados por hash no recibo. Extracções completas por página e inventário privados conservados. O HTML da BVM é uma shell React e não foi tratado como conteúdo normativo completo; bundle público foi consultado como fonte auxiliar de navegação, sem executar scripts ou contornar autenticação. O leitor web deu timeout em PDFs, mas HTTP directo recuperou os originais, conferidos pela assinatura PDF e hashes. Não se declarou scan antimalware novo ou publicação desses originais na biblioteca. - -Guião público /guias-investimento/bolsa, ligado de Como Investir, Documentos do dossier e guia de capitalização. Cinco percursos: acções e obrigações no MCO, acções e obrigações no Segundo Mercado, acções no Terceiro Mercado. Selecção organiza comparação; não decide admissibilidade ou aplica critérios a partir de nacionalidade do utilizador. Os exemplos empresariais não são automaticamente aplicados a fundos públicos/equiparados, outros valores, operações especiais ou valores estrangeiros. Os limites e bases dos casos especiais são identificados. - -Cada requisito/dispensa/lacuna referencia fonte, edição, artigo e página do PDF, com ligação directa ao ponto de partida da disposição. O guião distingue condições de contas e dispersão dos segmentos, documentação e prospectos: Anexos A/B de instrução documental do processo de admissão não são confundidos com Anexos A/B dos prospectos do Segundo Mercado. Dez grupos documentais, com identificador único e âmbito por percurso; comuns aparecem uma vez na escolha múltipla. Auditoria de entrada fica fora do grupo documental do Terceiro Mercado, mas as demonstrações PGC-NIRF assinadas por contabilista OCAM e a conferência da declaração de actualidade permanecem. Reutilizar documentos no dossier é o percurso existente; não se pediu nova introdução de nome, NUIT, morada, capital ou participações. - -Divergências concretas: Reg04/2021 revoga04/2019 (art9), define horizonte de até dois anos para conformidade, com eventual prorrogação excepcional fundamentada de mais um ano, e prestação semestral de informação. A página informativa ainda referia nove meses e exclusão geral dos pontos5/10 do AnexoA; esses enunciados não foram importados como regras de 2021. A dispensa de contas auditadas é de entrada, não perpétua; não foi estendida sem base à declaração do ponto10. O regime de2022 dos valores nominativos e a limitação de acções SAS foram incorporados, sem inventar uma nova regra organizacional. Prazos notificação/publicação são apresentados com condições e fonte; não criam aprovação por silêncio, extensão automática ou calendários do portal. - -Os mínimos01/2024 vigoravam até31/03/2025, conforme imagem do próprio preâmbulo. Não se reutilizaram os seus valores como mínimos de2026 nem se derivaram limites actuais por proporção de montantes expirados. Cada percurso conserva value:null/unit:MZN no requisito de montante; relações legais com mínimos de outros mercados são descritas sem cálculo. O regulamento anual actual e encargos/preçário ficam explicitamente por obter/conferir com BVM/operador, sem converter desconhecido em zero ou impedir a gravação privada. Os procedimentos operacionais CVM de2025 foram identificados no portal oficial mas não integralmente recuperados/codificados; o decreto de2006 serve a identificação institucional, não uma alegação de cobertura desses procedimentos recentes. - -Intervenientes e seis etapas distinguem emitente/requerente, operador patrocinador/interlocutor, BVM decisora, Banco de Moçambique supervisor e respectivas competências sobre ofertas públicas, e CVM como serviço gerido pela BVM. Encaminhamento oferece ligações oficiais de informação, sem transportar nota, dossier ou documentos; não há mensagem, pedido, oferta, registo, negociação ou admissão enviados pelo portal. Decisões externas e documentação real conservam os passos financeiros existentes, sem avanço por guardar o guia. - -InvestmentGuides existente mantém fontes/guia/escolhas/nota/contexto por snapshot cifrado e revisão. Não houve nova alteração ao motor de persistência. Provas novas verificam dois guias no mesmo dossier, protecção contra replay de chave de outro guia, recusa de revisão alheia e paginação de26 revisões BVM intercaladas com26 do guia de capitalização. As referências não se misturam; notas/fontes anteriores permanecem recuperáveis. Os sete casos anteriores de guias mantêm âmbito, autenticação, fonte desactualizada, ausência de criação por arrasto, permissões, revogação, encerramento, replay/no-op e snapshots de edição retirada. - -Provas finais: **14 Feature/474 asserções**, sete casos BVM e sete de guias anteriores; **18 frontend**, cinco novos e13 anteriores. PHPStan com regras herdadas/cache privada, Pint, tipos, lint sem avisos e build aprovados; processos terminais conferidos. A primeira ronda teve13/14 testes aprovados: a expectativa de citação só aceitava Art maiúsculo e recusava art.444; o teste foi corrigido para comparação de letra/Unicode, sem relaxar as referências de produção. Interface técnica confere requisitos/edições/links, dispensa de auditoria no percurso devido, OCAM/actualidade, documentos comuns uma vez, diferenças entre contas/prospectos, ausência de dados privados em links externos e leitura histórica sem escrita. Não se confundiu a inspecção visual dos PDFs fonte com aceitação visual da aplicação, login real ou utilização por cliente. - -QA exclusiva bvm_admission_20261103_test, PostgreSQL loopback 55441, guardas intactas; zero utilizadores/dossiers/organizações/declarações/pedidos após rollback, com visibilidade/owner das tabelas registados. Não houve migração, importação no activo, activação de cálculo, alteração de cadastro, mensagem externa, instalação remota ou nova prova de concorrência em dois processos. - -**Saldo concreto:** montantes anuais actuais, encargos/preçário actual, procedimentos CVM recentes completos, casos especiais não abrangidos/alterações posteriores, observação visual/login real e disponibilização. O guião base e a referência privada são demonstrados; admissão real e cobertura integral da regulamentação não foram declaradas concluídas. Próxima acção: continuar os outros saldos autorizados da matriz, mantendo estes campos indeterminados até recuperar as fontes aplicáveis e preservando os dois guias já entregues. Recibo bvm_admission_increment_20261103. - - -### 03/11/2026 — MASTER-e1169a77-0018: indicadores operacionais, bases e cobertura - -[PRODUCT-USAGE-20261103] Painel privado /management/product-usage para o gestor global já autorizado: coorte de pedidos por dias UTC e código de serviço incluindo versões históricas; contagens separadas, primeira submissão/devoluções por pedido distinto, causas explicitamente classificadas, duração até à primeira submissão e referências de comparação/guias guardadas por dossier distinto. Historial contíguo por versão até ao corte, cobertura e exclusões visíveis, ausência de base distinta de zero e exportação do snapshot agregado. Categoria opcional de devolução reutiliza o workflow/autorização; código, rótulo e definição conservados no evento cifrado. Sem inferência a partir de texto, novo rastreio de visitantes ou score. 24 Feature/338 asserções, 11 frontend, PHPStan/Pint/tipos/lint/build aprovados; snapshot PostgreSQL repeatable read/read only efectivamente conferido. Recibo product_usage_metrics_increment_20261103. - -Fonte funcional efectivamente relida: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420; confronto com métricas dos parágrafos 865–871 da segmentação bf26caee e com o código. O painel específico estava ausente; contagens do dashboard e DeclaredOriginStatistics existentes foram preservadas. AUD-STATS-01 continua separado e parcial; AUD-HUMAN-03 continua dependente dos pesos/limiares/pilotos concretos, sem bloquear as contagens factuais autorizadas nem inventar um score. - -Consulta em /management/product-usage, ligada do dashboard do gestor global. Autenticação, correio verificado e manage-portal já existentes; revogação volta a negar acesso. Período UTC inclusivo por dias, limite superior exclusivo min(dia seguinte, agora), código do serviço cobre as suas edições históricas. Não há limite arbitrário de dias ou mistura de linhas entre dossiers, pedidos e pessoas. Segmento de serviço dos dossiers/ referências exige um pedido desse código também criado no período; a definição é visível. - -Taxas: primeira submissão por pedido com draft_created v1 e versões contíguas observáveis até ao corte; o campo submitted_at mutável não é usado como primeira data. Histórico insuficiente fica excluído e quantificado; taxa de um subconjunto não é publicada como funil integral. Devolução conta uma vez após a primeira submissão, mesmo com reenvios e decisões repetidas. Causa específica exige código explícito validation_error/missing_documents; texto livre não é interpretado. Um pedido com causa comprovada permanece positivo apesar de outra devolução sem categoria; nos restantes, desconhecido impede taxa específica exacta. Numerador conhecido e denominador ficam visíveis. Média rascunho→primeira submissão usa apenas intervalos não negativos, identifica excluídos e não se intitula tempo de criação do projecto ou SLA. Rascunho ainda sem submissão não é abandono. - -Categoria de devolução opcional, configurada uma vez e entregue à interface; servidor exclui-a nas restantes transições e mantém as regras de independência, campos de correcção, versão e fundamento anteriores. Regista código, rótulo e versão da definição no payload cifrado do evento, sem reescrever o passado. Eventos VirtualDesk novos passam a registar explicitamente a hora da aplicação: o default PostgreSQL now() era a hora de início da transacção, podendo anteceder o rascunho criado dentro dela. Registos anteriores são preservados; intervalos negativos não são corrigidos por suposição. - -Consulta PostgreSQL numa transacção read only/repeatable read quando possui a transacção exterior; dentro de transacção já existente identifica essa condição e não substitui o contexto de acesso. Leitura por lotes de 100 pedidos; só desencripta payloads de devolução necessários à categoria, sem devolver motivos/nome/ID/payload privado. Exportação JSON reutiliza exactamente o relatório aplicado, sem nova chamada ou guardar filtros por aplicar. Fingerprint identifica o conteúdo, não certifica fontes independentemente. Não há migração ou novo evento de visitante, termo de pesquisa, IP, cookie ou identificador de navegação. - -Verificações: 24 Feature/338 asserções (7 casos novos e 17 regressões de guias/edições de serviço), 11 frontend, PHPStan/Pint, tipos e lint aprovados, build terminal aprovado. Primeira ronda apanhou um fecho de array em falta na validação e consequentes falhas; corrigido e repetido o lote, sem reduzir asserções. Formatação inicialmente abrangente foi interrompida e substituída por ficheiros explícitos; inventário de horários não mostrou edição de ficheiros alheios ao incremento. QA product_usage_20261103_test em loopback 55441, guardas preservadas. A prova posterior sem transacção de PHPUnit confirmou SHOW transaction_read_only=on e repeatable read em todas as consultas observadas; após rollback, seis colecções vazias conferidas com proprietário/RLS, sem actor ocultar linhas. Não é prova visual/login em navegador real, concorrência em dois processos, medição com utilizadores reais ou instalação no destino. - -Saldo 03/11/2026: primeiro painel operacional local implementado; não equivale à cobertura integral de métricas de produto. Restam aquisição/activação, pesquisa e zero resultados, comparação pública, correspondência individual CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão do roteiro versionado, tempo projecto/submissão e etapas, abandono, satisfação/suporte, pós-investimento e registo de experiências controladas com hipótese/indicador/período/segmento/resultado/decisão. Não foram inventados pesos, baseline de pilotos, limiares, consentimentos ou eventos de visitantes. Visual/login real e disponibilização continuam pendentes. - - -### 03/11/2026 — MASTER-e1169a77-0018: registo de experiências, planos e observações por versão - -[PRODUCT-EXPERIMENTS-20261103] Registo privado /management/product-experiments implementado: rascunho recuperável, plano/hipótese/indicador/edição/período/segmento/controlo/variante/método/critério, preservação dos quatro requisitos, observações, referências de evidência, limitações e decisão declarada. Versões cifradas com autoria/rótulos/definições conservados, ETag/compare de três vias, repetição idempotente de escritas, histórico paginado e exportação da versão consultada. Alteração do plano conserva a ligação das observações ao plano efectivamente utilizado, incluindo quando muda o período; reafirmação exige acção explícita e datas coerentes. Relatório operacional anexado só pelo servidor, preservado por versão e identificado como contexto sem separação de grupos/causalidade. Histórico imutável, origem estável, avanço unitário e FK diferível da versão actual conferidos em PostgreSQL. 18 Feature/271 asserções e 7 frontend, PHPStan/Pint/tipos/lint/build aprovados; recibo product_experiments_increment_20261103. Uma migração ensaiada apenas em QA, sem escrita ou instalação activa. - -Fonte funcional: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420, já conferida no incremento de indicadores. Reutilizados a matriz, o recibo product_usage_metrics_increment_20261103, os indicadores operacionais e a competência global manage-portal existente. O registo estava ausente no código/schema; não se reclassificou contagem anterior como experiência ou piloto real. AUD-HUMAN-03, AUD-STATS-01, contratos modulares experimentais e SLA mantêm os âmbitos/decisões próprios. - -Entrada pelo painel de indicadores, com lista/filtro/paginação de registos e novo rascunho que aceita informação ainda incompleta. Plano registado exige hipótese, indicador, período UTC, segmento, controlo/variante, método de comparação, critério e medidas de transparência/consentimento/segurança/igualdade. A declaração de preservação dos requisitos não executa ou aprova a alteração. Observação/resultado/decisão distinguem datas previstas das efectivamente observadas, evidências declaradas, limitações, controlo/variante descritos e fundamento. Pode registar conclusão inconclusiva; não há números, amostras, limiares, responsáveis nominais ou decisões automáticas fabricados. Rascunho/plano/observação/decisão/cancelamento são estados documentais, corrigíveis por nova versão e motivo, sem substituir o workflow dos processos. - -Cada versão guarda values cifrados, autoria real do actor autenticado, data de servidor, motivo, vocabulário, edição da definição do indicador e hashes. Indicador próprio é uma definição manual explícita; indicadores do painel reutilizam a definição do servidor e conservam a edição anterior até adopção explícita da nova. Dados de campos inactivos conservam-se sem os exigir ao ramo activo. Actualização meramente descritiva não actualiza silenciosamente a definição manual. Leitura histórica usa o vocabulário/definição realmente guardados. O primeiro plano registado conserva a data real, sem aceitar autoria/data de registo impostas pelo cliente ou alegar pré-registo por inferência. - -Alterar plano já registado exige confirmação explícita e motivo; conta revisões e identifica alteração após observação. A observação mantém plan_sha256 do plano em que foi registada. Alterar período pode preparar outro plano sem reescrever datas/resultados anteriores: fora do âmbito actual, permanecem históricos e identificados. Para registar observação/decisão como referente ao novo plano, o autor revê/reforça essa ligação explicitamente; datas devem então caber no período correspondente e não ser futuras. Nada disto transforma um resultado anterior em prova do plano novo. - -Relatório operacional opcional é capturado pelo ProductUsageMetrics, no servidor e em leitura consistente antes da transacção de escrita, conservando o seu âmbito efectivo quando já existir transacção exterior. Apenas filtros/datas autorizados são aceites; payload/report forjados não são usados. Fonte/edição/corte/cobertura/numerador/denominador/indeterminados ficam no snapshot. A legenda operational_cohort_not_experiment_arm é explícita: esse relatório não mede o segmento livre, não separa grupos e não comprova causalidade. Mudar datas/serviço conserva o relatório anterior e assinala divergência; anexar outro/remover da próxima versão exige acção explícita, sem apagar o histórico. Referências livres de evidência são texto, sem fetch/importação ou afirmação de validação dos documentos referidos. - -Product_experiments mantém origem/versão/estado e liga a revisão actual por FK diferível; product_experiment_revisions conserva snapshots cifrados, operação/hash/autoria, unicidade e versões. Gatilhos PostgreSQL rejeitam alteração/remoção/truncagem do histórico, remoção de registos, recuo/salto de versão ou alteração da origem. O rollback da migração recusa dados já existentes. Autorização volta a ser verificada no serviço; autenticação/correio verificado/privacidade e throttle existentes aplicam-se às rotas. Não há novos perfis/aprovadores, dependência de IA, mensagens externas, distribuição de visitantes, cookies ou termos de pesquisa. - -Repetição de escritas conserva a primeira versão/autor/snapshot, mesmo após revisão posterior ou mudança de catálogo. Conteúdo diferente com chave já consumida dá conflito; versão desactualizada não substitui a actual. A interface mantém o rascunho em erro, consulta a versão actual e compara três vias: acompanha os campos editados, inclusive quando o autor os repõe deliberadamente no valor inicial; funde apenas os não editados, exige escolha nos conflitos reais e só adopta a base após revisão. Relatório/indicador corrente do coeditor são reutilizados, sem copiar payloads do cliente como autoridade. Histórico e exportação referem-se à versão consultada; o formulário histórico usa a versão dessa origem e bloqueia submissões, mesmo se o evento for disparado programaticamente. A gravação também fica bloqueada enquanto a comparação estiver pendente. Esquema indisponível é distinguido de zero registos e não desactiva os indicadores anteriores. - -Verificações finais: 18 Feature/271 asserções (11 casos novos e 7 regressões de indicadores), 7 frontend (5 novos e 2 anteriores), análise estática/Pint/tipos/lint/build aprovados. Primeira ronda: referência errada a tabela de interesses e teste de TRUNCATE interrompido por FK diferível ainda pendente; corrigida a referência pela entidade real e validada a FK antes de testar o gatilho, sem alargar os SQLSTATE aceites. A repetição de migrate:fresh revelou funções de gatilho conservadas após remoção das tabelas; a migração passou a usar CREATE OR REPLACE para as suas funções, sem enfraquecer os gatilhos ou alterar as guardas de QA. A repetição final instalou efectivamente o esquema sobre essas funções existentes e passou. Três diagnósticos de tipos iniciais resolvidos na origem, sem supressões. A revisão delimitou também a preservação das observações ao alterar o período e acrescentou prova específica. Todos os logs anteriores foram conservados. QA product_experiments_20261103_test, loopback 55441, guardas inalteradas; uma migração ensaiada apenas aqui. Após rollback, nove tabelas e eventos de auditoria do módulo vazios, com visibilidade/proprietário/RLS e três gatilhos/FK conferidos. Não é prova visual/login em navegador, concorrência em dois processos, experiência real com utilizadores ou instalação no destino. - -Saldo 03/11/2026: painel factual e registo manual versionado implementados/ensaiados localmente. Restam ligação transversal das alterações/editores ao registo, atribuição/execução de variantes e eventos por grupo com consentimento/âmbito definidos; aquisição/activação, pesquisa/zero resultados, comparação pública, CRM/qualificação/reuniões/diligência/propostas, fonte de investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte e pós-investimento. Pesos/pilotos de AUD-HUMAN-03 permanecem uma definição distinta; nenhum score inventado. Visual/login real e disponibilização/migração no destino continuam pendentes. - - -### 03/11/2026 — MASTER-e1169a77-0018: respostas de pesquisa, edições e recolha independente - -[PUBLIC-SEARCH-METRICS-20261103] Recolha agregada de respostas de pesquisa em nove canais públicos: oportunidades página/API e alias/educação, negócios, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Só primeira página com critérios explícitos e HTTP200; exclui HEAD/pré-carregamento/páginas seguintes/respostas de erro e respeita DNT/Sec-GPC. Sugestões, mapas, referências, exportações e consultas privadas não contam. Não guarda termos, filtros, IP, cookies, utilizadores ou identificadores de visitantes. Definições imutáveis por edição; contadores diários atómicos, consulta histórica sem somar edições diferentes, desconhecido distinto de zero. Relatório/experiências reutilizam a fonte, com tempo diário distinto do corte de eventos e sem aplicar indevidamente filtro de serviço. Falha de armazenamento/diagnóstico/bloqueio não invalida pesquisa; savepoint e limites técnicos restaurados. 32 Feature/501 asserções e 9 frontend, PHPStan/Pint/tipos/lint/build aprovados; duas sessões PDO provaram limite de bloqueio, dois processos efectivamente sobrepostos conservaram 200 incrementos/150 zeros. Recibo public_search_metrics_increment_20261103. Uma migração apenas em QA; nenhuma instalação/escrita activa. - -Fonte funcional preservada: upgrade do portal de investimentos v6 programacao.docx, SHA256 e1169a7743b13ff6c950d3ffd4672a2afea32e81da84885e11154b7d8de9241e, w:p 420. Recibos product_usage_metrics_increment_20261103 e product_experiments_increment_20261103 reutilizados; o registo e as contagens anteriores não foram reabertos como ausentes. AUD-HUMAN-03 continua separado, sem aprovação/garantia de sucesso por métrica. Inventário do código distinguiu as respostas públicas com total principal dos pedidos auxiliares, buscas privadas e fontes ainda não instrumentadas. A política de privacidade já previa estatísticas agregadas; foi acrescentada apenas uma descrição factual dos dados destes contadores e dos sinais respeitados, sem interpretação legal, cookie novo ou recolha de identidade. - -Nove canais: página de oportunidades, API de oportunidades (moderna e alias legado pelo seu próprio controlador), página de oportunidades educativas, negócios existentes, biblioteca/legislação, parcerias, carteira, zonas e conteúdos sectoriais. Os controladores assinalam o total realmente obtido no paginador/lista principal depois da validação. Middleware global conta uma vez apenas depois de uma resposta HTTP200 produzida, GET e primeira página, com critério explícito normalizado; navegação sem critérios, apresentação/sort, paginação seguinte, HEAD, prefetch e erros não entram. Filtros implícitos da página de educação não fazem dessa entrada vazia uma pesquisa. Metadados internos não são aceites de um endpoint cliente ou de um parâmetro de total. Mapas, referências, sugestões, exportações, gestão e consultas privadas não entram. Pesquisas nos restantes canais, incluindo fundos e correspondências internas de educação, permanecem saldo concreto. - -Unidade: respostas HTTP registadas, não pessoas, pesquisas únicas ou todas as interacções no navegador. Actualizar/repetir a primeira página conta nova resposta; cache/CDN pode não executar a aplicação, bots não são separados e uma falha de recolha pode omitir amostras. O denominador é sempre a base registada, com cobertura parcial explícita. Sem linhas não é zero pesquisas; canal nunca observado fica sem medição, enquanto zero respostas vazias com base positiva produz uma taxa0% legítima. Uma pesquisa com total principal0 e sugestões relacionadas mantém-se sem resultados principais; não se alarga o critério original para melhorar a estatística. Mantida a pesquisa plantio de algodao e as suas regras demonstradas. - -Product_search_counts contém apenas dia UTC, código fixo de canal, edição, número de respostas/zeros e primeiro/último instante agregados; não contém consulta, valores de filtros, actor, endereço, cookie, IP, token ou identificador de pedido/visitante. DNT:1 e Sec-GPC:1 omitem recolha. Product_search_definitions conserva uma vez a definição/vocabulário/exclusões/hash por edição; FK e gatilho impedem substituir ou remover a definição. Reutilização de uma edição com configuração diferente recusa novas contagens, regista diagnóstico redigido e assinala conflito ao gestor. Outra edição cria série própria; o relatório permite escolher as anteriores, usa a definição efectivamente conservada e não soma silenciosamente métodos diferentes. Sem backfill ou inferência de tráfego anterior. - -INSERT ON CONFLICT incrementa atómicamente os dois contadores e preserva os limites temporais com LEAST/GREATEST. A recolha usa transacção/savepoint e limites técnicos configuráveis de bloqueio/statement (predefinições100/300 ms), respeitando limites mais curtos do chamador e restaurando as definições originais. Falha SQL, bloqueio ou falha do próprio log não substituem a resposta de pesquisa nem deixam a transacção exterior abortada. Ausência da tabela desactiva a recolha de modo delimitado; configurar desligado conserva a consulta histórica. Diagnósticos incluem só canal/edição/classe de erro, sem mensagem/SQL/pedido ou valores pesquisados. Os limites técnicos não constituem SLA ou prazo de negócio. - -Painel ProductUsageMetrics com três indicadores de respostas/zeros/taxa e tabela por canal, edição seleccionável, base/cobertura/exclusões e exportação do snapshot aplicado. Contagens diárias são lidas no snapshot da transacção; o dia actual é parcial e não permite corte por fracção de segundo. Esse âmbito foi distinguido do corte de eventos do Balcão. O filtro de serviço não é associado por inferência às pesquisas públicas e deixa estes valores sem cálculo. ProductExperiments conserva o relatório contextual e a sua edição; a comparação de datas/serviço considera esses campos, sem rejeitar o novo metadado da edição de pesquisa. Não transforma esses totais em amostras de controlo/variante, causalidade ou score. Relatórios antigos sem a extensão continuam legíveis. - -Provas: 32 Feature/501 asserções (11 casos novos, 3 regressões da pesquisa rápida, 7 de indicadores e 11 do registo), 9 frontend (2 novos e 7 anteriores), PHPStan/Pint/tipos/lint/build aprovados. Primeira ronda passou30/32: faltava o ponto de recolha do alias, que usa outro controlador, e o exemplar legado sintético não continha os metadados exigidos; corrigidos sem remover validação/publicação, reduzir asserções ou alterar resultados. Provas cobrem os nove canais reais, ausência de PII na estrutura, exclusões, sinais de privacidade, erros de escrita/log, recuperação da transacção, datas, separação/imutabilidade de edições, desligamento/histórico e ausência de associação a serviço. Duas conexões PDO reais provaram o limite de bloqueio e reposição do funcionamento após libertação. - -Concorrência adicional: base exclusiva search_metrics_concurrency_20261103_test com apenas as duas tabelas novas; dois processos PHP/PIDs diferentes, 1.861790s de sobreposição real,100 chamadas sintéticas cada e retenção de300ms na primeira transacção para provocar disputa. Orçamentos técnicos alargados apenas neste ensaio. Resultado confirmado no PostgreSQL após commits:200 respostas,150 sem resultados e uma única linha/definição, sem perda de incrementos. Relógio e dados sintéticos explícitos; não representa visitantes reais ou aceitação. Essa base conserva a prova, sem limpezas de dados activos. - -QA funcional search_metrics_20261103_test em loopback55441, guardas preservadas; após rollback, onze tabelas vazias com proprietário/RLS/visibilidade e gatilho conferidos. As duas bases/provas anteriores de indicadores/registo são preservadas. Uma migração nova ensaiada apenas em QA, funções CREATE OR REPLACE compatíveis com a repetição de migrate:fresh, sem aplicar no destino. Não é prova visual/login em navegador nem instalação activa. - -Saldo 03/11/2026: painel factual, registo manual de experiências e contagens de pesquisa dos nove canais implementados/ensaiados localmente. A medição é de respostas HTTP registadas, não pessoas/pesquisas únicas, visitas ou utilização integral; recolha best effort e fontes não instrumentadas, incluindo fundos e correspondências internas, continuam identificadas. Restam aquisição/activação, comparação pública, correspondência CRM/qualificação/reuniões/diligência/propostas, investimento confirmado, conclusão versionada do roteiro, tempo projecto/submissão/etapas, abandono, satisfação/suporte/pós-investimento; ligação transversal dos editores/alterações e execução/eventos de variantes. Pesos/pilotos de AUD-HUMAN-03 são definição distinta, sem score inventado. Visual/login real e disponibilização/migração no destino pendentes. - - -### 03/11/2026 — AUD-CHECKLIST-01: selecção múltipla e declarações versionadas no Balcão - -[DESK-TYPED-FIELDS-20261103] Balcão suporta campos de selecção múltipla e declarações de consentimento no editor e na validação comum. Listas distintas de códigos de texto, incluindo 0, sem coerção de escalares; condições de inclusão e ancestrais aplicáveis. Declaração sem escolha predefinida ou herdada: aceitar/recusar/por responder são distintos; obrigatória exige resposta, não aceitação. Snapshot cifrado liga texto exacto/hash/escolha/actor/data/edição ao pedido; respostas ocultas conservadas não contam como declarações aplicáveis. Recibo usa opções/texto da versão antiga. Rascunho vazio permitido, reintrodução e sobrescrita de arrays/zero/recusa evitadas; retorno conserva campos autorizados e repetição de submissão não duplica. 27 Feature/347 asserções e13 frontend, PHPStan/Pint/tipos/lint/build aprovados;12 tabelas QA conferidas vazias com owner/RLS. Recibo desk_typed_fields_increment_20261103. Sem migração nova ou escrita no activo. - -Fonte: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo extraído481: tipos texto/número/data/lista/selecção múltipla/localização/anexos/consentimento, versões/vigência/condições/obrigatórios/limites/formatos/erros/rascunhos. Parágrafos161 e565 mantêm três camadas de obrigações, registo/publicidade e licenciamento sectorial e o modelo reutilizável. Identidade/hash do original novamente conferidos; sem reimportação ou alteração. Inventário anterior: editor/histórico, validação de perguntas aplicáveis e vigência já implementados em desk_forms_increment_20261102, desk_analysis_scope_increment_20261102 e desk_effective_dates_increment_20261102. Não foram reclassificados como ausentes. Os37 logs de vigência/métricas/registo/pesquisa acima reconferidos conservam bytes/hashes; recibos anteriores preservados integralmente. - -Âmbito: mesmos códigos de serviço, fontes, rotas, permissões e motor. O editor publica tipos multiselect/consent e statement (texto obrigatório exclusivo de consentimento); valida códigos, referências, ciclos e adequação equals/contains. A fonte territorial tem de continuar disponível sempre que a localização se aplica. Ao converter lista simples/múltipla, opções mantêm códigos e condições directas passam a igualdade/inclusão; a alteração é visível na comparação e exige confirmação de publicação, sem reescrever versões. - -O requerente pode guardar rascunho inteiramente vazio; omitir payload continua inválido e submeter exige respostas aplicáveis. Multiselect aceita lista distinta de até100 códigos string declarados, incluindo string0; escalar, objecto, código numérico, repetido ou desconhecido são recusados. A ordenação normaliza a semântica de conjunto, permitindo retry sem nova submissão. Ausência/null/lista vazia não satisfaz obrigatório; opções não seleccionadas não se tornam decisões implícitas. - -Consentimento conserva texto e escolha explícita accepted/declined; nenhum valor predefinido ou herança de perfil/contexto. Obrigatório exige aceitar ou recusar, sem forçar aceitação ou inventar um impedimento organizacional. Campo opcional por responder permanece desconhecido. Consentimento geral de submissão, competências, decisões de processo e licenças continuam separados. Cada declaração respondida e aplicável recebe no snapshot cifrado texto/label/hash/escolha/actor/instante e service_version_id gerados pelo servidor; metadados enviados pelo cliente não substituem esse vínculo. Declaração oculta conservada no payload não integra declarações aplicáveis. A interface permite limpar a resposta e respeita leitura/correcções autorizadas. - -Tipos e valores mantidos na reutilização: escolhas múltiplas, zero numérico e recusa não são apagados por trim/coerção ou por prefill sem substituição explícita; consentimento nunca é herdado, mesmo ao substituir outros dados. Rótulos de multiselect e texto/hash/escolha no recibo HTML provêm da edição ligada ao pedido; original técnico TXT continua a transportar o snapshot completo. Valores ocultos permanecem na secção histórica, sem activar descendentes; texto escapado, permissões e no-store mantidos. Publicar nova edição/texto/opções não modifica pedidos ou snapshots anteriores. - -Provas:27 Feature/347 asserções (11 novos casos + regressões editor/vigência) e13 frontend (6 novos casos + condições/vigência); análise estática em cache isolada sem supressões, Pint, tipos, lint e compilação terminados com sucesso. Avisos de compilação existentes relativos ao tamanho de chunks, fontaine opcional e tempo de plugins não são erros de execução. Primeira execução:24/25, falha por asserção com nome de evento incorrecto (submitted), corrigida; tipos unknown incompatíveis com contrato Inertia foram substituídos por união real das respostas, remoção de array_values redundante após sort conforme diagnóstico PHPStan. Ficheiros/logs de diagnóstico anteriores conservados em storage/app/private. - -QA exclusiva desk_typed_fields_20261103_test, loopback127.0.0.1:55441, role/owner investmoz_test e DB_URL vazio, sem alterar a guarda do TestCase. Doze tabelas sem linhas retidas após rollback, RLS/FORCE false conferidos com a identidade efectiva. Nenhuma migração nova, publicação real de formulários, conta real, mensagem externa ou escrita na base activa. Compilação local não equivale a disponibilização. - -03/11/2026: editor, histórico, vigência, selecção múltipla e declarações de consentimento do Balcão implementados/ensaiados localmente. Restam outros consumidores/contextos de checklist, cobertura transversal dos tipos/regras/limites/anexos, autosave/recuperação nos contextos ainda não demonstrados, três camadas de obrigações/registo/licenciamento por fonte e âmbito, visual/login real e disponibilização. Não equivale a homologação, licença ou parametrização integral. Conferência visual/navegador continua limitada pela ferramenta já documentada; HTTP/SSR/SQL não são aceitação visual/utilizadores reais. Próximo resultado: conferir consumidores e os restantes critérios p481/p161 sobre o mesmo motor, distinguindo lacuna real de capacidade já demonstrada. ACT-16 mantém resposta ainda nao; modelos societários continuam sem URL fornecida, sem impedir estes incrementos independentes. - - -### 03/11/2026 — AUD-CHECKLIST-01: gravação automática, recuperação privada e conflitos - -[DESK-AUTOSAVE-20261103] Balcão passa a guardar cópia de recuperação cifrada, por pedido/conta, após pausa de edição; conserva formatos ainda incompletos sem alterar o pedido principal, versões, decisões, notificações ou consentimento de submissão. Usa autoridade/definição/limites do VirtualDesk e guarda versões/identificador de tentativa para CAS e repetição idempotente. Comparação entre página, rascunho e pedido actual; intenções de edição/reversão e contexto da oportunidade conservados em conjunto. Respostas restritas em devolução, acesso revogado/consulta negados, falta da migração mantém gravação manual. Recuperar confirma nova base e limpa autorização/revisão do contexto. Corrigido guardar manual em dossier encerrado, em coerência com criação/anexos. 38 Feature/487 asserções e21 frontend, PHPStan/Pint/tipos/lint/build aprovados. Dois processos sobrepostos: uma gravação e um conflito, uma cópia v1/uma auditoria, principal intacto. Treze tabelas QA vazias com identidade/RLS conferidos. Recibo desk_checkpoint_increment_20261103; uma migração apenas em QA, sem escrita activa. - -Fonte já identificada: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, parágrafo481 exige gravação automática/recuperação, condições, formatos, limites e versões; p161/p565 mantêm os contextos/modelo próprios. Conferidos código e provas de editor/vigência/tipos, não recriados. A cópia automática faltava no pedido do Balcão; simulador e outros rascunhos existentes mantêm motores/âmbitos próprios. Constrangimentos técnicos resolvidos antes de activar: formatos incompletos não podiam passar pela submissão estrita, o save manual incrementava a versão principal e notificava intervenientes, resposta perdida exigia repetição idempotente e dois separadores não podiam sobrescrever silenciosamente. Não foram transformados em novas regras da Tempo. - -Implementação: tabela desk_request_checkpoints com uma cópia corrente cifrada por request_id/actor_id; versão própria, base_request_version (coluna request_version), chave/hash da tentativa e datas. FKs e versões positivas; rollback recusa apagar cópias retidas. Mesma autorização de escrita do VirtualDesk, estado draft/returned e dossier aberto, confirmação da versão principal sob lock. Representantes com escrita conservam cópias separadas; gestor/analista sem representação não lê a recuperação, membros de consulta/revogados não acedem. GET/POST /balcao-virtual/pedidos/{id}/rascunho são autenticados/verificados/privados/no-store, no mesmo throttle e CSRF. A cópia não concede papel/competência nem aprova/submete nada. - -Payload/razão/base/intenção cifrados; auditoria regista apenas versão da cópia e versão principal, sem respostas. Nenhum desk_event, notificação ou snapshot de declaração é criado por autosave. Reutilizada a validação comum: tipos/limites/opções/consentimento/território/keys continuam controlados; apenas formatos textuais de número/data/email/URL podem ficar incompletos na cópia. Gravação manual e submissão conservam os formatos estritos existentes e campos obrigatórios aplicáveis. Base do pedido é obtida no servidor; parâmetros de submissão/consentimento/base forjada são recusados. Campo removido/omisso/limpo e zero mantêm intenção; alterações são derivadas também no servidor. Em devolução, dados e intenção respeitam somente campos autorizados. - -Interface: pausa técnica2s e uma tentativa em curso; alterações entretanto digitadas mantêm-se e são guardadas a seguir. Pedido/consentimento global/revisão do contexto não entram na tentativa. Resposta perdida conserva exactamente corpo/chave da tentativa para repetição; não substitui essa tentativa por edições novas. Erro de validação espera nova edição, sem ciclo de retry; normalização do servidor não gera writes incessantes. Falha de rede/sessão mantém a página e permite repetir ou comparar; aviso de saída apenas quando há edições ainda não confirmadas. Sem localStorage/sessionStorage/cookie de respostas, nem alegação de escrita garantida no unload. Confirmar saída pode perder alterações ainda sem confirmação; estado explícito e cópia confirmada no servidor distinguem-se. - -Recuperação: compara base antiga, página, cópia da conta e versão principal actual. Edição deliberadamente revertida ainda é intenção; conflitos exigem escolha e campos não alterados adoptam a versão actual. Oportunidade/contexto associado recuperam-se como unidade, sem mostrar hashes/JSON técnicos no formulário. Listas apresentam rótulos da definição ligada ao pedido e declarações distinguem aceitação/recusa/desconhecido. Resolução é gravada com CAS antes de adoptar os dados/base na página, de modo que falha de rede também permite retry da resolução congelada. Recuperar limpa consentimento global e revisão/revisão do contexto; precisa de nova acção explícita para submeter. Estado encerrado/submetido impede nova cópia; a consulta autorizada continua disponível. Falta da migração conserva o percurso manual, sem declarar autosave disponível. - -Correcção conexa: VirtualDesk::save não verificava closed_at antes da escrita, embora criação e anexos já o fizessem. Agora rejeita gravação/submissão num dossier encerrado e preserva consulta/idempotência sem escrita do que já está submetido. Não redesenha fecho, alçadas ou sequência do workflow. - -Provas: 38 Feature/487 asserções (11 novos casos de recuperação +27 regressões editor/vigência/tipos) e21 frontend (8 novos +13 anteriores); PHPStan em cache isolada, Pint, tipos, lint e build terminados com sucesso. Incluem snapshot cifrado, privacidade por actor/organização/revogação, ausência de notificações/submissão, formatos parciais vs submissão estrita, vazio/zero/limpeza, CAS/retry/base principal, âmbito de devolução e migração ausente/rollback. Frontend exercita debounce/serialização/edições durante write, resposta perdida/normalização/validação, recuperação e versão/flags no pedido, contexto atómico e navegação pendente. Primeira ronda35/36: expectativa do teste omitia regime pré-preenchido efectivamente removido no payload; corrigida a expectativa sem esconder a intenção real. Diagnósticos anteriores mantidos em storage/app/private. - -Concorrência real: dois processos PHP/conexões PG sobrepostos por0.266754s na base desk_checkpoint_concurrency_20261103_test; A guardou, B recebeu409, checkpoint v1 e uma auditoria, principal v1/cifra original intactos. Dataset sintético de corrida preservado, não representa utilizadores reais. QA funcional desk_checkpoint_20261103_test, loopback127.0.0.1:55441, DB_URL vazio/role investmoz_test;13 tabelas sem linhas retidas e owner/RLS/FORCE conferidos após rollback. Guarda de testes intacta. 45 logs anteriores reconferidos;56 recibos anteriores conservados e deltas intencionais de VirtualDesk/página/teste de condições/política discriminados no novo recibo. - -Uma migração apenas em QA, nenhuma escrita/migração no activo ou comunicação externa. Política de privacidade recebe descrição factual/condicional da cópia cifrada, sem nova interpretação legal. Avisos de chunks/fontaine/tempos de plugins na compilação continuam não bloqueantes. 03/11/2026: Balcão tem editor/histórico/vigência/tipos múltiplos/declarações e gravação automática/recuperação privada demonstrados em QA. Restam outros consumidores/contextos de checklist e respectivos critérios p481, configuração transversal de limites/anexos/formatos/mensagens, camadas de obrigações gerais/registo/licenciamento por fonte e âmbito, observação visual/login real e disponibilização/migração no destino. Não é homologação nem parametrização integral. Conferência visual/login por navegador continua limitada pela ferramenta documentada; HTTP/SSR/SQL não substituem essa aceitação. Não se declarou cobertura integral da fonte p481, outros consumidores ou inventário legal das três camadas. Próxima acção: restantes limites/tipos/regras por consumidor e fonte, com os mesmos motores. Modelos societários sem URL e línguas nacionais sem tradução mantêm as respostas já registadas. - - -### 03/11/2026 — AUD-CHECKLIST-01: perguntas de anexos, limites e reutilização documental - -[DESK-ATTACHMENTS-20261103] Perguntas attachment do Balcão têm formatos/tamanho/quantidade por edição, condições e obrigatoriedade de submissão; reutilizam documents/desk_documents/scan/verificador binário existentes. Selecção por nome e versão, novo envio ou referência exacta de outro pedido do mesmo dossier por quem já tem escrita; sem UUID digitado ou nova cópia física. Vínculos separados preservam acesso do pedido de origem; fonte/validade declarada e proveniência conservadas, etapa da utilização vem do pedido. Rascunho/recuperação conservam suportes pendentes e respostas ocultas não contam como evidência aplicável. Submissão verifica permissão, scan/hash, bytes/tamanho/MIME reais, incluindo originais cifrados e metadados antigos desconhecidos medidos sem reescrever o cadastro. Recibo/snapshot usam os limites e ficheiros da edição aplicada. Conferência partilha verificador e ordem de bloqueio; anexos não se tornam valores financeiros por igualdade de identificador. 81 Feature/1110 asserções na regressão e20 específicos/251 finais (rondas sobrepostas, não somadas),38 frontend e estática/Pint/tipos/lint/build aprovados. Dois processos sobrepostos conservaram1 original/1 vínculo/1 evento, segundo envio409, principal intacto.16 tabelas QA vazias/owner/RLS e2 índices conferidos. Recibo desk_attachment_fields_increment_20261103; migração só em QA, sem escrita activa. - -Fonte preservada: segmentar processos v1.docx, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, p481 (campos/anexos/versões/vigência/condições/obrigatórios/limites/formatos/erros/rascunhos); p161/p565 mantêm as três camadas e o modelo documental. Hash do original reconferido, sem reimportação. Inventário inicial e recibo desk_checkpoint_increment_20261103 confirmaram editor/vigência/tipos/recuperação existentes; faltavam perguntas documentais com limites por edição. Não foram recriados os motores nem declaradas ausentes as capacidades anteriores. - -Editor: attachment, mime_types, max_size_kb e max_files, com declaração explícita de formatos/limites/obrigatoriedade, comparação/histórico pelo mesmo formatador, confirmação/motivo/base_version/vigência e auditoria. Tipos canónicos existentes conservados. Limites pertencem apenas ao tipo de anexo; formatos distintos por pergunta e nunca globalmente entre perguntas. Formatos suportados mantêm PDF/PNG/JPEG/TXT e limites técnicos anteriores; não se activou DOCX/formatos arbitrários. Condições comparam respostas apropriadas, sem usar anexos ou números como comparadores; fonte retirada/incompatível fica visível para correcção no editor. Pedidos antigos mantêm a FK e os limites da sua edição. - -Armazenamento/identidade: o payload guarda IDs de vínculo desk_documents, seleccionados por nome/versão/estado/referência; não duplica ficheiros. Uma migração troca a unicidade antiga case/document por dois índices parciais: uso global do dossier e uso por pedido. Todas as linhas/UUID/FKs/originais são conservados; rollback recusa perder usos que a regra anterior não consegue representar. Duplicação de upload é por bytes dentro do dossier, como já acontecia; não se fundem entidades/ficheiros por igualdade de nome nem por hash entre dossiers. O mesmo document_id pode ter vínculos específicos distintos e apoiar várias perguntas. Aliases do mesmo original não contam como dois documentos na mesma pergunta. O tecto de100 ficheiros do dossier conta originais distintos, sem consumir lugar por nova utilização do mesmo original. - -Reutilização por interface: os intervenientes com escrita no dossier recebem inventário autorizado dos seus pedidos; analista/gestor sem essa representação não recebe esse catálogo de reutilização. O inventário apresentado ao analista do pedido continua apenas o seu âmbito/global. O selector agrupa apenas utilizações do mesmo document_id com fonte/etapa/validade exactamente iguais, conserva alternativas de proveniência e envia reuse_link_id escolhido. Backend verifica origem e documento correspondentes e âmbito autorizado; não pede UUID, proveniência ou datas já disponíveis. Nova ligação conserva referência/validade declarada, recebe a etapa do pedido e regista em evento cifrado a origem exacta e os factos utilizados, sem expor o processo/interveniente antigo na cópia. O vínculo antigo não se torna global nem é alterado; analista do novo pedido continua sem acesso ao vínculo do pedido antigo. Validade declarada não é renovada ou interpretada como alvará válido por esta operação. O selector novo cobre o mesmo dossier; o formulário geral legado e catálogo entre dossiers ainda têm saldo específico. - -Validação: upload e documento reutilizado passam pelos limites da definição ligada ao pedido e pelo acesso actual. Só uma alternativa (ficheiro ou documento) é aceite. Referência existente é reutilizada; se não existir, pede-se apenas o dado em falta. Uploads ficam na quarentena e no job de scan existentes, sem cópia/novo job para reutilização de original. Rascunho e checkpoint conservam selecção pendente; estado oculto conserva IDs/metadados, sem exigir suporte nem o declarar aplicável. Submissão de pergunta activa exige suporte disponível/scan válido e verificação de autorização/hash/original pelo VerifiedDocumentBinary. Mede MIME e tamanho reais no original, incluindo após decifrar; metadados conhecidos divergentes não passam silenciosamente. Ausências antigas são medidas para o snapshot, conservando no cadastro e no snapshot a ausência registada, sem exigir reenvio, preencher zero ou reescrever a fonte. Campo com nome financeiro e tipo de anexo não entra no motor numérico nem gera perguntas de financiamento; regras financeiras numéricas continuam verificadas. - -Interface/recuperação: limites e estado visíveis, upload/reutilização só por acção explícita, sem submeter o pedido. A proveniência já registada fica em leitura; ficheiro/referência local continuam disponíveis após falha. Multipart reutiliza transporte/CSRF da aplicação, deixando boundary ao navegador e conservando JSON nos outros consumidores. Associação devolve inventário/versão/vínculo e indicação de repetição; repetir não substitui referência antiga. Ficheiro seleccionado no equipamento ainda não é suporte associado e não integra o rascunho do pedido até confirmar o envio. Selecção local de ficheiro ainda não enviado não é recuperável após fechar/recarregar, e o original continua no equipamento. Refresh de documentos conserva respostas, não duplica aliases nem apaga edições em curso; inventários de scan com a mesma versão do dossier deixam de esconder respostas mais recentes. Recuperação mostra nomes em vez de UUIDs e não herda anexos de texto de perfil/contexto. Guardas de navegação existentes abrangem envio em curso, sem guardar respostas em browser storage. Pedido encerrado mantém consulta mas não oferece edição/catálogo de reutilização. - -Histórico/recibo: field_attachments no snapshot cifrado captura rótulo/aplicabilidade, edição, limites e ficheiros/versão/hash/MIME/tamanho medidos/valores registados/referência/validade/etapa/estado efectivamente utilizados. HTML/TXT recuperam essa informação e distinguem perguntas ocultas de evidência aplicável. Nova publicação/opção/limite não reescreve submissão anterior. Conferência documental usa o verificador binário comum, incluindo cifra e autorização da origem, e bloqueia pedido antes de dossier como a gravação/associação, evitando a inversão de locks anterior. Mantêm-se revisão independente, auditoria e distinção entre conferência interna e acto oficial. - -Provas: regressão de81 Feature/1110 asserções (editor/vigência/tipos/checkpoint/análise/métricas/orientação/conferência), seguida de20 testes específicos/251 na versão final com selector/proveniência/fecho. São rondas sobrepostas e não uma soma de testes únicos.38 frontend, com8 novos casos de anexo/transporte/editor/reutilização e regressões dos consumidores existentes. PHPStan sem supressões, Pint, tipos, lint e build terminaram com sucesso. Ensaios validam formato/tamanho/quantidade, fonte seleccionada/datas sem reintrodução, permissões/revogação/âmbitos, pendente vs submissão, originais alterados/em falta/cifrados, medição de legado desconhecido, replay, versões/recibos antigos, rollback e migração ausente. Nova conferência de original cifrado foi exercitada com bytes sintéticos e corrupção posterior recusada. Estados de scan nas fixtures são sintéticos; não equivalem a novo ensaio real de ClamAV ou aceitação humana. - -Concorrência: dois processos PHP/conexões PG efectivamente sobrepostos por0.373360s, invocando o controlador com actor sintético autenticado na fixture isolada, conservaram1 document/1 vínculo/1 ficheiro físico/1 evento. A guardou, B recebeu409, dossier v2 e pedido v1/cifra intactos, hash físico conferido. Prova delimita controlador/DB/disco, não browser/visitantes reais; testes HTTP separados conferem autenticação/permissões. Dataset desk_attachment_concurrency_20261103_test e ficheiro privado de prova preservados. Primeira tentativa técnica perdeu o resolver de actor no rebinding de Request da fixture:0 documentos/0 vínculos/versões1 conferidos antes da v2, sem alterar autenticação da aplicação. Saídas falhadas conservadas em storage/app/private. - -Diagnósticos preservados: distinct do wildcard de MIME validava indevidamente campos diferentes, corrigido para unicidade dentro de cada pergunta; fixture PNG deixou de depender de GD; correcção de sintaxe da fixture e representação de MIME desconhecido como string vazia, respeitando NOT NULL real. Falhas assíncronas iniciais dos testes frontend eram espera insuficiente do harness, corrigida sem enfraquecer o fluxo. Logs anteriores às provas finais permanecem privados. - -QA funcional exclusiva desk_attachments_20261103_test, loopback127.0.0.1:55441, DB_URL vazio/role investmoz_test;16 tabelas sem linhas retidas após rollback, owner/RLS/FORCE e ambos índices válidos conferidos. Guarda do TestCase intacta. 57 recibos e57 logs anteriores reconferidos/preservados; deltas intencionais do checkpoint estão discriminados no novo recibo. Migração apenas em QA, sem migração/escrita activa, conta real, mensagem externa ou importação de exemplar oficial. Compilação conserva avisos conhecidos de chunks/fontaine/tempo de plugins, sem erro de execução. - -03/11/2026: Balcão tem editor/histórico/vigência, tipos múltiplos/declarações/anexos, recuperação automática e limites de ficheiro por pergunta demonstrados localmente. Restam outros consumidores/contextos p481, limites/formatos/mensagens parametrizados transversalmente, catálogo/selector legado geral e reutilização entre dossiers sem UUID manual, camadas de obrigações gerais/registo/licenciamento por fonte/âmbito, visual/login real e disponibilização/migração no destino. Os quatro MIME e tectos técnicos existentes (10MiB/100 ficheiros por dossier) não são parametrização integral da aplicação. Não é homologação, aprovação documental ou aceitação real. Conferência visual/login real continua limitada pela ferramenta já documentada; HTTP/SSR/SQL não são prova visual. Próxima acção: substituir entradas legadas por UUID por selecção de cadastros/documentos autorizados com o âmbito completo, depois restantes tipos/limites/contextos p481 e três camadas p161, sem apagar capacidades demonstradas. Os sete modelos continuam sem URL e ACT-16 sem tradução/prioridades, conforme respostas já registadas; não impediram este desenvolvimento. - - -### 03/11/2026 — AUD-CHECKLIST-01: pesquisa e selecção documental no âmbito autorizado - -[DESK-DOCUMENT-REUSE-20261103] O formulário geral do dossier e as perguntas de anexos permitem pesquisar documentos por nome, referência ou dossier e seleccionar a origem exacta, sem introdução manual de UUID. Catálogo privado paginado de 25 resultados cobre o âmbito já autorizado pelo servidor: originais enviados pelo próprio, documentos do dossier de destino e fontes dos seus dossiers pessoais. Ser membro de outra organização ou gestor/analista não concede acesso adicional ao catálogo. Um uploader sem acesso à origem organizacional só recebe os metadados do próprio ficheiro, sem referência, título ou datas desse dossier. Origem da oportunidade conserva a autorização actual, tanto na pesquisa como na associação. Nova utilização preserva referência/etapa/validade declarada e original físico; só pede referência ausente. A selecção documental da etapa usa o vínculo exacto e conserva os factos utilizados no workflow, mantendo clientes antigos por document_id. Pesquisa/paginação não associam documentos nem submetem pedidos. 56 Feature/766 asserções, 40 frontend, PHPStan/Pint/tipos/lint/build aprovados; 16 tabelas QA vazias e owner/RLS/índices conferidos. Recibo desk_document_reuse_increment_20261103; sem nova migração ou escrita activa. - -Inventário anterior reconferido: desk_attachment_fields_increment_20261103 conserva perguntas/limites/versões/recuperação e provas de concorrência do upload. Código e documentos mostravam o formulário geral por UUID, enquanto o servidor já autorizava reutilização de originais do próprio e de dossiers pessoais. Este incremento resolve esse saldo de interface, sem reapresentar a reutilização anterior como motor novo. Fonte segmentar processos v1.docx/p481 e p565, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, original reconferido; orientações de reutilização/percurso adaptativo no AGENTS.md, 23/10/2026. - -GET privado autenticado/verified documentos-disponiveis valida escrita efectiva e dossier aberto, pesquisa literal de nome/referência/título nas fontes acessíveis e pagina sem expor armazenamento, intervenientes, IDs dos dossiers de origem ou dados de fontes alheias. Direitos sobre o ficheiro não herdam dados da sua utilização numa organização. Upload próprio sem fonte autorizada permanece seleccionável, pedindo apenas a referência efectivamente ausente. O catálogo conserva alternativas por vínculo, com versão, etapa e validade declarada; não escolhe automaticamente outro exemplar nem renova validade. A autorização específica dos anexos de oportunidade é a mesma do VerifiedDocumentBinary e é conferida também antes da associação, sem ler ou divulgar bytes na pesquisa. - -Componente comum de pesquisa usado no formulário geral e nas perguntas de anexos. Enter pesquisa sem submeter o formulário envolvente; todos os botões de pesquisa/paginação são type=button. Paginar ou falhar conserva a origem deliberadamente seleccionada; editar a pesquisa retira resultados/cursor antigos para não saltar páginas da nova pesquisa. Resposta tardia de outro dossier é ignorada. Pesquisa e selecção não fazem escrita de negócio. A associação continua explícita, com consentimento, fonte exacta e verificação no servidor; limites por edição, original/scan/hash/cifra e snapshot anteriores continuam no mesmo motor. Mudar de ficheiro para origem existente limpa a selecção local de ficheiro para impedir envio posterior de um ficheiro oculto; falhas de associação mantêm a escolha actual. Nenhum ficheiro é guardado em browser storage. - -Suporte da etapa: lista os vínculos já associados por nome/versão/referência/validade. document_link_id é resolvido apenas no dossier e tem de corresponder ao document_id quando ambos são enviados. Workflow/evento conservam o vínculo e os factos de origem utilizados; alterações posteriores da origem não os reescrevem. Clientes que enviam só document_id continuam disponíveis, resolvendo de forma determinística o vínculo anterior; decisões/revisão independente não foram substituídas. A interface geral deixa de oferecer upload em dossier encerrado, que continua consultável. - -Provas em base sintética exclusiva desk_document_reuse_20261103_test, 127.0.0.1:55441, DB_URL vazio e role investmoz_test, guardas inalteradas. 56 testes Feature/766 asserções incluem 8 novos casos e regressão de anexos/checkpoints/recibos/orientação; 40 frontend incluem 10 novos casos de pesquisa/consumo. Testados âmbito, revogação/viewer/gestor sem representação, origem organizacional privada do próprio uploader, fontes pessoais/unlinked/deleted/alheias, origem de oportunidade sem autorização, filtros literais %/_, paginação, datas/proveniência, sem segunda cópia física, selecção por vínculo e compatibilidade por documento, leitura de dossier fechado e anonimato. PHPStan sem supressões, Pint, tipos, lint e build aprovados. Dezasseis tabelas sem dados retidos, owner/RLS/FORCE e índices de âmbito existentes válidos conferidos. A primeira ronda falhou apenas na fixture de paginação por reutilizar uma storage_key única; passaram a existir chaves/ficheiros sintéticos distintos, sem enfraquecer o schema. Logs iniciais preservados privados. - -58 recibos e 70 logs aceites preservados por hash; quatro deltas intencionais da implementação anterior discriminados no recibo. A prova anterior de concorrência continua a delimitar o upload e não é apresentada como novo ensaio do catálogo. Sem nova migração, escrita activa, conta real ou mensagem externa. Build conserva avisos não bloqueantes já conhecidos; prova de componentes/HTTP/SQL não é conferência visual. - -03/11/2026: selector geral do dossier, anexos por pergunta e suporte da etapa já não exigem UUID manual. Catálogo entre dossiers corresponde à autoridade existente, sem alargar o acesso a fontes de outras organizações. Continuam pendentes outros consumidores/formulários e a parametrização transversal de limites/formatos/mensagens, camadas de obrigações/registo/licenciamento por fonte/âmbito, conferência visual/login real e disponibilização no destino. Não é parametrização integral, homologação ou aceitação real. Próxima acção: conferir outros consumidores documentais e remover reintroduções nos respectivos percursos, sobre cadastros e permissões existentes; continuar os restantes critérios p481/p161 sem repetir capacidades concluídas. Modelos societários e traduções nacionais mantêm as respostas do proprietário já registadas, sem novo pedido genérico de autorização. - - -### 03/11/2026 — AUD-DESK-01/02: completar comprovativos no mesmo registo de pagamento - -[DESK-PAYMENT-EVIDENCE-20261103] A declaração manual já existia e permitia comprovativo pendente, mas faltava juntá-lo posteriormente sem repetir a referência. Agora o titular/representante com escrita acrescenta ou corrige o suporte do mesmo pagamento pending/internal_issue por vínculo seleccionado, versão, motivo e consentimento. Referência, montante, moeda e fonte do valor são conservados; a nova associação fica pending, sem confirmação bancária. Registo internal_verified não pode ser substituído pelo titular; eventual problema continua a ser registado pelo revisor independente no percurso existente. Proveniência documental, exemplar, versão/hash registados e validade declarada ficam nos eventos cifrados, sem segunda tabela/migração ou cópia física. Conferência valida o original comum e a correspondência ao exemplar associado; legado sem captura continua desconhecido, sem reconstituição retroactiva. Pesquisa/reutilização anterior preservada. Dossier encerrado mantém leitura dos pagamentos, sem novas operações manuais. 53 Feature/721 asserções e 47 frontend, PHPStan/Pint/tipos/lint/build aprovados; 18 tabelas QA vazias/owner/RLS/índices. Dois processos sobrepostos 0.392022s, em pedidos diferentes com a mesma referência, conservaram 1 declaração/evento; segundo com conflito 409 e pedidos principais intactos. Recibo desk_payment_evidence_increment_20261103, sem escrita activa ou nova migração. - -Inventário/preservação: recibo desk_document_reuse_increment_20261103 e os registos anteriores confirmam que declaração, selecção de comprovativo, conferência interna e comunicação manual já funcionavam. A lacuna concreta era declarar sem documento e tentar completá-lo: repetir a referência com document_id diferente devolvia409 e não havia acção própria. Não se recriou o motor de pagamentos nem se confundiu a fonte do valor/finalidade com a proveniência do ficheiro. Fonte funcional: AUD-DESK-01/02, orientação de reutilização do AGENTS.md e segmentar processos v1.docx p474/p479/p481, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5, original conferido. Estados/aprovações vigentes preservados; nenhuma taxa, responsável ou entidade externa inferida. - -A nova acção PUT comprovativo exige autenticação/verified/escrita actual no pedido, pagamento do mesmo pedido, dossier/pedido abertos, vínculo global ou desse pedido, versão corrente, motivo e consentimento. Ordem de locks: pedido, dossier, pagamento. Só suporta pending/internal_issue; internal_verified permanece protegido de substituição pelo titular. O revisor pode continuar a registar um problema no percurso existente, com fundamento e histórico. Correcção documental faz nova versão do pagamento e volta a pending, retirando apenas os indicadores actuais de conferência; revisões anteriores continuam nos eventos. Valores/ref/moeda/fonte não são reintroduzidos, editados ou novamente somados. Associar não cria novo ficheiro, scan ou pagamento. - -Documentos: o formulário de declaração e o de complemento escolhem o vínculo exacto por nome, versão e referência, em vez de aliases do mesmo original terem valores indistinguíveis. Backend aceita o document_id antigo, resolvendo um vínculo autorizado determinístico; IDs de outro pedido/caso ou origem de oportunidade sem acesso são recusados. A captura guarda nome, vínculo/original, versão/hash registados, categoria, etapa e validade declarada na associação, sob a cifra/auditoria existentes. Não é prova de integridade binária ou de dinheiro confirmado. Não copia montante/moeda/fonte do valor a partir do documento. Alterações futuras de referência/data não reescrevem a captura. Conferência positiva verifica binário/scan/autorização comuns e versão/hash face à captura, incluindo vínculos exactos; original substituído ou corrompido não é conferido como se fosse o anterior. Declarações antigas sem captura ficam legíveis e conferíveis pelas regras anteriores, com a ausência histórica explícita. - -Idempotência: operação documental identifica client_key/actor/pedido/pagamento/dados normalizados; repetição exacta confirma a operação anterior sem nova versão/evento. Alterar a operação com a mesma chave ou base obsoleta não sobrescreve. Mudanças deliberadas da selecção/motivo iniciam nova chave e renovam consentimento; falha conserva a escolha/motivo/chave para repetição. Versão de edição fica estável; actualização concorrente pede adopção explícita da nova base, conservando o texto e a selecção. A declaração de referência continua idempotente pelos factos já registados e serializa a referência no PostgreSQL, conservando a unicidade anterior em pedidos distintos com conflito tratado em vez de violação única500. - -Interface: entradas pendentes oferecem Juntar/Corrigir no próprio artigo; entradas conferidas e leitores não recebem essa acção. Declaração nova explica onde completar uma referência existente. Pagamentos e metadados congelados permanecem visíveis em pedidos/dossiers encerrados; criação, complemento, conferência e comunicação manual ficam bloqueados no servidor e respectivos formulários ocultos. As demais funcionalidades do pedido mantêm as próprias permissões. Não se declarou efectuado um envio de SMS/WhatsApp/email por registar manualmente uma comunicação. - -Provas: 53 Feature/721 na regressão de pagamentos/anexos/reutilização/orientação/recibos, incluindo 8 casos novos; 47 frontend, com 7 novos casos de complemento/idempotência/base concorrente/consulta histórica/ausência de reintrodução. PHPStan sem supressões, Pint, tipos, lint e build concluídos. Primeira ronda frontend43/46 e tipos detectaram uma referência a request no valor inicial de um parâmetro, antes de existir o nome local; corrigida para initialRequest e acrescentada regressão de props legadas/consulta sem edição. Provas falhadas e primeiro build preservados privados, sem apresentá-los como validação final. Nenhum bug pré-existente foi alegado para esse erro introduzido no incremento. - -Concorrência: dois processos PHP e conexões PG efectivamente sobrepostos 0.392022s invocaram o controlador de declaração, em pedidos/dossiers diferentes com a mesma referência sintética. Um guardou e outro409; 1 desk_payments/1 payment_declared, 25.50MZN pending, ambos os pedidos v1/cifras intactos. Actor autenticado sintético na fixture do controlador; não é prova de middleware/browser, cobertos separadamente pelos testes HTTP no âmbito demonstrado. Fixture desk_payment_race_20261103_test conservada. Este ensaio refere-se à declaração concorrente; versão/idempotência do complemento foram demonstradas por HTTP sequencial, sem alegar outro ensaio paralelo. - -QA funcional exclusiva desk_payment_evidence_20261103_test, loopback127.0.0.1:55441, DB_URL vazio e role investmoz_test; 18 tabelas vazias após rollback, owner/RLS/FORCE e índices existentes válidos conferidos. 59 recibos e 79 logs aceites preservados por hash; deltas do código anterior discriminados. Sem nova migração da funcionalidade, alteração de base activa, conta real, mensagem externa ou confirmação bancária. Avisos conhecidos de fontes/chunks/tempos de plugins conservados no build final com saída0. - -03/11/2026: comprovativo pendente ou corrigido pode completar a declaração existente sem repetir montante/moeda/fonte, com histórico e revisão independente. Restam outros consumidores e origens por formulário, atribuições/próxima acção/documentos por âmbito, parametrização transversal, conferência visual/login real e disponibilização no destino; integração bancária/entrega de mensagens não é declarada por estes registos manuais. Critérios gerais do Balcão/percurso não estão integralmente encerrados. A conferência visual continua pendente nas condições da ferramenta já documentadas; HTTP/componentes/SQL não são aceitação humana. Próxima acção: continuar os restantes consumidores/formatos/limites e percurso adaptativo sobre os motores e fontes existentes. Modelos societários/ACT-16 conservam as respostas anteriores, sem nova pergunta genérica. - - -### 03/11/2026 — AUD-DESK-01/02 e AUD-CRM-01: coerência dos registos encerrados, cancelamento e fecho pelo dono - -[DESK-CLOSED-LIFECYCLE-20261103] Por decisão expressa do proprietário, o dono registado executa agora o encerramento/reabertura, com acesso efectivo, versão, motivo, operação idempotente e histórico. Gestores/outros representantes não recebem esse poder por inferência. Resumo das pendências antes da confirmação e manutenção dos estados/payloads/documentos/tarefas/pagamentos, sem aprovação em cascata. Dossier com closed_at já bloqueava rascunhos/anexos/pagamentos, mas permitia transições, etapas, atribuições, mensagens e actualizações de tarefas. Reproduzidos HTTP200 nesses percursos, incluindo atribuição com MFA válido. Agora a guarda de estado comum e lock do dossier protegem esses comandos, preservando leitura/histórico e as permissões anteriores. Tarefas com vínculo CRM/dossier respeitam o fecho também no CRM; CRM sem tarefas vinculadas não consulta nem exige o Balcão. Listas de triagem/filas excluem encerrados e a interface retira decisões/atribuições/mensagens/etapas/conferência/tarefas sem aplicação. Cancelamento de rascunho/devolvido, já autorizado pelo servidor ao titular com escrita, fica disponível por motivo e confirmação explícita, conservando dados/documentos/histórico e o dossier. Sucesso mostra a versão efectivamente guardada; falha conserva edições. Justificação de correcção só é perguntada num pedido devolvido. 77 Feature/1016 na regressão, 15/202 específicos finais (rondas sobrepostas, não somar),64 frontend e estática/Pint/tipos/lint/build aprovados;20 tabelas QA vazias/owner/RLS/índices. Recibo desk_closed_lifecycle_increment_20261103, sem nova migração/escrita activa. - -Inventário reconferido no recibo desk_payment_evidence_increment_20261103: rascunhos/checkpoints, anexos, reutilização, declaração/complemento de comprovativos e operações manuais preservados. No código, closed_at já suspendia criação/edição e várias operações; faltava coerência em cinco comandos. Não foram recriadas essas funcionalidades nem inferido um procedimento novo de fecho. Fonte: decisão expressa do proprietário em03/11 sobre fecho/reabertura pelo dono, registada no AGENTS.md; orientação adaptativa/reutilização/preservação do AGENTS.md e segmentar processos v1.docx p474/p479/p481, SHA256 bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5; estados/competências aprovados e configuração existentes prevalecem. - -Reprodução: primeira ronda7 casos teve1 aprovado e6 falhas. Transição, etapa, mensagem e tarefa aceitaram200 em dossier encerrado; o ensaio inicial de atribuição recebeu403 porque a fixture administrativa não tinha MFA. Corrigida só a fixture pelo helper sintético já aceite, a reprodução específica demonstrou atribuição200 em vez de409. A guarda MFA e os perfis da aplicação não foram enfraquecidos. O caso aberto também verifica autodecisão negada, atribuição e transição legítimas, mensagem e ausência de acesso de outra conta. - -Servidor: assertOpen é uma guarda de estado comum, separada da autenticação/autorização de case/request; não se bloqueiam consultas por tratar o parâmetro write de acesso como se fosse uma ordem de mutação. Transição, atribuição, mensagem e tarefa bloqueiam o dossier antes de decidir/gravar; pedido continua antes do dossier onde ambos são necessários. Etapa usa o lock que já tinha e verifica o estado. Não criam revisão, mensagem, evento ou notificação de negócio quando recusados. Leitura/auditoria de consulta, recibos, documentos e histórico continuam pelas ACL existentes. Listas administrativas e fila de acompanhamento deixam de oferecer pedidos de dossier encerrado como trabalho activo. - -CRM partilhado: tarefa já ligada a lead e dossier conserva a autoridade anterior do CRM, mas a alteração verifica/locka o estado do dossier antes da actualização. Não é transferida, duplicada ou cancelada por arrasto. A apresentação devolve can_update sem persistir esse atributo virtual. Tarefas comuns sem ligação mantêm o percurso normal e não executam consulta à tabela desk_cases; teste com tabela temporariamente indisponível em QA prova independência. Não se declarou nova interface para associar automaticamente lead e dossier. Próxima tarefa de lead activo, MFA, contas e scopes mantêm as regras anteriores. - -Interface: dossier encerrado tem explicação de consulta; etapas/conferência ficam ocultas. Orientação continua calculável/legível, com pressupostos e acções de tarefa sem edição. No pedido, decisões, atribuições e mensagens obedecem ao mesmo operationsEditable das operações documentais; mensagens anteriores e pagamentos permanecem visíveis. CRM mostra título/estado/prazo e retira a actualização da tarefa vinculada encerrada. Pesquisa de fontes e notificações pessoais não se tornam operações de negócio bloqueadas por omissão. - -Cancelamento: a API já permitia ao titular/representante com escrita cancelar draft/returned por motivo; não é novo estado nem novo direito. O formulário usa a mesma transição, versão e auditoria, bloqueia clique/envio enquanto há gravação/associação em curso e explica o efeito sobre a última versão guardada. Não pede dados financeiros, documentos ou motivo de correcção que não se aplicam. Justificação de correcção mantém-se nos devolvidos. Falha não apaga texto/edições; resposta de sucesso repõe no formulário o payload efectivamente devolvido pelo servidor e retira consentimento, evitando apresentar alterações não guardadas como dados do registo cancelado. Pedido submetido não recebe esse cancelamento pelo titular. Acesso ao cancelado e dossier/documentos/histórico conservados; nenhuma reabertura ou cancelamento em cascata. - -Provas: 77 Feature/1016 na regressão de ciclo/anexos/comprovativos/reutilização/orientação/CRM/checkpoints, seguida de15 casos/202 na versão final com independência do CRM sem vínculos e a decisão do dono implementada. Rondas sobrepostas, não somadas como testes únicos.64 frontend, incluindo12 novos casos de cancelamento, sincronização do payload de sucesso, espera de recovery, permissões/contextos fechados, pergunta aplicável e leitura de tarefas/contexto. PHPStan sem supressões, Pint, tipos, lint/build concluídos. O teste anterior de vigência/refresh de serviços exigiu actualizar os mocks de importação e hooks da fixture para os componentes de documentos e estado agora usados na página; os dois ensaios63/64 e os seus erros de harness ficam privados. A aplicação não foi enfraquecida para os contornar. Sem novo ensaio concorrente alegado: recusa de versões/estados exercitada por HTTP sequencial e locks conferidos no código; provas paralelas de incrementos anteriores preservadas no seu âmbito. - -QA exclusiva desk_closed_lifecycle_20261103_test, loopback127.0.0.1:56441, DB_URL vazio e role investmoz_test.20 tabelas sem dados retidos, owner/RLS/FORCE e índices de documentos válidos. A indisponibilidade de tabela da fixture foi revertida em finally e o schema final reconferido. 60 recibos e 92 logs aceites preservados por hash; deltas de código conhecidos discriminados. Sem nova migração, conta real, escrita activa ou mensagem externa. Avisos conhecidos do build mantidos; saída final0. - -03/11/2026: coerência do closed_at e cancelamento de rascunhos demonstrados nos percursos identificados, sem alterar regras/perfis ou encerrar dossiers automaticamente. A operação de encerrar/reabrir o dossier completo foi implementada conforme a resposta expressa do proprietário: o dono executa essa acção. Mantêm-se acesso efectivo, motivo, versão e histórico, sem impor que todas as pendências estejam concluídas nem alterar estados de outros processos. Restam restantes consumidores/parametrização/percurso adaptativo, conferência visual/login real e disponibilização no destino. Fecho/reabertura: o proprietário respondeu que o dossier tem um dono e esse deve executar a acção. PUT privado/verified reutiliza user_id do dossier e exige a autoridade efectiva actual, incluindo representação vigente em organização. Outro gestor/analista/representante não substitui esse dono. O dono vê contagens locais de pedidos/tarefas/comprovativos pendentes; desconhecido continua por confirmar, sem zero inventado. Decide por motivo e confirmação, sem exigir conclusão de todas as pendências. Lock/versionamento do dossier, client_key e eventos cifrados preservam antes/depois/actor/motivo/contagens. Repetir exactamente não cria outra decisão; operação antiga repetida após reabertura devolve o estado actual e não volta a encerrar. Não modifica payload/workflow/estados próprios de pedidos/tarefas/pagamentos. Reabertura não reabre pedidos cancelados/encerrados. Formulário adopta estado/versão do servidor só no sucesso, preserva motivo/chave na falha e exige adopção explícita se a base mudar. Depois de sucesso retira ficheiro local não associado/consentimento antigo para não os reutilizar invisivelmente após reabrir. Não é aprovação por silêncio, licença, conferência de dinheiro ou fecho em cascata. Conferência visual/login real continua pendente nas condições da ferramenta já registadas; componentes/HTTP/SQL não são aceitação humana. Prosseguir com os restantes consumidores autorizados e manter ACT-16/modelos societários nas respostas já registadas. - -### 03/11/2026 — AUD-CRM-01: edição concorrente sem sobrescrever alterações recentes - -[CRM-RECORD-VERSIONS-20261103] Investidor, contacto, qualificação/atribuição de lead e estado de tarefa passam a enviar automaticamente a revisão que foi apresentada. PortalAudit confere-a sob lock, devolve erro de versão e só incrementa a revisão numa alteração efectiva. As colunas version_no já existiam; o trigger existente apenas actualiza updated_at. Contactos partilhados mantêm uma revisão comum. A interface compara dados actuais com a edição, exige escolha nos campos em conflito e conserva alterações deliberadas, incluindo regressar ao valor inicial e editar durante a gravação. Preservados conversão idempotente, consentimento, não duplicação, responsáveis autorizados, próxima acção e fecho de dossiers pelo dono. 45 Feature/594 asserções, 75 frontend (10 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL com espera por lock comprovada: uma gravação, um conflito de versão, um evento; contacto sentinela preservado. 23 tabelas QA vazias, owner/RLS conferidos. Recibo crm_record_versions_increment_20261103; sem migração ou escrita activa. Visual/destino e restante cobertura do CRM continuam parciais. - -Origem e inventário: instruções permanentes de preservação e edição deliberada; segmentação bf26caeee043, parágrafos474/479/481. Reutilizados os registos investors/contacts/leads/tasks, a auditoria e os quatro formulários existentes. O inventário do incremento anterior conserva dossiers, encerramento/reabertura pelo dono, anexos, comprovativos, rascunhos, tarefas e permissões. Conferidos os hashes dos recibos/logs anteriores e o delta explícito do código, sem nova regra de competências. - -Uso: «Comparar com os dados actuais» recupera apenas os dados desta página e conserva o formulário. Campos alterados por ambas as operações exigem «Usar valor actual» ou «Manter minha alteração». A adopção é explícita; a gravação seguinte utiliza a revisão comparada, novamente sujeita a concorrência. Sucesso repõe os dados efectivamente devolvidos pelo servidor, preservando edições feitas durante a espera. O fundamento anterior do lead fica em consulta e não é reutilizado como fundamento de um evento novo. Nenhuma cópia de contactos é guardada em localStorage. - -Compatibilidade e limites: os quatro PATCH privados de edição exigem agora version, enviado pela interface sem pergunta adicional ao utilizador; cliente anterior sem esse metadado recebe422 e deve actualizar a página. Coordenar backend/frontend na entrega. Não se trata de nova versão de edição de documentos/fontes, nem de histórico integral dos textos pessoais na auditoria. A política de incremento restringe-se às quatro tabelas CRM em PortalAudit; restantes domínios conservam a política existente. A conservação da edição é em memória da página/recarga parcial/erros, sem promessa de recuperação após fechar o navegador. Os acessos existentes da gestão são preservados; esta correcção não acrescenta MFA ao CRM. Guia/tarefas mantém a sua verificação de versão já existente. - -Provas: servidor CrmRecordVersionsTest(8), CrmIntakeTest(6), DeskClosedLifecycleTest(9), DeskCaseStateTest(6), InvestorGuidanceTest(16),45/594 no total; frontend75 incluindo10 casos novos de comparação, reversão deliberada, actualização parcial, normalização de email, edição em voo, fundamento por evento, registo exacto e envio de revisão nos quatro formulários. O ensaio concorrente chama o serviço com duas ligações/processos reais numa segunda base sintética; não substitui os testes HTTP de autorização nem aceitação visual. Base principal crm_record_versions_20261103_test (55441/investmoz_test),23 tabelas sem linhas retidas após rollback; base concorrente crm_record_race_20261103_test mantém explicitamente a fixture sintética/sentinela para prova. Nenhuma base activa alterada, migração nova, mensagem externa ou instalação. Compilação aprovada com os avisos anteriores de fonte opcional/chunks/tempo de plugins. - -Próxima acção: continuar o inventário e implementação autorizados, mantendo AUD-CRM-01 parcial até conferir os percursos/filas por perfil e apresentação visual aplicáveis. Não repetir a decisão do dono, as conversões ou os resultados já demonstrados como novas lacunas. Línguas nacionais e sete minutas oficiais continuam dependentes das definições/exemplares que o proprietário ainda não possui. - -### 03/11/2026 — AUD-DASH-01 e AUD-CRM-01: acompanhamento pessoal no painel - -[DASHBOARD-WORK-QUEUE-20261103] O painel passa a reunir manifestações, pedidos do Balcão e tarefas CRM atribuídos à pessoa autenticada, usando as autoridades de consulta existentes. Colecções separadas, totais/prazos sobre o conjunto completo, ordenação por prazo/ID e cinco linhas por página com paginação independente. Ligações directas ensaiadas; tarefas apontam ao formulário existente do lead. Fecho do dossier suspende a presença dos pedidos/tarefas vinculados na fila activa, conservando estados/histórico. Auditor não recebe o resumo de gestão que os destinos já lhe negavam. Regressão final41 Feature/694,82 frontend (7 novos), estática/Pint/tipos/lint/build aprovados;26 tabelas QA vazias, owner/RLS conferidos após libertação do lock do processo de testes. Recibo dashboard_work_queue_increment_20261103; nenhuma migração nova/escrita activa. Restam outros acompanhamentos por perfil, visual e entrega. - -Origem e inventário: AUD-DASH-01 pede acções permitidas por perfil, indicadores e destinos reais; AUD-CRM-01 pede acompanhamento interno com responsável/próxima acção. A navegação e os painéis de domínio já existem, mas dashboard não reunia estas atribuições. Reutilizados interest_requests.assigned_to, desk_requests.analyst_id e tasks.assignee_user_id/lead_id, ScopedPortalAdministration, acesso directo do Balcão e o gate da gestão CRM, sem criar perfis, concessões, prazos ou outro workflow. O incremento anterior de edição concorrente foi reconferido antes da alteração; guardas, versões, contactos, documentos, operações de dossier e provas anteriores preservados, com delta explícito para a âncora do formulário de tarefa. - -Âmbito: fila pessoal, mesmo para gestor; as colecções não são somadas para não sugerir pessoas/processos únicos. Manifestações exigem a consulta efectiva existente, incluindo confirmação MFA válida; pedidos atribuídos usam a consulta já permitida ao analista; tarefas CRM usam o acesso de gestão já existente, sem concedê-lo por mera atribuição. Ausência de autoridade/módulo omite a colecção, sem zero inventado. Revogação, expiração MFA e condição de auditor são reavaliadas em cada pedido. O resumo global antigo deixa de ser enviado a um auditor que acumule o gate legado de gestão. Nenhuma alteração aos gates globais ou às decisões autorizadas. - -Prazos e estados: ausência de prazo aparece «Sem prazo definido»; instante igual ao da leitura não é atraso. Datas em Maputo e instante de actualização explícitos. Estados apresentados pelos dicionários já existentes da manifestação/tarefa e configuração do Balcão; aceitação interna não é mostrada como licença/aprovação externa. Concluídos/cancelados e exclusões lógicas pertinentes saem da fila activa. Pedidos e tarefas vinculados a dossier encerrado ficam em consulta/histórico, sem mudar estados nem reabrir por arrasto. CRM sem vínculo continua disponível quando o Balcão opcional está ausente. - -Navegação: cada colecção tem cinco registos por página, mantendo os parâmetros das outras páginas. Prazo seguido do ID dá ordenação estável; página antiga fora do novo total regressa a uma página existente após mudanças de atribuição/estado. A fila não reserva trabalho, não decide pedidos, não envia avisos nem executa tarefas. Leituras são dinâmicas e os destinos voltam a verificar acesso/versão/estado no momento da acção. As páginas anteriores do investidor, oportunidades e indicadores continuam acessíveis no âmbito já autorizado. - -Provas: regressão final41 casos: DashboardWorkQueueTest(11), DashboardOpportunityAccessTest(3), CrmRecordVersionsTest(8), DeskClosedLifecycleTest(9), DeskCaseStateTest(6) e InvestorPathTest(4). Os cenários novos cobrem visitante/não verificado/investidor, operador por atribuição, totais separados, destinos, ausência de escrita/auditoria, fecho/conclusão/exclusão, perda de atribuição, paginação sem duplicações, prazo nulo/igual ao instante, expiração MFA/auditor e CRM sem Balcão, além dos parâmetros inválidos. Sete casos frontend novos e os75 anteriores,82 no total: continuidade do investidor/gestão, dicionários de estados, ausência/zero, datas, paginação, texto escapado e âncora real. Base dashboard_work_queue_20261103_test,55441/investmoz_test;26 tabelas sem linhas retidas, RLS e proprietário conferidos depois de adquirir o lock que exclui testes vivos. Ficheiros de diagnóstico anteriores conservados. Build com os avisos já conhecidos de fonte opcional/chunks/tempos de plugins. - -Limites e próxima acção: não declara dashboard integral de todos os perfis, todos os contadores de domínio ou a matriz concluídos. Restam outros consumidores/filas, verificação visual/móvel/teclado no navegador e disponibilização no destino. Prosseguir com as lacunas autorizadas da matriz, sem repetir as aceitações existentes, sem nova aprovação organizacional para escolhas técnicas e sem instalar dados sintéticos ou migrar o activo. - -### 03/11/2026 — AUD-CRM-01 e AUD-DASH-01: próxima acção consistente no CRM e na orientação - -[CRM-NEXT-ACTION-20261103] Reproduzidas três falhas: uma tarefa futura em dossier encerrado permitia qualificar o lead e concluir a última tarefa disponível (HTTP302), e a orientação permitia concluir a última tarefa de lead activo sem substituta (HTTP200). Agora a disponibilidade de trabalho é partilhada por CrmTask/CrmNextAction, qualificação, conclusão pelos dois percursos, fila pessoal e indicadores factuais. A tarefa conserva estado/histórico, mas não serve de próxima acção enquanto o dossier está encerrado; reabertura pelo dono recupera a disponibilidade sem reescrever a tarefa. Os dois comandos serializam pelo mesmo lead antes de alterar tarefas. Regra de prazo futuro já existente preservada; interface explica a pendência e liga ao formulário existente. 75 Feature/915 asserções e foco final2/42 sobreposto,87 frontend (5 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real CRM/orientação: uma conclusão, uma recusa por falta de outra próxima acção, uma acção futura mantida e lead/dois dossiers preservados.29 tabelas QA vazias, owner/RLS/lock conferidos. Recibo crm_next_action_increment_20261103; nenhuma migração/escrita activa. - -Origem e inventário: AUD-CRM-01 já exige responsável autorizado e próxima tarefa antes de encerrar a última; a decisão expressa de03/11 mantém o fecho/reabertura do dossier exclusivamente no dono, sem alterar em cascata estados de tarefas. Código e recibo dashboard_work_queue_increment_20261103 reconferidos antes da alteração. O painel já retirava tarefas de dossiers encerrados, mas os testes de qualificação/conclusão do CRM contavam-nas; a resposta da orientação não reutilizava a guarda CRM quando uma tarefa possuía ambos os vínculos. As três falhas HTTP foram guardadas antes da correcção. Não se criou nova regra de competências nem uma condição para o dono encerrar o dossier. - -Execução: scope CrmTask.availableForWork reúne estado open/in_progress, ausência de exclusão lógica e dossier associado aberto, quando existe. CrmNextAction acrescenta o prazo futuro e o mesmo lead para as condições que já o exigiam. Tarefas de outro lead, sem prazo, vencidas ou eliminadas não substituem a próxima acção futura. A qualificação conserva as regras anteriores de responsável, motivo, versão e lead convertido; desqualificação continua sem exigir outra tarefa. Na conclusão de um lead new/qualified, CRM e orientação verificam a mesma substituta excluindo a tarefa em conclusão. Orientação sem lead e resposta associada a lead arquivado conservam o percurso autorizado anterior. A disponibilidade não inventa novas regras de vigência/perfil do responsável. - -Concorrência e autoridade: ordem de locks dossier, lead e tarefa nos dois comandos; a orientação recupera o lead associado e confirma novamente o vínculo da tarefa antes da decisão. Os comandos continuam sujeitos aos seus acessos e versões anteriores. O ensaio com dois processos PostgreSQL e dois intervenientes sintéticos comprovou espera real pelo lock do lead: CRM concluiu uma tarefa, a orientação reavaliou após essa decisão e recusou concluir a outra, que permaneceu aberta/versão1; somente uma revisão/evento de auditoria acrescentados. Os dois dossiers e o lead mantiveram os respectivos dados/estados. A ordem do fecho pelo dono é independente: o dono pode suspender um dossier mesmo que a sua tarefa fosse a próxima acção do lead. Não se bloqueia esse fecho nem se cria/reabre outra tarefa por arrasto; a falta posterior de próxima acção fica visível para acompanhamento. - -Consulta e formulários: fila pessoal reutiliza o scope do modelo; contagem de atrasos CRM e avisos determinísticos locais deixam de tratar tarefas suspensas como trabalho disponível. O aviso missing_next_action conserva a distinção anterior entre ter trabalho pendente disponível e ter prazo futuro; tarefa disponível vencida pode ter alerta de atraso sem ser tratada como inexistente. Filtros de classificação/privacidade dos indicadores opcionais não foram alargados, nem foram copiados dados privados para métricas. Os comandos normais funcionam com IA/SuiteCRM desligados. No lead, contagem informativa de tarefas futuras e ligação ao formulário de próxima acção, com singular/plural correctos; nenhuma pergunta adicional, estado automático ou bloqueio geral que impeça desqualificação. Histórico de tarefas suspensas e erro por versão permanecem visíveis. - -Provas e preservação: CrmNextActionTest(11), CrmIntakeTest(6), CrmRecordVersionsTest(8), DeskClosedLifecycleTest(9), DeskCaseStateTest(6), DashboardWorkQueueTest(11), InvestorGuidanceTest(16) e AiGatewayTest(8),75/915. Foco final2/42 sobreposto confirma a leitura/avisos após a consulta tipada e regras sem modelos externos; não somar rondas. Frontend87, incluindo5 casos novos sobre pendência, contagem/singular, histórico suspenso, resposta antiga sem metadado e lead desqualificado. Base crm_next_action_20261103_test,55441/investmoz_test;29 tabelas sem linhas retidas, dono/RLS conferidos e lock do processo de testes adquirido antes de contar. A segunda base crm_next_action_race_20261103_test conserva explicitamente fixtures sintéticas para prova. HTTP/factos determinísticos não substituem observação visual ou aceitação de utilizadores. - -Limites e próxima acção: observar a apresentação/recuperação dos erros no navegador, disponibilizar no destino no âmbito próprio e continuar os restantes percursos/filas da matriz. A regra não garante uma tarefa futura para sempre: prazos expiram e o dono pode suspender o dossier posteriormente. Não automatiza decisão/qualificação nem cria responsáveis ou tarefas. Não declara o CRM/dashboard ou a auditoria integralmente concluídos; fontes/modelos e decisões concretas ainda pendentes permanecem no inventário existente. - -### 03/11/2026 — AUD-PART-01: edição de parcerias sem perda de dados e recuperação comparada - -[PARTNERSHIP-EDITING-20261103] Corrigidas omissões destrutivas no editor/API: disponibilidade existente, organização, campos escalares, locais e origens não enviados são conservados; valores explicitamente vazios continuam a remover o dado. Disponibilidade opcional agora visível, distinta do prazo de recepção de interesses. Actualização da página conserva edições e compara divergências por campo/grupo antes da adopção explícita. Repetição de criação não confirmada reutiliza o comando/chave originais, exige representação actual e não volta a validar sector activo numa repetição já executada. Gravações novas conservam validação do sector, versões409 e estados autorizados, incluindo publicada→rascunho.19 Feature/148 asserções (10 novos),103 frontend (16 novos), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 registo/1 evento/1 auditoria/1 notificação, mesma identidade/versão e disponibilidade conservada.45 tabelas QA vazias com owner/RLS/lock conferidos. Recibo partnership_editing_increment_20261103; sem migrações/escritas activas. - -Origem e inventário: AUD-PART-01 e orientação expressa de23/10 sobre reutilizar dados e preservar edições deliberadas, explicar divergências/impactos e aperfeiçoar componentes existentes. A referência segmentar processos v1.docx, parágrafos479/481, conserva a distinção entre estados, reabertura e recuperação/versionamento; este incremento não declara executadas todas as variantes. Recibo CRM anterior, código e provas aceites reconferidos antes de continuar. Reprodução inicial: quatro cenários expuseram três defeitos distintos: perda de disponibilidade em duas edições; repetição pelo criador sem representação actual devolvia200; repetição exacta após desactivação de sector devolvia422. O quarto cenário produziu erro de asserção por chave availability desaparecida, não HTTP500. Reproduções e diagnósticos anteriores foram conservados. - -Servidor e reutilização: actualização parcial conserva raízes, campos permitidos do payload e relações omitidos. Apenas campos explicitamente enviados são substituídos; null/texto vazio, false e listas vazias mantêm significado próprio. Relações omitidas não são apagadas/recriadas nem novamente resolvidas; indicar novas origens/locais continua sujeito às guardas existentes. Conservar a referência não concede acesso ao documento. Preservados autor original, hash de criação, chave, versão, relações e eventos anteriores. Não se inventou novo requisito de NUIT, organização, documentos ou MFA para o rascunho pessoal; teste de utilizador não verificado confirma o percurso. As opções de edição draft/returned/rejected/published e a passagem de published a draft continuam as existentes. - -Autoridade e repetição: o replay procura a criação anterior dentro do mesmo lock por actor/chave, verifica a autoridade efectiva actual e a correspondência ao hash original; sem nova escrita/evento/notificação. O criador que perdeu representação após transferência não recupera acesso por conhecer a chave. Validação de sector activo aplica-se depois do ramo de replay, conservando a verificação para escritas novas. Validação estrutural básica continua a anteceder o replay; não se promete compatibilidade com qualquer futura alteração de esquema. O ensaio final usa dois processos reais e espera demonstrada pelo lock, conservando um único efeito mesmo com o sector desactivado após o primeiro commit. A prova de serviço concorrente complementa, sem substituir, os19 testes HTTP. Retirar explicitamente uma organização pode terminar o acesso futuro do representante conforme a regra anterior do autor original; a interface explica esse efeito, sem criar novo dono/perfil. - -Editor e formulário: removida a remontagem pela versão; estado mantém-se durante actualização e na transição de criação para edição. Comparação usa valores normalizados e versões, apresenta dados actuais e locais e pede escolha explícita nos conflitos. Locais, origens e critérios são grupos comparados atomicamente; ordem de conjuntos não cria divergência falsa. Edições deliberadas que regressam ao valor inicial continuam reconhecidas. Escolhas independentes não desaparecem ao resolver outro campo. Alterações batched de payload e remoções por identidade usam o estado corrente. Respostas inválidas, de outra identidade, mais recentes ou readonly não apagam a edição nem autorizam gravação. Erro409 mantém o texto e pede actualização/comparação. - -Criação e resultado incerto: a tentativa conserva uma cópia do comando efectivamente enviado. Repetir usa essa mesma chave/conteúdo, preservando à parte edições feitas depois do envio. A confirmação identifica o registo e conserva essas edições para a próxima actualização; não cria outro registo. A confirmação de gravação usa os dados canónicos devolvidos, incluindo normalização de espaços, e não toma alterações concorrentes como suas. Há aviso ao sair com alterações e recuperação em memória durante o percurso; não existe novo localStorage nem garantia de autosave, recuperação após fechar/recarregar o navegador, regressar pelo histórico ou voltar a autenticar. Falha403 é apresentada como impossibilidade de confirmar com o acesso actual, pois um redireccionamento posterior pode falhar após escrita autorizada. A revisão de proposta publicada explica a volta a rascunho e o circuito existente; não afirma que uma proposta privada estava publicada no catálogo público. - -Provas e preservação: PartnershipEditingTest10 e PartnershipExchangeTest9,19/148; frontend103 com16 novos casos no componente/editor/helper efectivamente transpilados, modelo de hooks incluindo identidade/key e limpeza de efeitos. Não é ensaio visual num navegador. PHPStan sem supressões, Pint--test, tipos, lint sem avisos e build exit0; avisos de fontes/chunks/tempos já conhecidos não são falhas. Diagnósticos iniciais de fixture/harness/tipagem e de caminhos JSON foram retidos sem os confundir com falhas actuais. A fixture geográfica positiva usa identificador técnico sintético compatível com a guarda de referências; não representa lugar oficial importado, hierarquia validada ou divulgação real. Base principal partnership_editing_20261103_test,55441/investmoz_test,45 tabelas conferidas sem linhas e lock adquirido antes da contagem. As duas bases de concorrência retêm fixtures sintéticas identificadas; prova final v2 após a última alteração do servidor. - -Limites e próxima acção: histórico de eventos conservado não equivale a arquivo imutável do texto integral de cada versão. Não se acrescentaram migrações, permissões, publicações nem alterações no destino activo. Manter prova visual/entrega e restantes variantes de sala, partilha documental e formulários no inventário existente. Línguas nacionais e os sete modelos oficiais continuam dependentes das fontes/definições já pedidas; não se inventaram traduções ou minutas aprovadas. AUD-PART-01 permanece parcial. - -### 03/11/2026 — AUD-PART-01: responsáveis dos marcos ligados aos participantes efectivos - -[PARTNERSHIP-PARTICIPANTS-20261103] Selector de responsáveis dos marcos agora reutiliza a regra efectiva de representação das duas partes. Pessoas identificadas pelo nome e lado da parceria, sem introduzir IDs, e-mails ou novos papéis. Autores de participações pessoais mantidos; representantes actuais de organizações seleccionáveis; viewers, vínculos revogados e organizações eliminadas não são fontes de atribuição. Leitura conserva o responsável anterior e informa perda de representação; substituir exige escolha explícita e evento com IDs anterior/novo. Salas em negociação, encerradas ou apenas de consulta não oferecem edição de marcos.25 Feature/211 asserções (6 novos),1413 frontend em regressão ampla (6 novos), PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_participants_increment_20261103; sem migrações/escritas activas. - -Origem e inventário: AUD-PART-01 exige candidatura isolada, sala e marcos com papéis reais. A guarda de gravação já permitia qualquer participante actualmente autorizado, mas o selector continha apenas os dois autores originais; uma organização cujos autores perderam representação ficava sem opção válida no formulário, apesar de possuir representantes competentes. O resumo só mostrava ID do responsável. Reconciliados código, recibo partnership_editing_increment_20261103 e provas anteriores antes de continuar; nenhuma entrega anterior foi reclassificada como ausente. - -Reutilização de autoridade: representa() e o novo catálogo contextual partilham uma única query de vínculos/organização actuais, com os mesmos papéis de escrita admin/manager/officer e as mesmas exclusões anteriores. O catálogo só é calculado depois de validar o acesso à sala. Não há directório público nem novo endpoint para procurar pessoas fora das duas partes. A participação pessoal selecciona apenas o seu autor, independentemente de outras organizações a que pertença. A mesma pessoa que representa ambas as partes tem um ID e dois lados; pessoas não são fundidas por igualdade de nome. O catálogo devolve apenas id/name/parties; sem e-mail, credenciais, MFA ou lista de perfis. Contas apenas de consulta recebem lista de atribuições vazia. Estado do vínculo no momento da consulta não concede autoridade futura. - -Formulário e estado: novos marcos pedem selecção explícita de um participante autorizado. Em marcos existentes mantém-se o ID efectivamente atribuído; o nome é consultado no cadastro actual, não um nome congelado na data original. Perda de representação fica indicada, sem transferir responsabilidade por arrasto. A opção anterior permanece visível/desactivada até escolha explícita de substituto, conforme a validação que já existia no comando. Consulta não altera linha, versão ou evento. Botão/envio recusam escolha indisponível na lista actual; o servidor continua a reavaliar a autoridade, incluindo quando o vínculo é revogado/rebaixado depois de abrir a sala. Não se criaram novas competências ou responsabilidades automáticas. Editor de marcos aparece somente nos estados agreement_recorded/agreed/execution já aceites pelo servidor, conservando a consulta do histórico nos restantes. Não se alterou a regra das confirmações do acordo, nem os estados/fecho da conexão ou de outras candidaturas. - -Rastreabilidade: evento partnership_milestone.changed.v1 e envelope de auditoria acrescentam previous_responsible_id/responsible_id. A reatribuição é um comando versionado explícito; versões antigas, responsável de outra sala/organização ou participante sem representação actual continuam recusados. Não se reescrevem eventos anteriores e não se promete um arquivo integral de todas as versões do texto/evidência do marco. Exibir o nome actual do cadastro não transforma essa pessoa em representante actual nem concede acesso ao responsável histórico. A regra de consulta da sala e a regra de atribuição continuam distintas. A listagem é informativa; não se acrescentou garantia de serialização de revogações além das guardas/locks existentes. - -Provas: PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9,25/211 na ronda final. Casos novos cobrem representantes de ambos os lados, resposta mínima, revogação do autor e substituição expressa/evento, participações pessoais, deduplicação de representação dupla, consulta/encerramento, escolha desactualizada após downgrade, pessoa alheia, versão antiga e organização eliminada. Prova inicial da lacuna:3 falhas de asserção e1 erro do teste por propriedades ainda ausentes em respostas200; não quatro falhas HTTP. Primeira fixture sem tipo da parceria foi corrigida antes dessa reprodução e o diagnóstico conservado. Frontend1413 em todos os ficheiros *.test.mjs;6 casos novos exercitam os componentes transpilados, opções por nome/lado, escolha explícita, atribuição anterior, estados sem edição, lista alterada sem troca silenciosa e nome indisponível. Não é aceitação visual em navegador. PHPStan passou sem supressões antes da formatação, que alterou somente o estilo do teste; Pint--test final, tipos e build exit0. Avisos de fontes/chunks/tempos existentes mantidos. - -QA e limites: base partnership_participants_20261103_test em127.0.0.1:55441/investmoz_test,45 tabelas conferidas vazias depois do processo terminal, com lock adquirido, proprietário e RLS verificados. Sem nova migração, escrita activa, notificação externa ou importação de pessoas reais. Preservados65 recibos e143 provas aceites anteriores; deltas de código explicitados no novo recibo. A recuperação/comparação integral dos formulários de acordo, candidatura e marcos continua como saldo próprio: este incremento não remove o remontar da sala pela versão nem promete conservar todas as edições noutra actualização. Também não implementa novas notificações dirigidas aos representantes em substituição dos destinatários históricos. Próxima acção: continuar esses percursos e as variantes restantes da matriz, observar a apresentação no navegador e disponibilizar no destino no âmbito próprio. AUD-PART-01 permanece parcial. - -### 03/11/2026 — AUD-PART-01: recuperação dos formulários da sala e repetição sem efeitos duplicados - -[PARTNERSHIP-ROOM-RECOVERY-20261103] Sala deixa de remontar pela versão; acordo, marcos, mensagem e ficheiro preparados conservam-se durante actualizações. Alterações deliberadas exigem comparação por campo/contexto e escolha explícita nos conflitos; controlos intocados acompanham os dados actuais sem pedir comparação de um formulário vazio. Estado/acesso posteriores limitam novas gravações e conservam preparação; aviso único antes de sair. Novos marcos e documentos usam chave/conteúdo por actor/sala no histórico existente, com lock da sala; mensagens reutilizam a chave já existente. Repetição confirmada é leitura, mesmo após encerramento, sem novos marcos, bytes, partilhas, eventos ou scans.34 Feature/310 asserções (9 novos),foco final2/37 sobreposto para caixa UUID,1429 frontend em regressão ampla e22 focados finais sobrepostos (16 novos e6 adaptados), estática/Pint/tipos/lint/build aprovados. Dois processos PostgreSQL:1 marco,1 documento/ficheiro,2 eventos/auditorias e1 pedido de scan; lock do marco demonstrado, seguido de replay documental.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_room_recovery_increment_20261103; sem migrações/escritas activas. - -Origem e inventário: orientação expressa de23/10 sobre reutilização, conservação de edições e explicação de divergências/impactos, e AUD-PART-01 (versões, sala, marcos e participantes). O incremento anterior identificara a remontagem de RoomPage pela versão e dos marcos pela versão, bem como o saldo de recuperação dos formulários. Confirmadas essas chaves no código e reconferido o recibo partnership_participants_increment_20261103 antes de alterar. A proposta funcional e os estados existentes foram preservados; não se criaram competências, etapas ou aprovações. Chaves/hashes de comandos são uma escolha técnica de repetição segura, sem nova pergunta de negócio ao utilizador. - -Editor e comparação: identidade da sala mantém-se durante actualizações preservadas pelo Inertia; navegação normal para outra sala continua a ter o ciclo próprio da página. Resposta de outra sala não reinicializa nem autoriza gravar no destino diferente; outra conta recebe editor próprio. Acordo e cada marco têm bases/versões independentes, estado/acesso corrente e geração das edições. Mudança remota não sobrescreve texto, inclusive retorno deliberado ao valor original, edição posterior ao envio e resolução de vários conflitos. Comparação apresenta valores guardados/locais e exige opção explícita por campo em conflito; adopção incorpora apenas actualizações compatíveis e conserva o que foi escolhido. Controlos sem qualquer edição ou comando incerto seguem o estado actual, evitando confirmação redundante num novo marco vazio. Erros409, falha de rede, resposta inválida ou inesperadamente mais recente conservam a preparação e suspendem a gravação até recuperação/comparação. Actualizar dados iguais à base pode resolver uma pendência transitória sem inventar uma versão nova. - -Estados e sentido da acção: fecho/perda de escrita mantém preparação visível/desactivada em memória, sem a transformar numa nova autorização. Marco que estava em edição não é desmontado quando a sala muda para negociação ou estado terminal; formulários limpos continuam omitidos nesses estados. Atribuição histórica conserva nome do cadastro actual e indicação correcta: lista de atribuição indisponível num estado não é, por si só, prova de perda de representação. Acções de acordo usam versão revista e motivo; só registar altera título/condições. Confirmar/iniciar/renovar/cancelar/concluir continuam a agir sobre o instrumento actualmente guardado, apresentado acima; a interface avisa quando existe instrumento local ainda por registar. A confirmação conserva edições locais não enviadas e não certifica assinatura jurídica. Não se mudou quem pode confirmar, a sequência de estados ou a regra dos marcos pendentes. - -Mensagem e ficheiro: cada tentativa conserva o comando originalmente enviado, incluindo File imutável e autorização de partilha. Repetir após incerteza usa esse comando/chave; texto, selecção de ficheiro ou consentimento preparados depois ficam para uma próxima operação e não são apagados pela confirmação anterior. Resposta válida exige a sala esperada e identificação do efeito nos dados devolvidos. O campo nativo do ficheiro só é limpo quando o envio correspondente foi confirmado, mantendo uma selecção posterior; identificação do ficheiro preparado permanece visível. Mensagens e marcos devolvem a chave apenas ao respectivo actor; documento é reconciliado pelo identificador devolvido em flash e pela ligação/autor na sala. Estas referências não dão acesso à contraparte, não substituem autorização de download e não activam o documento. - -Servidor/idempotência: PartnershipMilestones e PartnershipRoomUploads reutilizam a autorização do PartnershipExchange, os locks da sala, repositório privado e eventos/auditoria existentes. Novos marcos/documentos com chave UUID registam no evento a referência do comando e hash normalizado do conteúdo; sem nova tabela/migração nem ledger concorrente. A pesquisa actor/sala/tipo/chave e a gravação/evento são serializadas pelo mesmo lock. Caixa maiúscula/minúscula da UUID é normalizada na entrada HTTP. Repetir conteúdo diferente sob a mesma chave devolve409. Pedidos legados sem chave continuam compatíveis e não recebem por inferência garantia de idempotência. Actualizações de marco mantêm a versão e as regras de responsável/evidência anteriores. Não se adiciona um novo evento ou se reescreve o marco actual ao recuperar a criação, mesmo se o marco já tiver versão posterior. - -Recuperar após encerramento: a autoridade actual de escrita continua obrigatória; o replay exacto já executado é identificado antes de rejeitar novas escritas pelo estado terminal. Isso permite confirmar uma operação anterior, sem nova mensagem, ficheiro, marco ou alteração de estado. Se não existe operação anterior, permanece409 no estado terminal; conta de consulta ou representação revogada não recupera autoridade pela chave. Upload repetido não volta a autorizar partilha posteriormente revogada e não volta a pedir scan. Novos bytes continuam privados/quarentenados e sujeitos à análise/hash/ACL de download já existentes. Falha transaccional remove apenas o ficheiro recém-criado sob o prefixo autorizado, preservando originais anteriores. A confirmação de envio não prova execução do worker/scan, autenticidade ou vigência. Não se implementou novo mecanismo de reencaminhamento se a fila falhar após commit; esse acompanhamento operacional continua separado. - -Provas: PartnershipRoomRecoveryTest9, PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9:34/310. Foco final2/37 sobreposto confirma a normalização UUID após a ronda principal, sem somar casos/asserções de rondas. PHPUnit cobre efeito único, hash/conteúdo/ficheiro/consentimento, escopo por actor, compatibilidade legada, leitura após encerramento, versões antigas, revogação, privacidade de chaves, bytes/quarentena e rollback com original preservado. Frontend1429 em todos os *.test.mjs e22 focados finais sobrepostos depois da correcção do rótulo contextual de estado,16 casos novos de recuperação e6 casos anteriores do selector adaptados ao modelo que executa também os hooks reais. O harness respeita identidade/key, frames separados, efeitos/limpeza e respostas de Inertia, mas não é um navegador/ensaio visual. Os diagnósticos de tipagem, redundância de comparação, aviso do harness e resposta de sala errada foram conservados; corrigidos sem supressões. PHPStan/Pint--test/tipos/lint e build exit0; avisos conhecidos de fontes/chunks/tempos mantidos. - -Concorrência e QA: base principal partnership_room_recovery_20261103_test,127.0.0.1:55441/investmoz_test;45 tabelas conferidas vazias após o foco final terminal, com lock do processo adquirido e owner/RLS verificados. Disco fake dos testes não é o repositório activo. Base separada partnership_room_recovery_race_20261103_test conserva fixtures sintéticas e ficheiro original próprios. Dois processos e conexões PostgreSQL distintos; espera pelo lock da sala demonstrada na criação do marco. Primeiro processo criou marco e documento, o segundo recuperou ambos:1 marco,1 ligação/documento/ficheiro,2 eventos e2 auditorias acrescentados,2 notificações de marco e1 pedido fake de scan. Os bytes mantiveram o hash. O ensaio não forçou uma disputa independente entre dois uploads simultâneos; essa leitura documental seguiu a disputa do marco. Estados preparados directamente nessa fixture comprovam serialização do serviço; os34 testes HTTP exercitam separadamente o workflow/autoridade/validação. Sem envio externo ou pessoas reais. - -Preservação e saldo:66 recibos e152 provas anteriores conservados;11 fontes do incremento e deltas autorizados identificados no recibo. Este registo substitui apenas a pendência anterior da remontagem/recuperação dos formulários da sala, sem apagar a prova histórica. Preparação permanece em memória, com aviso único antes de sair; não há novo localStorage/autosave nem promessa de recuperação após fechar/recarregar o navegador, perder a página ou voltar a autenticar. Eventos não passam a guardar todo o texto de cada versão do marco. Continuam pendentes candidatura/avaliação por consumidor, apresentação visual, destinatários actuais das notificações, variantes documentais/sala e disponibilização no âmbito próprio. Línguas/modelos oficiais já pendentes não foram inventados. AUD-PART-01 e auditoria global permanecem parciais. - -Último delta de apresentação: pending de marco tem rótulo Pendente, distinto de pending legado da proposta. A fixture foi alinhada ao dicionário real e reproduziu1 falha entre16 casos;22 casos finais da sala/selector passaram após a correcção. A ronda ampla1429 e este foco22 sobrepõem-se e não devem ser somados. Build/tipos/lint finais correspondem a esse fonte. - -### 03/11/2026 — AUD-PART-01: candidaturas identificadas, recuperação e avaliação no contexto revisto - -[PARTNERSHIP-CANDIDACIES-20261103] Corrigidas quatro falhas reproduzidas: omissão apagava organização/declarações; actualizar outra candidatura podia atingir o registo errado; faltava autorização efectiva por candidatura na resposta; repetição de submissão já executada devolvia409. Agora identidade explícita, omissões conservadas e remoções explícitas, versões/consentimento/representação anteriores mantidos, snapshots privados de submissão/avaliação e repetição actor/parceria/tipo/chave sem nova decisão. Formulários mantêm preparação e comparam divergências; declaração e avaliação têm bases próprias, perda de acesso conserva apenas preparação local e não concede autoridade. Versão da parceria/hash de critérios conferidos no servidor para novos clientes, retirada independente da janela/requisitos. Ordem de locks parceria→candidatura partilhada.47 Feature/401 asserções (13 novos),1451 frontend (22 novos), estática/Pint/tipos/lint/build aprovados. Concorrência real:1 ressubmissão/1 avaliação antiga recusada409,1 evento/auditoria,2 notificações locais e replay só de leitura.45 tabelas QA vazias, owner/RLS/lock conferidos. Recibo partnership_candidacies_increment_20261103; sem migrações/escritas activas. - -Origem e inventário: AUD-PART-01 exige consentimento, versões, candidatura isolada, retirada, sala e marcos com papéis reais; orientação expressa de23/10 exige reutilizar informação e conservar edições deliberadas, explicando divergências. Reconferidos código, recibo partnership_room_recovery_increment_20261103 e provas aceites antes de continuar. Candidacy remontava pela versão; actualização escolhia o primeiro registo por autor OU organização, substituía todo o payload e assumia organizaçãoNULL quando omitida. Reproduções: perda de organização (HTTP200), edição de candidatura organizacional retirada afectava a pessoal com a mesma versão (HTTP200 com ID errado), ausência de can_edit por candidatura e replay após avaliação devolvia409. Não se classificaram as quatro como erros500. - -Identidade, autoridade e dados: novos pedidos identificam a candidatura seleccionada; o servidor confirma parceria, acesso actual, versão e estado. Pedidos anteriores sem ID continuam pelo mesmo percurso quando existe um único candidato possível; ambiguidade é409, sem seleccionar por ordem nem alterar outra candidatura. A organização omitida e as declarações/classificações autorizadas omitidas são conservadas; null/vazio expressos continuam a remover informação. A proposta e o consentimento aceite mantêm as exigências anteriores; não se infere novo consentimento de dados antigos. Nenhuma condição de empresa, NUIT, documento, verificação de e-mail ou MFA foi acrescentada ao percurso pessoal. Autor original permanece; retirar explicitamente uma organização não transforma o representante em autor. O formulário explica que essa escolha pode terminar o seu acesso, de acordo com a regra pessoal já existente. - -Consulta e capacidades: resposta identifica can_edit de cada candidatura usando a mesma owns/representação do comando; viewers podem consultar no âmbito anterior mas deixam de ver acções de escrita/retirada. canStartInterest reflecte a unicidade anterior por autor/parceria, evitando oferecer nova candidatura a um autor cujo registo deixou de estar acessível por representação. Não se alteraram os predicados de visibilidade da parceria: numa proposta que deixou de estar disponível à conta, a página pode continuar indisponível mesmo quando a API reconhece uma operação anterior. Não se expuseram rascunhos ou novos detalhes privados para contornar isso. A lista de candidatos mantém o isolamento anterior e as chaves de comandos são devolvidas apenas ao actor que os emitiu. - -Submissões e auditoria: nova submissão continua a reiniciar a avaliação actual e a passar ao estado submitted, conforme o comportamento existente. A interface explica esse impacto. Antes de o fazer, o evento existente conserva snapshot da versão anterior: organização, proposta, declarações, avaliação, motivo, estado e versão; conserva também a versão submetida. Decisões conservam o snapshot anterior e o contexto realmente utilizado: versão da parceria, algoritmo/hash, pesos, obrigatoriedade, evidências e resultado de correspondência. Não se alteraram pesos, limiares ou o significado de desconhecido. Campos alheios ao contrato da avaliação deixam de ser persistidos; autoria/data da avaliação continuam a ser fixadas no servidor. Estes snapshots são privados, a partir deste incremento; não reconstituem versões antigas sem prova nem constituem ainda um leitor completo de revisões para todos os actores. - -Concorrência do conteúdo revisto: novos clientes enviam a versão da parceria e o hash dos pesos ao decidir; o servidor confere-os dentro do lock da parceria antes da escrita. A candidatura mantém o controlo próprio da versão. Mudança de declarações, requisitos ou pesos não autoriza aplicar silenciosamente uma avaliação velha. Legacy sem os novos tokens mantém o protocolo anterior; não se promete a mesma guarda adicional a pedidos que não os enviem. Retirada continua dependente da candidatura/representação actual e não da publicação/janela/pesos da parceria. Ordem de locks foi uniformizada em parceria, depois candidatura, eliminando a inversão entre ressubmissão e avaliação neste percurso. Não se criou aprovação por silêncio, nova competência ou passagem automática de desconhecido a incumprido. - -Recuperação e interface: componentes deixam de remontar por versão. Preparação é mantida por candidatura e por acção, com geração de alterações inclusive retorno deliberado ao valor inicial, eventos batched e escrita posterior ao envio. Comparação por campo conserva declarações compatíveis só após adopção explícita; estado/evidência do mesmo critério são uma unidade. Critérios retirados permanecem identificados em preparação local, sem integrar o pedido actual; descarte local é explícito e não apaga auditoria. Dados intocados acompanham actualizações, evitando confirmar formulários vazios. Após criação, o mesmo editor passa ao ID/versão do registo e conserva o texto preparado depois de enviar, sem duplicar formulários. Se a candidatura sai da lista por perda de acesso, só a preparação local permanece desactivada; outra conta tem editor próprio. Um único aviso de saída cobre as preparações independentes. Não há novo localStorage/autosave ou recuperação garantida depois de fechar/recarregar, sair da página ou autenticar novamente. - -Decisões e repetição: cada tentativa nova usa UUID e hash do conteúdo no histórico existente, sem tabela/migração paralela; busca e evento serializados pelo lock da parceria. UUID é normalizada na entrada. Recuperar repete o comando original, respeitando autoria/representação actuais, sem reiniciar avaliação, duplicar sala/evento/notificação ou reescrever decisões posteriores. Mesmo nonce com conteúdo diferente é409. Motivo ou avaliação preparados após o envio são conservados. Acções que não guardam avaliação enviam assessment vazio e usam a avaliação guardada, com aviso visível sobre edições ainda por guardar. Respostas de outra parceria, incompatíveis ou com dados posteriores não apagam preparação nem conferem autoridade. Ao comparar um contexto novo, o utilizador pode preparar uma nova tentativa explícita; não é uma repetição automática da acção anterior. Leitura por chave não reabre a janela de submissão nem a candidatura. - -Preservação e apresentação: comparação com o ecrã anterior detectou a necessidade de manter peso, obrigatoriedade, evidência e explicação de cada critério; esses elementos foram repostos e recebem teste específico. Intervalo indeterminado apresenta Por determinar, sem percentagem falsa, zero inventado ou aprovação. O restante detalhe público, origens/geografia, moderação e ligações à sala foram conservados. Hash comparativo normalizado por finais de linha confirma que PartnershipExchange fora de interest/decideInterest não mudou; os métodos públicos delegam numa única implementação de candidaturas. A hipótese de opções duplicadas por vários vínculos activos foi rejeitada pelo índice parcial imz_memberships_user_id_organization_id_uq, definido em2026_09_24_012000_investmoz_indexes.php. A fixture inválida foi corrigida, sem remover o índice nem manter uma alteração desnecessária da query; entidades diferentes com nome igual permanecem distintas. - -Provas: PartnershipCandidaciesTest13, PartnershipRoomRecoveryTest9, PartnershipParticipantsTest6, PartnershipEditingTest10 e PartnershipExchangeTest9,47/401 na ronda final. Casos incluem identidade exacta/ambígua/estrangeira, omissão/remoção, snapshots, consentimento, replay normalizado e posterior a decisões, perda de representação, critérios/versão antigos, retirada fora da janela e nomes iguais sem fusão. Frontend1451 em todos os *.test.mjs,22 novos casos com componentes/hooks efectivamente transpilados e dicionário de rótulos lido do fonte real. O modelo respeita frames, keys, efeitos, respostas e limpezas, mas não é prova visual num navegador. PHPStan sem supressões, Pint--test, tipos/lint e build exit0; avisos de fontes/chunks/tempos já conhecidos mantidos. Rondas anteriores e falhas de fixture/harness/comando foram retidas sem as declarar falhas actuais ou somar casos. - -Concorrência real e isolamento: base principal partnership_candidacies_20261103_test,127.0.0.1:55441/investmoz_test;45 tabelas conferidas sem linhas após o último processo terminal, com lock adquirido e owner/RLS verificados. Base separada partnership_candidacies_race_20261103_test retém actores e workflow sintéticos. Dois processos/conexões PostgreSQL: nova submissão detém o lock da parceria, avaliação antiga espera, submissão grava versão2 e a avaliação recusa409 sem deadlock nem sobrescrita.1 evento/1 auditoria/2 notificações acrescentados; snapshot anterior e declarações novas conservados, avaliação não reaplicada e replay da submissão sem escrita. O delta final acrescentou contexto de matching à auditoria; o ramo de conflito da prova concorrente continua anterior a essa escrita. Não há pessoas reais, comunicações externas, alterações no activo ou instalação de migracões. - -Saldo:67 recibos e165 provas anteriores conservados,10 fontes do incremento e deltas autorizados identificados. AUD-PART-01 e a auditoria integral continuam parciais. Ficam o leitor/variantes de história por actor, outras transições de papel, destinatários actuais das notificações, apresentação visual, recuperação além da página e disponibilização no âmbito próprio. O formulário de publicação/moderação da parceria é outro consumidor, não declarado recuperável por este incremento. Fontes/modelos/traduções já pendentes permanecem no inventário existente; nenhuma dependência genérica de aprovação foi criada para continuar o desenvolvimento. - -### 03/11/2026 — AUD-PART-01: consulta privada das versões e decisões das candidaturas - -[PARTNERSHIP-HISTORY-20261103] Leitor dos eventos existentes, sem recalcular ou reconstruir valores históricos com dados actuais. Acesso actual à candidatura/parceria e conferência adicional do âmbito guardado em cada versão para o candidato. Página privada com comparação antes/depois, avaliação e parâmetros realmente guardados, links no painel e candidatura; paginação estável por cursor cifrado vinculado à conta/candidatura. 57 Feature/488 asserções (10 novos),1460 frontend (9 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias, identidade/owner/RLS/lock conferidos. Recibo partnership_history_increment_20261103;68 recibos e177 provas anteriores preservados. AUD-PART-01 permanece parcial, sem instalação/escritas no activo. - -Origem: requisito AUD-PART-01, documento segmentar processos v1.docx (parágrafos479/481: estados, reabertura, versões e histórico) e orientação de23/10 para conservar dados efectivamente utilizados. Reutilizados eventos/snapshots e autorização owns existentes, sem novo perfil, migração, concessão ou alteração de elegibilidade. Este incremento implementa a leitura que estava explicitamente pendente no recibo anterior; não declara todos os fluxos do módulo concluídos. - -Autoridade: o responsável actual pela parceria pode consultar as candidaturas do processo pelo predicado de leitura existente. Candidato exige acesso actual à candidatura e a cada snapshot pelo user_id imutável e organization_id efectivamente guardado. Outro candidato, moderador sem esse vínculo ou representante revogado não recebe consulta por inferência. Troca entre organizações A/B não transfere o texto de A para representantes de B. Versão sem âmbito histórico conhecido fica scope_unknown para o candidato; não é inventada participação pessoal. Lacunas antigas mantêm-se parciais para o responsável autorizado. - -Dados: a página apresenta estados, declarações, consentimento, avaliação e motivos realmente registados; campos ausentes distinguem-se de null/vazio expressos. Parâmetros congelados de matching, algoritmo/hash, pesos, obrigatoriedade, evidência e explicação provêm apenas do evento da decisão; não se aplica Matching.explain actual. Zero válido permanece zero; parâmetro malformado/ausente permanece desconhecido. Os nomes de pessoas/organizações e rótulos da lista de avaliação provêm do cadastro/catálogo actual e a interface declara essa origem; não são apresentados como nomes históricos congelados. Os rótulos do contexto de matching são os guardados nesse contexto. - -Privacidade e navegação: rota GET autenticada protegida pelo middleware privado existente, Cache-Control private/no-store e histórico Inertia cifrado. Não expõe nonces, hashes de comandos, IDs de eventos, contador global, título/offer/payload actual da parceria. Candidatura autorizada continua consultável após arquivo da parceria por um link próprio, sem alargar a visibilidade da página original. Link à parceria só é oferecido quando publicada ou acessível pelo responsável. Cursor cifrado vincula actor/candidatura, revalida acesso em cada pedido e pagina10 eventos por aggregate_version; inserções posteriores não duplicam versões ao avançar. Não há botões de restaurar, reaplicar ou decidir neste leitor. - -Provas:10 novos Feature cobrem contexto congelado após mudança de configuração, snapshots antes/depois, concorrentes/moderação/anonimato, viewer/revogação, mudança A/B, legado parcial,21 decisões e inserção entre páginas, cursor estrangeiro/inválido, arquivo sem rascunho exposto, resposta Inertia e consulta sem escrita, parâmetros malformados. A primeira ronda teve9/10: o pedido Inertia sem X-Inertia-Version recebeu409 de actualização de recursos. A fixture passou a enviar a versão real do middleware; nenhuma guarda da aplicação foi removida.9 casos frontend novos transpilam as páginas/componentes reais, verificam valores/conteúdo reservado, campos ausentes, escape de texto, navegação sem escrita e manutenção da preparação existente. Não equivalem a aceitação visual no navegador. - -Isolamento e saldo: base partnership_history_20261103_test em127.0.0.1:55441,role investmoz_test,45 tabelas conferidas sem linhas após processo terminal com lock,owner e RLS efectivos. Sem migrações novas, instalação no activo, pessoas reais ou comunicações externas. Preservados recibos e provas anteriores; a corrida PostgreSQL do incremento anterior mantém o seu âmbito e não foi apresentada como nova prova deste leitor. Mantêm-se outros consumidores de edição/publicação/moderação, variantes de papéis/representação, destinatários actuais de notificações, recuperação além da página e validação visual/entrega no âmbito próprio. As traduções e os sete modelos sem fonte permanecem pendentes já inventariados, sem nova pergunta repetida. - -[PARTNERSHIP-HISTORY-FOLLOWUP-20261103] Próxima acção concreta identificada na revisão: o dashboard anterior ainda selecciona p.title actual para uma candidatura, incluindo quando a parceria deixou de estar publicada, e as notificações são listadas pelo destinatário histórico sem voltar a conferir a representação. O novo leitor não devolve esse título privado; esta prova limita-se ao GET do histórico. Conferir/corrigir a projecção e os links do painel e os destinatários/visibilidade das notificações com provas próprias, reutilizando a autoridade existente. Não declarar a privacidade de todos os consumidores encerrada por este incremento. - -### 03/11/2026 — AUD-PART-01: painel e avisos pelo âmbito actual e histórico - -[PARTNERSHIP-DASHBOARD-20261103] Corrigidas três falhas reproduzidas: título privado após despublicação, organização eliminada ainda no painel e aviso de representante revogado. Painel projecta só título/link autorizados; representação usa o mesmo cadastro activo de owns. Avisos novos seguem participantes operacionais actuais e guardam contexto no evento existente; leitura e confirmação exigem destinatário, acesso actual e âmbito guardado. Links reconstruídos para candidatura/sala/parceria; primeira leitura preservada. 73 Feature/576 asserções (16 novos),1466 frontend (6 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.69 recibos e185 provas anteriores preservados. Recibo partnership_dashboard_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: continuação concreta PARTNERSHIP-HISTORY-FOLLOWUP-20261103 e AUD-PART-01. O leitor anterior não devolvia rascunho privado, mas a consulta do painel ainda seleccionava p.title actual e a lista de avisos filtrava apenas user_id; /ler também só conferia esse destinatário. Três reproduções anteriores à correcção falharam por conteúdo exposto/avisos acessíveis, sem as classificar como erros500. A consulta do painel passa a excluir organizações eliminadas pelo mesmo join e deleted_at já usados na representação efectiva, sem inventar novos perfis. - -Painel: candidaturas pessoais/organizacionais autorizadas conservam estado, motivo, sala e consulta do histórico. Título/link da parceria só são devolvidos quando a mesma conta pode abrir o detalhe existente: publicada, responsável com leitura ou moderador efectivo. Caso contrário title e partnership_href são null e a interface explica a indisponibilidade; não recebe título, oferta ou estado privado da nova proposta. O dono/representante actual e o moderador mantêm as consultas existentes. As permissões de edição/decisão não são ampliadas por ter um link ou ver o painel. - -Encaminhamento: apenas eventos que já pediam avisos continuam a produzi-los. A intenção anterior para uma ou ambas as partes é resolvida para as pessoas actuais, usando a mesma query de representantes e os mesmos papéis admin/manager/officer usados nos comandos e participantes operacionais. Parte pessoal mantém o seu titular; fundador revogado ou organização eliminada não são destinatários por arrasto. Viewer não recebe automaticamente nova distribuição operacional, mas pode ler o aviso individual que já recebeu enquanto conservar acesso de leitura ao âmbito actual e histórico. IDs sobrepostos são desduplicados por evento. Eventos antes sem aviso, incluindo acesso/documentos, continuam sem nova distribuição. Não há envio externo, calendário, assinatura ou concessão adicional. - -História e autoridade: o evento/auditoria existente conserva _notification_context versão1, referências do processo/candidatura/sala e user_id/organization_id das partes efectivas no momento. Não se reescrevem eventos ou destinatários anteriores, nem se redistribuem avisos antigos a um novo membro. O leitor exige o destinatário individual e, para pelo menos uma parte, tanto owns actual como owns no âmbito guardado. Passar de A para B não autoriza ler o aviso de A só por agora representar B; revogação, organização eliminada, destinatário estranho e contexto malformado são recusados na leitura e no POST/ler. Inconsistência de candidatura/sala/processo na preparação do evento aborta a transacção sem evento/auditoria/aviso cruzado. - -Legado: eventos de candidatura sem o novo contexto só reutilizam o organization_id efectivamente presente no snapshot submitted/previous, com user_id imutável da candidatura; isso pode justificar a leitura pelo candidato, nunca inventa o âmbito histórico do proponente. Avisos sem contexto demonstrável não expõem título/link nem permitem confirmar leitura; continuam intactos no registo e a interface explica a limitação. Contexto explícito inválido não é degradado para uma reconstrução legada. A correcção não promete recuperar informação que não foi registada. - -Consulta e confirmação: filtragem precede o limite de50 avisos visíveis e percorre lotes de100 por ID. Foram atravessadas105 notificações inacessíveis para alcançar um aviso autorizado mais antigo;55 autorizadas conservam as50 mais recentes por ordem, sem duplicações. Nunca é devolvido o href bruto antigo: destinos são construídos para o histórico da candidatura, a sala actual correspondente ou a parceria autorizada. Marcar como lido volta a conferir autoridade na transacção e preserva o primeiro read_at em repetições; não decide processos nem acrescenta eventos de negócio. Mensagem repetida conserva a distribuição original sem novos avisos. - -Validação:16 novos Feature mais57 existentes cobrem dados publicados/privados, organização eliminada, moderador, representação operacional/viewer, autor revogado, mudança A/B em candidatura e proponente, legado, contexto malformado/cruzado, paginação, leitura idempotente e mensagem/sala.6 casos frontend transpilam a página real e conferem links, explicação, escaping, navegação existente e comando de leitura só do aviso apresentado. PHPStan inicial identificou tipos de retorno sem garantia de lista; consultada documentação primária return.type e corrigida a construção dos arrays/validação da identidade, sem casts para ocultar erros, supressões ou alargamento de contrato. As rondas diagnósticas foram conservadas, sem as somar à regressão final. - -Isolamento e saldo: base partnership_dashboard_20261103_test em127.0.0.1:55441,role investmoz_test,45 tabelas vazias após execução terminal; lock,owner e RLS conferidos. Mantidos69 recibos e185 provas aceites e deltas apenas nos consumidores previstos. Sem nova migração, alteração de contas/pessoas reais, comunicação externa ou instalação no activo. Este incremento resolve a lacuna concreta apontada no leitor anterior; permanecem publicação/moderação e recuperação desse editor, variantes transversais de papéis/representação e apresentação visual/entrega. Alertas de prazo/inactividade, notificações externas e cobertura integral dos consumidores não são inferidos desta correcção. - -### 03/11/2026 — AUD-PART-01: recuperação da publicação e moderação da parceria - -[PARTNERSHIP-PUBLICATION-20261103] Publicação/moderação preserva motivo por proposta/conta e compara contexto antes de nova tentativa; replay por UUID/actor no evento, autoridade actual e estados existentes. Suspensão exposta pela capacidade real. Snapshot anterior/aplicado privado, metadados seguros no detalhe e um único aviso de saída com as candidaturas. 85 Feature/642 asserções (12 novos),1482 frontend (16 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.70 recibos e194 provas anteriores preservados. Recibo partnership_publication_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-PART-01, orientação de23/10 e saldo PARTNERSHIP-DASHBOARD-20261103. O editor de conteúdo já tinha comparação/preparação em parceria-edit; não foi declarado ausente nem substituído. A lacuna concreta estava em Publication: remontagem por record.version apagava o motivo, /estado não reconhecia repetição de uma decisão gravada e a UI omitia suspend, já permitido no servidor. Foram reproduzidas três falhas Feature e uma perda de motivo no componente real antes da correcção. - -Autoridade e estados: PartnershipExchange.transition conserva a assinatura anterior e delega no serviço central PartnershipPublication, com clientKey opcional. Reutiliza os estados e permissões anteriores: titular/representante com escrita para submit/archive/renew; manage-portal e exclusão de owns com escrita para publish/return/reject/suspend. A capacidade exposta à UI provém dessa mesma regra; não se introduziu outro requisito de empresa, NUIT, documentos, aprovação ou aprovação por silêncio. A autoridade actual é conferida antes da versão e do replay; um actor estranho já não recebe409 por uma versão antiga antes de lhe ser recusada a operação. Não se alterou a definição de independência para inferir papéis novos. - -Decisões: motivo obrigatório até2000 e requisitos anteriores de submissão mantidos. UUID normalizada e hash de version/action/reason guardados no evento existente, no lock da parceria. Repetir a tentativa exacta pelo mesmo actor é leitura, mesmo depois de outra transição, sem incrementar versão, repetir revisão, evento, auditoria ou aviso. Mesma chave com conteúdo diferente é409; outro actor/processo tem âmbito próprio e autoridade sempre conferida. Pedidos legados sem chave conservam o protocolo anterior, sem promessa de replay identificável. Não há nova tabela/migração nem novo motor de workflow. - -Auditoria: eventos novos conservam snapshot anterior e aplicado da proposta, incluindo estado/versão, organização, título, oferta/procura, declarações, origem/localizações e published_at realmente utilizados; _creation_hash não integra esses snapshots. Não se reconstituem versões antigas. A API do detalhe passa a projectar no histórico apenas os metadados já apresentados na UI (tipo, autor e data), mantendo o envelope privado no registo. Chaves de recuperação são projectadas apenas para o seu actor com competência actual, sem devolver hash, contexto de avisos ou snapshots completos de outras representações. Um leitor próprio das versões da publicação continua pendente; a captura privada não é esse leitor. - -Interface: componente deixa de remontar por versão e fica identificado por proposta/conta. Conserva motivo deliberado e gerações de edição durante comparação, falha, alteração de estado/acesso e resposta tardia. Uma resposta só confirma a tentativa se o ledger do actor trouxer chave/acção/versão compatíveis; alterações posteriores ficam por rever, em vez de serem adoptadas como se fossem o contexto decidido. Recuperação repete o comando congelado e conserva texto escrito depois de enviar. Conflito ou resposta ambígua exigem consulta efectiva antes de adoptar contexto para nova tentativa; a adopção é explícita e conserva o motivo. Viewer/perda de competência não recebe escrita, mas mantém preparação local visível na mesma conta. Outra conta tem estado separado e callbacks de componente desmontado são ignorados. - -Formulários e navegação: os comandos actuais, incluindo suspensão, são apresentados a partir da capacidade do servidor. O motivo só é pedido quando existe acção aplicável ou preparação local; são explicados os efeitos da submissão/renovação e da adopção após tentativa incerta. Comparação apresenta os campos alterados, contexto revisto e estado/versão actual. Publicação e candidaturas partilham um único aviso de saída e conservam as preparações independentes; não há novo localStorage, autosave ou garantia depois de fechar/recarregar a página/autenticar de novo. Acções da publicação não decidem candidaturas nem alteram salas/marcos em cascata. - -Provas:12 novos Feature e16 novos frontend, incluindo replay após outra transição, nonce alterada/normalizada, snapshots, representação revogada, independência, metadados por actor, requisitos legados, suspensão, escopo entre processos, preparação durante refresco, edição posterior ao envio, conflito, acknowledgement posterior/incompatível, perda de competência, mudança de actor, aviso único e payload API vazio. Os testes transpilam os componentes/hooks reais. O harness inicial recriava setters de estado em cada render e produziu Component state did not settle; passou a conservar essa identidade por frame. Essa falha de modelo não foi apresentada como uma falha demonstrada no navegador. Um teste usava o rótulo abreviado Motivo em vez do rótulo real; a fixture foi corrigida. Lint inicial identificou conversão de objectos para texto; dados da comparação passam por validação de escalares, sem ocultar avisos. - -Isolamento e saldo: base partnership_publication_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas conferidas sem linhas após processo terminal, com lock/owner/RLS efectivos. Mantidos70 recibos e194 provas anteriores. A prova de concorrência PostgreSQL de candidaturas continua com o seu âmbito; não é uma nova corrida de publicação. Não houve migração/instalação no activo, pessoas reais ou comunicação externa. AUD-PART-01 e auditoria integral continuam parciais. Próximas lacunas: confirmação incerta da edição pós-criação, leitor das versões da publicação pelo âmbito histórico e variantes de representação/consumidores; prova visual e disponibilização no âmbito próprio continuam pendentes. - -### 03/11/2026 — AUD-PART-01: leitura privada das versões da publicação - -[PARTNERSHIP-VERSIONS-20261103] Leitor privado do histórico da publicação, antes/depois, por acesso actual e âmbito histórico. Captura de novas criações/edições reutiliza o snapshot das transições, sem inventar o placeholder de criação ou conteúdo legado.10 eventos por página, cursor cifrado por conta/processo/propósito, sem dados actuais no lugar dos antigos. 97 Feature/739 asserções (12 novos),1490 frontend (8 novos),PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.71 recibos e204 provas anteriores preservados. Recibo partnership_versions_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-PART-01 e saldo PARTNERSHIP-PUBLICATION-20261103. A publicação já conservava snapshots nas transições, mas o detalhe só apresentava tipo/autor/data e as gravações do rascunho conservavam apenas estado anterior e referências. Implementada consulta dedicada dos eventos existentes e completada a captura das gravações futuras. Não se criou outra tabela de história, matriz, backlog ou migração; os registos e provas anteriores permanecem intactos. - -Captura: PartnershipPublication.snapshot é reutilizado por transições e save. Edição guarda anterior/aplicado com versão, estado, âmbito, título, oferta/procura, declarações, critérios, sector e referências da origem/localização efectivamente utilizados. Criação guarda aplicado e previous=null: a linha vazia temporária inserida dentro da transacção não é inventada como uma versão anterior. Replay da criação continua leitura, sem nova revisão nem reescrita do snapshot. O hash de criação, nonce, hashes de comandos e envelopes de distribuição não são projectados para o leitor. - -Autoridade: a rota é autenticada e exige owns com leitura no processo actual ou manage-portal efectivo, tal como a leitura privada existente da proposta. Publicação pública e candidatura não concedem consulta histórica. Para o responsável da organização, cada snapshot exige ainda o âmbito guardado na versão; representar B não autoriza ler A nem o rascunho pessoal de outro titular. Revogação e organização eliminada impedem o acesso actual, incluindo por cursor antigo. Moderação efectiva conserva a leitura global já existente das propostas; isso não concede competência para decidir a própria proposta nem substitui as verificações dos comandos. - -Legado e integridade: falta de âmbito/identidade fica scope_unknown para o responsável, sem assumir participação pessoal. O moderador pode ler metadados parciais guardados, mas não recebe conteúdo actual como se fosse antigo. Um snapshot com ID de outro processo não é apresentado nem ao moderador como versão deste processo. Quando existe o contexto de aviso efectivamente gravado, pode justificar a projecção parcial do estado posterior/reason, sem inventar o anterior. Acção ausente continua Alteração registada, em vez de se deduzir uma decisão a partir do tipo do evento. Referências malformadas ficam assinaladas como incompletas; não equivalem a listas vazias. - -Apresentação: página de leitura compara antes/depois, estado/versão, motivo, conteúdo, consentimento, obrigatoriedade e referências guardadas. Ausente distingue-se de null/vazio explícitos, falso e lista vazia; zero/ausência não são fabricados. Não se recalculam decisões, nomes de critérios ou conteúdo de fontes; nomes de pessoas/organizações usam o cadastro actual e isso é explicado. Referências da origem/localização são apresentadas sem resolver catálogos actuais ou gerar ligações que concedam acesso a essas fontes. Fonte declarada não é validação oficial da hierarquia territorial. Não há formulário de restauro, nova publicação, aprovação ou sobrescrita a partir da história. - -Navegação e privacidade: links no detalhe, propostas próprias e fila de moderação; candidato conserva o seu link próprio de histórico de candidatura, sem receber o da publicação por inferência. GET privado/no-store e histórico Inertia cifrado.10 eventos por página, ordem decrescente e cursor cifrado vinculado à conta/processo/propósito publication; não expõe IDs de evento ou contador global e não aceita cursor de candidatura. Inserção posterior não duplica versões ao avançar. Não entram eventos de candidatura, sala, documento ou marco no histórico da publicação. O aviso de saída existente conserva a preparação antes de navegar. - -Provas:12 novos Feature cobrem criação sem placeholder, edição/transição, candidato/anónimo, mudança A/B, viewer, revogação/organização eliminada, moderação, legado conhecido/desconhecido,21 versões e inserção entre páginas, cursor por actor/processo/propósito, consulta sem escrita/cache/encriptação, referências após mudanças de cadastro, limpeza explícita, formas malformadas e replay sem nova revisão.8 casos frontend transpilam a página real e os consumidores nativos: comparação, ausência/falso/listas incompletas, âmbito reservado, legado, cursor, escape de texto, links e preparação local conservada. Estes ensaios não substituem aceitação visual no navegador. - -Isolamento e saldo: base partnership_versions_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas vazias após processo terminal e lock/owner/RLS conferidos. Preservados71 recibos e204 provas anteriores; apenas deltas de fonte previstos no incremento. Sem nova migração, instalação/dados no activo, pessoas reais ou comunicação externa. AUD-PART-01 e auditoria integral permanecem parciais. Continuam confirmação incerta de edição pós-criação, variantes transversais de papéis/consumidores, síntese de metadados no detalhe, prova visual e entrega no âmbito próprio. Traduções e modelos sem fonte continuam nas pendências anteriores, sem perguntas repetidas. - -### 03/11/2026 — AUD-PART-01: recuperação de edições sem confirmação - -[PARTNERSHIP-DRAFT-RECOVERY-20261103] Edições identificadas por operation_key/actor/processo, com replay no evento existente antes de validar cadastros vivos, sem repetir versão ou efeitos. Editor conserva comando e alterações posteriores, revalida consulta antes de nova tentativa e separa contas. Critérios/tipos anteriores mantêm identificação e remoção explícita da preparação. 109 Feature/802 asserções (12 novos),1502 frontend (12 novos) e28 focados verificados sem somar repetições;PHPStan/Pint/tipos/lint/build aprovados.45 tabelas QA vazias e owner/RLS/lock conferidos.72 recibos e212 provas anteriores preservados. Recibo partnership_draft_recovery_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-PART-01, orientação de23/10 e saldo PARTNERSHIP-VERSIONS-20261103. A criação já reconhecia client_key, mas uma edição gravada sem resposta voltava a receber409 ou podia falhar422 por tipo/critério entretanto retirado. O hook só congelava a criação. Foram reproduzidos dois Feature antes da correcção e um caso real do componente/hook, no ficheiro completo. Uma tentativa inicial com filtro de nomes não seleccionou o caso e produziu apenas o resultado do ficheiro; ficou como diagnóstico, sem a apresentar como reprodução ou aceitação. - -Identidade da tentativa: operation_key UUID por edição, independente do client_key de criação que se mantém. O evento changed existente guarda chave normalizada, hash do conteúdo relevante e result_version; o hash distingue omissão de remoção explícita e exclui a chave de criação que não altera a edição. Sob o lock da parceria, a autoridade actual precede procura de replay, versão, estado e validação de referências vivas. Mesma tentativa do mesmo actor/processo devolve leitura com versão originalmente gravada e estado actual, sem novo snapshot, versão, evento, auditoria ou aviso. Mesmo nonce com conteúdo diferente é409. Outra pessoa ou processo tem âmbito próprio; isso não autoriza recuperar o processo alheio. - -Regras preservadas: comandos novos continuam sujeitos aos estados, representação, tipo/critério activos, sector e fontes autorizadas existentes. As validações de catálogo foram colocadas depois do reconhecimento de gravação já concluída, tal como a validação de sector já estava depois do replay de criação. Tipo/critério/sector retirados não bloqueiam a leitura de uma tentativa concluída nem autorizam nova escrita inválida. Pedidos anteriores sem operation_key conservam a guarda de versão e não recebem falso replay. Retirar organização ou mudar âmbito mantém os seus efeitos e a autoridade original; recuperações de representante revogado ou viewer são recusadas. - -Projecção e acesso: editor devolve editorActorId e apenas chaves/versões de gravações do actor com escrita efectiva. A consulta usa projecções JSONB sem transferir envelopes completos para extrair os identificadores. Não expõe operation_hash, _creation_hash ou contexto privado de avisos. O histórico privado conserva os snapshots originais; não é reescrito por replay. A resposta JSON distingue replay e saved_version do estado/versão correntes. A leitura dos metadados não concede competência adicional ou autoria a outro representante. - -Preparação: tentativa de edição fica congelada, inclusive perante cancelamento ou resposta perdida, e Recuperar a mesma gravação envia o comando original. Gerações conservam campos escritos depois do envio; acknowledgement exige proposta/actor/chave/versão compatíveis. Uma resposta sem a chave do actor não limpa a preparação. Se houver versão posterior, o formulário reconhece a gravação antiga, mas conserva o contexto intermédio e exige comparação para outra escrita. Um valor já confirmado antes da edição de outra pessoa não é automaticamente reaplicado; o texto efectivamente preparado depois de enviar permanece local. Recusa de acesso suspende recuperação até nova consulta autorizada; nova tentativa após falha exige consulta efectiva e adopção explícita, mantendo as escolhas e usando nova chave. - -Separação e formulários: editor é identificado por conta, conservando a passagem de criação a ID atribuído na mesma conta. Outra autenticação inicia preparação própria; callbacks desmontados ou de tentativa abandonada não recuperam texto antigo. Recuperação fica fora do fieldset de edição, permitindo reconhecer uma gravação mesmo quando o estado posterior só admite consulta, sem nova competência de escrita. Grupos/tipos/organização que saíram das listas mantêm opção anterior identificada. Critério retirado pode ser removido explicitamente da preparação sem ser apagado do histórico; não é retirado automaticamente nem confundido com não aplicável. O comando de recuperação conserva o valor original e a nova escolha permanece para a gravação seguinte. Aviso de saída inclui tentativas ainda sem confirmação, mesmo sem diferenças de campos. - -Provas:12 novos Feature cobrem replay após submissão posterior, tipo/critério/sector retirados, nonce alterada/normalizada, chaves distintas sem mudar criação, representação revogada/viewer, metadados por actor, entradas inválidas/stale não consumidas, omissão/remoção e clientes legados/processos distintos.12 casos frontend novos ampliam o ficheiro de16 para28; os16 anteriores permanecem, com a fixture a modelar os novos metadados. O caso de uma edição posterior de outra pessoa foi reforçado para provar que, após comparação, esse título actual é adoptado enquanto texto preparado durante o envio permanece conservado. Há ronda completa e nova ronda focada desse ficheiro após o reforço, sem somar casos repetidos. Testes usam componentes/hooks reais transpilados; não são aceitação visual num navegador. - -Isolamento e saldo: base partnership_draft_recovery_20261103_test em127.0.0.1:55441,role investmoz_test;45 tabelas vazias após processo terminal, lock/owner/RLS efectivos. Preservados72 recibos e212 provas aceites. Sem migração nova, instalação/dados no activo, pessoas reais ou mensagens externas. A prova PostgreSQL concorrente anterior conserva o seu âmbito; este incremento não a apresenta como nova corrida de edição. AUD-PART-01 e auditoria integral continuam parciais. Restam variantes de representação/consumidores, apresentação visual/entrega e síntese do histórico no detalhe; preparação continua em memória, sem garantia depois de fechar/recarregar ou voltar a autenticar. - -### 03/11/2026 — AUD-PART-01: recuperação e revisão de contexto nos acordos - -[PARTNERSHIP-AGREEMENTS-20261103] Acordos com tentativa identificada por actor/sala, recuperação sem duplicar efeitos após estados terminais e revisão da versão da proposta/candidatura. Confirmação bilateral pelas partes efectivas, histórico completo anterior e preparado posterior conservado; assinatura jurídica continua não verificada. 121 Feature/905 asserções (12 novos),1514 frontend (12 novos),28 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;73 recibos e224 provas anteriores preservados. Recibo partnership_agreements_increment_20261103; parcial, sem entrega activa. - -Origem e reprodução: AUD-PART-01, orientação de 23/10 e saldo dos incrementos anteriores. Dois casos demonstraram que repetir um cancelamento já concluído recebia 409 e que uma confirmação podia avançar sobre proposta alterada sem mudança da versão da sala. Um caso do componente/hook demonstrou a falta de recuperação da acção sem resposta. As falhas originais foram conservadas. Diagnósticos intermédios, incluindo uma ligação inicial incompleta ao serviço e fixtures de confirmação entretanto corrigidas, não são apresentados como provas finais. - -Comandos: as seis acções existentes (registar, confirmar, iniciar, concluir, cancelar e renovar) aceitam client_key UUID normalizada por actor, parceria e sala, com hash do conteúdo relevante. Motivo continua obrigatório; título/condições só fazem parte do comando de registo. A ordem de bloqueio é parceria, candidatura e sala. A representação efectiva actual é verificada antes do reconhecimento da tentativa. Um replay devolve a versão originalmente gravada e o estado actual sem novo evento, versão, auditoria ou aviso, incluindo após encerramento/cancelamento. Chave com conteúdo diferente é 409; outro actor ou outra sala não reutiliza a autoridade dessa tentativa. - -Contexto revisto: novos comandos da interface transportam a versão da proposta e da candidatura, além da versão da sala. Se o contexto mudou, o servidor recusa antes da decisão e o formulário conserva a preparação para comparação explícita. Esses dois tokens são opcionais por compatibilidade com clientes antigos; estes conservam a sua guarda de versão da sala e não recebem por inferência a garantia de revisão do contexto completo. Não há migração ou segundo motor de estados. - -Partes e confirmação: conserva-se a precedência já existente de proponente quando a pessoa representa ambas as origens; não foi inventado selector de parte, nova alçada ou regra de pessoas distintas. A interface identifica a parte efectiva e distingue actualizar uma confirmação própria de confirmar pela primeira vez. Apenas entradas com as chaves proponent e candidate e actor positivo contam para a confirmação bilateral; uma chave desconhecida não constitui segunda parte. A representação actual é exigida para novas intervenções, sem invalidar retroactivamente decisões históricas de quem entretanto saiu. A assinatura jurídica permanece not_verified; a confirmação interna não prova assinatura ou validade legal. - -Histórico e integridade: cada comando guarda no evento existente o estado anterior e o aplicado, versão, motivo, parte e contexto real. Registar nova versão e renovar conservam o instrumento completo anterior, incluindo campos legados, sem inserir recursivamente a lista anterior dentro de cada entrada; confirmações são reiniciadas nos mesmos pontos do percurso. Estruturas legadas de histórico ou confirmações incompatíveis recebem 409 sem escrita, em vez de erro 500. Concluir mantém a exigência existente de marcos terminados. Estes snapshots não constituem ainda um leitor paginado de histórico de acordos. - -Preparação e recuperação: o comando fica congelado; Recuperar a mesma acção repete bytes e chave originais, conservando alterações feitas depois do envio. Confirmar não grava título/condições ainda não registados. Acknowledgement exige actor, sala, chave, acção e versão próprios; na versão exacta exige instrumento e carimbo de confirmação compatíveis. A ausência desses metadados não apaga a preparação. Uma decisão posterior ou alteração posterior da proposta/candidatura reconhece o comando antigo mas exige comparação antes de outra escrita. O contexto intermédio não reaplica automaticamente valores antigos sobre a decisão de outra pessoa. - -Acesso e separação: recibos da sala projectam apenas chave/acção/versão/estado/parte das tentativas do próprio actor com escrita efectiva, sem envelopes privados ou hashes. O DTO da proposta remove _creation_hash mantendo o tipo JSON string anterior. Recusa de acesso suspende recuperação até consulta autorizada; outra conta recebe editor próprio. Callbacks de tentativa abandonada ou editor desmontado não apagam preparação nova. Antes de abandonar uma tentativa incerta e criar outra, a consulta actual e a adopção explícita são exigidas. O aviso de saída continua único para os formulários da sala. - -Provas: 12 novos Feature cobrem replay terminal/sem efeitos, alteração de contexto, registo seguido de confirmação, nonce/conteúdo, partes forjadas, confirmação bilateral, versões completas e renovação, marcos, representação revogada/viewer, metadados por actor e salas distintas, entradas inválidas, estrutura legada e compatibilidade antiga. Há 12 casos novos de frontend, além dos 16 anteriores do formulário de sala, com 28 focados sem somar repetições; os dois casos antigos de sucesso passaram a modelar o recibo real de comando. Os testes executam componentes/hooks transpilados; não são aceitação visual num navegador. Não foi executada nova corrida PostgreSQL, e as provas concorrentes anteriores conservam o seu âmbito. - -Isolamento e saldo: base descartável partnership_agreements_20261103_test em 127.0.0.1:55441, role investmoz_test; 45 tabelas verificadas vazias após processo terminal, com aquisição do lock e conferência de owner/RLS. Preservados 73 recibos e 224 provas anteriores. AUD-PART-01 e auditoria integral continuam parciais. Continuam pendentes variantes de papéis/consumidores, leitura de instrumentos legados sem mapa de confirmações, leitor de histórico do acordo, síntese no detalhe, aceitação visual e disponibilização. A próxima verificação deve começar pela leitura legada, distinta da recusa de escritas malformadas já testada. Preparação mantém-se em memória, sem promessa de persistência após fechar/recarregar ou autenticar. Sem migrações novas, instalação/escrita no activo, pessoas reais ou mensagens externas. - -Diagnóstico de ambiente: uma primeira execução com filtro textual Partnership seleccionou 123 casos, incluindo anexos independentes fora dos 11 ficheiros da suite específica. Terminou com 122 casos passados e um erro de fixture por imagecreatetruecolor indisponível. Esse resultado foi conservado como diagnóstico, sem o apresentar como regressão limpa. A suite específica foi repetida pelos 11 caminhos explícitos (121 casos). O caso de anexos que falhou foi executado adicionalmente com a extensão GD já disponível carregada apenas nesse processo, sem alterar php.ini global, fabricar scan ou dispensar ClamD. O seu JUnit conserva o resultado e as asserções; não se soma esse caso antigo aos 12 novos Feature deste incremento. A verificação final das 45 tabelas ocorre depois de ambos os processos terminarem. - -### 03/11/2026 — AUD-PART-01: leitura legada e histórico privado dos acordos - -[PARTNERSHIP-AGREEMENT-HISTORY-20261103] Leitura de instrumentos antigos sem falha/confirmações inventadas e histórico privado ligado à sala, com snapshots antes/depois, âmbitos actuais/históricos separados e paginação cifrada por conta/relação/finalidade. 132 Feature/1009 asserções (11 novos),1525 frontend (11 novos),39 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;74 recibos e237 provas preservados. Recibo partnership_agreement_history_increment_20261103; parcial, sem entrega activa. - -Origem: AUD-PART-01, orientação de 23/10 e saldo PARTNERSHIP-AGREEMENTS-20261103. O incremento anterior capturou instrumentos antes/depois dos comandos mas não tinha leitor. Foi reproduzido GET404 no histórico e falha real do componente/hook ao abrir uma sala cujo instrumento antigo não tinha confirmations. Os diagnósticos são preservados. Um teste intermédio de HTML procurava uma barra não escapada no JSON Inertia; foi substituído por assertInertia sobre o componente e room_id efectivos, sem alterar o produto para satisfazer uma representação textual. - -Leitura actual: parser e componente partilhados tratam dados desconhecidos como desconhecidos. Mapa ausente/null não se torna Pendentes; mapa malformado mantém aviso e o registo original. O array vazio guardado pelo serviço equivale ao mapa vazio compatível; listas não vazias não são convertidas em confirmações. Carimbos com actor inválido são incompletos e não activam o rótulo de actualização de confirmação. Referências adicionais não substituem uma parte e são assinaladas. Títulos, condições, datas e motivos de tipos não reconhecidos não são inseridos como filhos React; valores vazios conhecidos distinguem-se de valores não registados. A leitura não limpa nem regrava esses dados. - -Percurso: ligação Consultar histórico do acordo na sala, GET privado JSON/Inertia em /parcerias/salas/{id}/historico e página agreement-history. O percurso usa autenticação, instalação, resposta privada/no-store e histórico Inertia cifrado existentes. A página é só de consulta, mostra antes/depois, acção, motivo, autor e data, parte que confirmou e versões guardadas da proposta/candidatura. Os nomes de pessoas provêm do cadastro actual e são identificados como tal. Não volta a executar comandos, não recalcula, não envia avisos e não certifica assinatura jurídica. - -Acesso actual e histórico: a entrada exige o mesmo acesso efectivo de leitura da sala, incluindo viewer de organização, sem excepção de moderação. Os eventos são filtrados por parceria, tipo exacto e sala. O contexto privado de aviso já capturado identifica as duas origens, sala e versão do contrato de contexto; IDs e âmbitos têm de ser consistentes. Os responsáveis actuais não herdam por essa condição uma representação antiga. Sem contexto conhecido, o evento é reservado e não devolve actor, motivo ou conteúdo. Contexto conhecido mas sem representação actual da origem histórica também é reservado. Mantém-se a possibilidade de ler o âmbito de qualquer das duas partes autorizadas; não foi inventada competência funcional nova. - -Instrumentos: cada snapshot exige a sala correcta, versão positiva e estado identificado. O instrumento tem ainda âmbito próprio em recorded_context; proposta/candidatura e origens guardadas têm de ser reconhecidas. Um representante novo pode ler a decisão produzida na sua organização actual e continuar sem acesso ao instrumento de outra representação anterior. A contraparte com autoridade histórica conserva a sua leitura. Instrumentos legados sem origem registada são marcados scope_unknown; snapshots antigos inexistentes são not_recorded. Não se reconstitui conteúdo a partir do acordo actual ou de previous_versions, nem se atribui uma origem retrospectiva. Ausência de dados não é uma decisão de invalidade jurídica. - -Projecção: apenas título, condições, estado de assinatura e confirmações nomeadas saem do instrumento. IDs positivos de autores recebem o nome actual; motivo/data são valores efectivamente guardados quando têm tipo reconhecido. Campos adicionais, listas recursivas de versões, envelopes, hashes e nonces não são devolvidos. Referências desconhecidas são representadas por um indicador sem copiar chaves ou valores privados. O âmbito usado para autorizar não é exposto como um novo cadastro. Snapshots de outra sala são ocultados mesmo dentro de um evento de uma sala autorizada. - -Paginação: máximo de10 entradas, com consulta de11 para reconhecer continuação. A ordem usa a sequência estável do evento. O cursor é cifrado e vinculado à finalidade acordo, conta, sala, candidatura e parceria, com fronteira inteira positiva; referências de outro percurso/actor/relação ou malformadas são422. A autoridade é conferida em cada página antes de descifrar o cursor. Inserir um evento mais recente não repete os eventos da página anterior. Páginas antigas e retorno às mais recentes têm navegação explícita. - -Provas:11 novos Feature exercitam leitura sem escrita/avisos, ambas as partes após cancelamento, página Inertia, recusa de terceiro/moderador, snapshots congelados e projecção, paginação com inserção, cursor adulterado, viewer e mudança de organizações/revogação, contexto desconhecido/inconsistente, eventos legados, IDs de snapshot alheio, confirmação malformada e isolamento entre salas.11 casos novos frontend exercitam a falha antiga, array vazio, tipos inválidos, partes incompletas, leitura antes/depois, reservas/ausência, paginação, lista vazia, escape HTML e ligação com o aviso de saída existente.39 focados incluem os28 anteriores; não se somam casos repetidos. Componentes/hooks transpilados e React SSR são provas de comportamento, sem os apresentar como aceitação visual em navegador. - -Isolamento e saldo: base descartável partnership_agreement_history_20261103_test em127.0.0.1:55441, role investmoz_test,45 tabelas vazias verificadas depois do processo terminal e com aquisição do lock/owner/RLS. Sem nova migração, escrita ou instalação no activo, pessoas reais ou mensagens externas. Preservados74 recibos e237 provas aceites, incluindo o caso adicional de scan com GD do incremento anterior, sem o repetir ou aumentar o âmbito dessa prova. Sem nova corrida concorrente. AUD-PART-01 e auditoria integral continuam parciais. Restam variantes de papéis/consumidores, síntese do histórico no detalhe, aceitação visual e disponibilização; conteúdo antigo que não foi capturado não é fabricado. Preparação mantém-se em memória e não tem por este incremento garantia após fechar/recarregar ou autenticar. - -Próxima verificação concreta: confrontar os restantes consumidores com esta projecção, começando pelo DTO actual da sala, que ainda descodifica o instrumento completo e pode transportar previous_versions e recorded_context. O leitor novo filtra esses dados, mas esta prova não demonstra filtragem transversal dos outros endpoints. Reproduzir o caso com mudança de organização e preservar o instrumento actual e o histórico no servidor ao corrigir a exposição de versões anteriores. Esta pendência não requer inventar uma transferência automática de autoridade. - -### 03/11/2026 — AUD-PART-01: histórico do acordo fora da resposta corrente da sala - -[PARTNERSHIP-AGREEMENT-PROJECTION-20261103] Sala corrente projecta título, condições, assinatura guardada e confirmações reconhecidas; versões anteriores e metadados privados ficam no servidor e no leitor histórico autorizado. 141 Feature/1146 asserções (9 novos),39 frontend focados;PHPStan/Pint aprovados e QA45 vazias/owner/RLS/lock conferidos. Frontend1525/tipos/lint/build anteriores reutilizados com fontes cliente e artefactos conferidos.75 recibos e248 provas anteriores preservados. Recibo partnership_agreement_projection_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-PART-01 e pendência concreta PARTNERSHIP-AGREEMENT-HISTORY-20261103. Reproduzida a leitura por viewer da nova organização depois de uma mudança A→B e de registar novo instrumento: o GET corrente ainda devolvia previous_versions com o instrumento da origem anterior. O primeiro teste falhou na ausência esperada desse campo. A falha original foi preservada. A primeira ronda alargada corrigiu dois problemas de fixture (alias Assert removido quando ainda não era usado e expectativa de um instrumento reservado dentro de um evento inteiramente reservado), sem alterar o produto para tornar essas expectativas verdadeiras. - -Inventário de consumidores: pesquisa por partnership_rooms nos controladores e serviços encontrou PartnershipExchangeController, PartnershipExchange, PartnershipAgreements, PartnershipCandidacies, PartnershipMilestones, PartnershipRoomUploads e PartnershipNotifications. No controlador, painel e detalhe usam apenas referência/ligação à sala; o método room era a saída do agregado completo. O leitor PartnershipAgreementHistory é a saída dedicada de snapshots. As operações internas continuam a trabalhar sobre o agregado guardado e não recebem a projecção de leitura como fonte de escrita. Não se apresenta esta pesquisa literal como auditoria de todos os módulos do portal. - -Correcção: PartnershipAgreementProjection fornece uma única formatação para os campos reconhecidos, usada depois da autorização pelos dois leitores. A sala corrente conserva título, condições, estado de assinatura e confirmações nomeadas com actor positivo/data/motivo quando reconhecidos. Não devolve previous_versions, recorded_context, extensões privadas, nomes não autorizados de chaves adicionais ou actor_name introduzido num instrumento legado. No histórico autorizado, os nomes continuam a provir do cadastro actual, através das referências efectivamente guardadas. Cada leitor conserva a sua verificação de autoridade: actual da sala para o instrumento corrente; actual e histórica para snapshots. A formatação não é uma concessão de acesso. - -Legado e conservação: omissão e null de confirmações mantêm-se distintos do mapa vazio conhecido; array vazio compatível é representado por objecto vazio. Estruturas não reconhecidas recebem marcador e não ecoam o seu conteúdo opaco. Carimbos incompletos continuam identificados, e chaves adicionais produzem só indicador. Nenhum GET limpa a base, elimina versões ou altera decisões. Acordo actual continua acessível aos participantes actuais pelo percurso já existente; não se inventa transferência de autoridade histórica, nova alçada ou bloqueio de escrita. O histórico completo, contextos e campos legados permanecem nos agregados e nos snapshots de auditoria. - -Operações e recuperação: registo novo e replay mantêm as regras, versões, nonces e efeitos existentes. A projecção não é enviada de volta para substituir o agregado; os formulários já enviam campos próprios do comando. Os testes conferem preservação do conteúdo privado em previous_versions e nos snapshots previous/applied após registar, ler e repetir. Repetir o comando não acrescenta evento, auditoria ou aviso. O estado de assinatura continua not_verified. A consulta de versões anteriores usa /parcerias/salas/{id}/historico e as guardas já implementadas. - -Provas:9 novos Feature cobrem mudança de organização e contraparte histórica, campos correntes e confirmações das duas partes, metadados próprios, JSON e Inertia/private-no-store, formas legadas/marcadores, referências incompletas e privadas, preservação do agregado/auditoria e replay, viewer/representação revogada/terceiro/moderação e os consumidores painel/detalhe. Os39 casos frontend focados foram executados sem novos testes cliente. Como não houve alteração em código cliente ou rotas, reutilizam-se as1525 provas frontend e tipos/lint/build do incremento anterior; as fontes cliente das bases anteriores são conferidas e o manifesto, entradas compiladas e dependências da sala/histórico têm hashes preservados. Não se declara nova ronda integral frontend, nova compilação, aceitação visual ou corrida concorrente. - -Isolamento e saldo: base partnership_agreement_projection_20261103_test em127.0.0.1:55441/role investmoz_test,45 tabelas vazias depois do processo terminal com lock/owner/RLS conferidos.75 recibos e248 provas anteriores preservados. Sem migração, escrita/instalação no activo, pessoas reais ou mensagens externas. AUD-PART-01 e auditoria integral continuam parciais; restam variantes dos outros percursos/consumidores, síntese no detalhe, visual e disponibilização. A exposição de versões anteriores no DTO corrente registada no incremento anterior fica reconciliada por esta prova; o registo anterior não é apagado. Preparação mantém-se em memória; conteúdo histórico não capturado não é fabricado. - -Próxima acção concreta: o detalhe da parceria ainda devolve history com event_type, actor_id e occurred_at sem limite, e detail.tsx apresenta esses códigos/IDs no bloco Histórico e decisões. Reutilizar o leitor de publicação para uma síntese limitada, com as mesmas guardas históricas e linguagem do processo, mantendo o acesso ao histórico completo. Conferir as variantes de dono, nova representação, moderação e consulta pública; não trocar a síntese por uma nova concessão de leitura. - -### 03/11/2026 — AUD-PART-01: síntese do histórico no detalhe da parceria - -[PARTNERSHIP-PUBLICATION-SUMMARY-20261103] Síntese de até cinco alterações recentes no detalhe, com autoridade do leitor histórico, metadados reservados ocultos e linguagem partilhada com o histórico completo. 149 Feature/1247 asserções (8 novos),1533 frontend (8 novos),55 focados;PHPStan/Pint/tipos/lint/build aprovados. QA45 vazias e owner/RLS/lock conferidos;76 recibos e254 provas anteriores preservados. Recibo partnership_publication_summary_increment_20261103; parcial, sem entrega activa. - -Origem: AUD-PART-01, orientação de23/10 e próxima acção PARTNERSHIP-AGREEMENT-PROJECTION-20261103. O detalhe devolvia todos os metadados de eventos de publicação sem limite, com actor_id/event_type/occurred_at, e a interface mostrava IDs/códigos técnicos. Um Feature reproduziu a presença do campo bruto history e um caso do componente/hook reproduziu a falta de linguagem do processo. Esses resultados originais foram preservados. A nova propriedade historySummary substitui a lista bruta; não se mantém uma segunda cópia do histórico no detalhe. - -Servidor: summary reutiliza context, events e entry do leitor PartnershipPublicationHistory. Há uma só autoridade de leitura actual e histórica e uma só interpretação dos snapshots; não se deduzem decisões de um código de evento. A consulta é limitada a seis eventos para apresentar no máximo cinco e saber se existem anteriores, na ordem da sequência estável. A página completa conserva dez entradas e cursor cifrado por finalidade/conta/publicação. O endereço do histórico é derivado no servidor. Cinco é uma escolha técnica de apresentação, não uma regra organizacional ou nova alçada. - -Projecção: saem apenas versão, reserva do conteúdo, acção reconhecida, nome actual do actor, data, motivo e estados antes/depois quando o respectivo snapshot está disponível. Não saem actor_id, event_type, envelopes, snapshots, origem privada, hashes ou nonces. Se um dos snapshots está reservado, o seu estado não é copiado para a síntese. Um evento inteiramente reservado não expõe actor/data/motivo/acção. Uma nova representação não recebe metadados antigos por ser responsável actual. A moderação mantém exactamente a leitura histórica que o leitor já lhe concedia; não ganha por este incremento acesso a salas privadas. - -Percurso e linguagem: detalhe apresenta secção de até cinco alterações, com nomes, motivos, estados e rótulos do processo. Os rótulos das acções são partilhados com a página completa. O texto identifica nomes como cadastro actual e os dados como valores guardados. Registos vazios, metadados ausentes, estados/acções desconhecidos e conteúdo reservado têm indicação própria, sem inventar aprovação, data ou autor. Há uma única ligação para o histórico completo e indicação de alterações anteriores. A secção não cria formulários, decisões ou nova tramitação. Permanece oculta em consultas públicas/candidatas sem a autoridade correspondente, mesmo se a interface receber uma síntese desactualizada. - -Preparação: actualizações da síntese não adoptam versões da proposta nem apagam um motivo preparado para publicação. O percurso mantém o aviso de saída já partilhado com candidaturas; consultar histórico não acrescenta um segundo aviso nem envia comandos. Motivos e nomes são escapados como texto pelo React. Identificadores técnicos não são usados como texto de substituição quando falta informação. A leitura não altera versões, eventos, notificações, auditoria ou estado comercial. - -Contrato de lista: a primeira análise estática identificou que Collection::values()->all() não comprovava o contrato list no tipo devolvido. Após consultar https://phpstan.org/error-identifiers/return.type, a construção foi tornada explícita com array_values, assegurando os índices sequenciais do JSON. Não se alargou o tipo, não se acrescentaram casts para esconder o erro nem supressões/baselines. A análise final passou com o contrato de lista preservado. - -Provas:8 novos Feature exercitam limite/ordem e ligação ao histórico completo, equivalência de metadados com o leitor autorizado, nova organização/viewer/revogação, moderação, consulta pública/candidata, âmbito antigo desconhecido, ausência de eventos de publicação e HTTP/Inertia sem efeitos.8 novos frontend exercitam linguagem, reserva dos dados, ausência para público, lista vazia/limite/uma só ligação, valores desconhecidos, preparação/aviso de saída, escape React e perda de contexto de leitura.55 focados incluem os47 anteriores, sem somar repetições. A ronda integral frontend, tipos/lint e compilação são novas neste incremento; testes de componentes/hooks e React SSR não são apresentados como aceitação visual num navegador. Não foi executada nova corrida concorrente. - -Continuidade dos artefactos: a compilação nova substitui o manifesto e os bundles que o incremento anterior apenas reutilizava. O recibo anterior e os seus hashes permanecem preservados como inventário histórico; o recibo actual identifica o estado dos treze artefactos anteriores após a compilação, sem fingir que hashes antigos de bundles continuam a ser a versão corrente. As provas anteriores de testes não são reescritas. As páginas concluídas continuam conferidas no manifesto actual. - -Isolamento e saldo: base partnership_publication_summary_20261103_test em127.0.0.1:55441/role investmoz_test,45 tabelas vazias verificadas depois do processo terminal, com lock/owner/RLS.76 recibos e254 provas anteriores preservados. Sem migração nova, instalação/escrita no activo, pessoas reais ou mensagens externas. AUD-PART-01 e auditoria integral continuam parciais: faltam variantes dos outros percursos, aceitação visual e disponibilização. Preparação continua em memória e não se fabrica conteúdo histórico ausente. A pendência do detalhe identificada no incremento anterior fica reconciliada por esta implementação, sem apagar a prova anterior. - -Próxima acção transversal: confrontar AUD-CRM-01, AUD-DESK-01/02 e os restantes eixos da matriz com os recibos e código actuais, antes de escolher o próximo desenvolvimento. A leitura inicial da matriz ainda apresenta lacunas históricas sobre encerramento de dossier e estado Implementado com falha no CRM; conferir o saldo actual e as decisões do dono, sem repetir provas aceites nem declarar um módulo concluído pela mera existência de testes. A auditoria permanece com o âmbito integral do portal. - -Reconciliação do teste existente: a primeira ronda integral terminou com148 casos passados e um erro no teste de privacidade que ainda procurava history.0. O teste passou a exigir ausência do campo bruto, ausência de payload/event_type/actor_id/command_hash na síntese e síntese null para o leitor público, conservando as verificações de chaves privadas por actor. Trata-se da actualização do contrato testado, não de uma nova concessão no produto. Esse caso anterior não é contado entre os8 novos Feature. A ronda integral foi repetida; a falha intermédia e o ajuste de formatação ficam como diagnóstico, sem os apresentar como resultado final. - -Actualizações parciais: a verificação final encontrou que Comparar a proposta e Comparar a candidatura ainda não pediam historySummary. O teste passou a executar os dois hooks reais, em vez de apenas fornecer metadados numa renderização; reproduziu falha antes da correcção. Os dois pedidos incluem agora a síntese, e a comparação de candidatura inclui os indicadores/capacidades de publicação actuais para não conservar autoridade visual desactualizada. A preparação do motivo e o único aviso de saída permanecem. A ronda frontend integral/tipos/lint/build foi repetida após esta alteração cliente; a primeira ronda é diagnóstico, sem somar casos repetidos nem alterar a prova149 Feature do servidor, cujo código não mudou. - -### 03/11/2026 — AUD-CRM-01: recuperação da criação de tarefas e conservação da preparação - -[CRM-TASK-CREATION-20261103] Recuperação da criação de tarefas CRM sem duplicar a tarefa/eventos de negócio e sem apagar edições feitas durante o envio. 77 Feature/877 asserções (10 novos), confirmação final sobreposta10/79;1545 frontend (12 novos),41 focados. PHPStan/Pint/tipos/formato/lint/build aprovados. QA45 vazias com owner/RLS/lock conferidos; índice único novo somente em QA. 77 recibos/266 provas anteriores preservados. Recibo crm_task_creation_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-CRM-01, regras existentes de responsável/próxima acção e orientação de23/10 sobre conservar alterações deliberadas. Um Feature reproduziu duas tarefas após repetir o mesmo envio; um caso do componente real reproduziu o apagamento do título alterado enquanto o pedido estava em curso. As provas originais permanecem. A correcção não muda a regra de conversão, consentimento, qualificação ou titularidade do dossier. - -Servidor: CrmTaskCreation usa a autorização efectiva de gestão existente, valida o identificador da tentativa e o conteúdo canónico, bloqueia o lead antes de gravar e preserva PortalAudit. O recibo imutável adicional reutiliza audit_events com origem própria e não guarda título/prazo/texto livre: apenas lead, chave, resumo criptográfico e versão. Repetir a mesma tentativa pela mesma conta/lead confirma o resultado antes de reavaliar prazo/assignee transitórios; dados diferentes com a mesma chave dão409. Outra conta/lead tem âmbito próprio. O índice parcial único reforça a identidade; não foi instalado no activo. Chamadores antigos sem chave conservam o contrato anterior e não recebem por inferência garantia de recuperação. - -A leitura devolve apenas recibos da conta e lead actuais, sem hashes ou envelopes de auditoria. Uma tarefa concluída, alterada ou removida não é restaurada nem recriada pelo reenvio. A autorização HTTP/MFA e a autorização de gestão continuam aplicáveis; perder acesso não permite confirmar por uma chave antiga. A auditoria normal de acesso permanece: a primeira asserção intermédia confundia esse evento com nova gravação de negócio, foi delimitada aos eventos das tarefas e o diagnóstico foi preservado. - -Formulário: congela os dados enviados e o identificador, converte o prazo local para UTC uma vez e recupera exactamente esse pedido após falha de rede/500/interrupção. Os campos continuam a aceitar edições posteriores, conservadas por geração ao confirmar o resultado. A confirmação é conferida por conta/lead/chave/versão/tarefa; uma leitura sem confirmação mantém a tentativa e não dispara nova criação. Uma leitura confirmada evita outro POST. Validação permite corrigir os campos sem consumir a tentativa. Atribuição não editada acompanha o dono actualizado; uma escolha deliberada permanece, incluindo opção anterior indisponível. Um aviso de saída cobre a preparação e a tentativa incerta. O resumo da recuperação mostra os dados enviados, prazo em Maputo e nome do responsável quando disponível. - -Actualização parcial: o novo formulário e o editor de lead/tarefa pedem lead, owners, taskCreation e nextAction juntos. As fixtures dos testes de fila/dossier que importam apenas TaskRow passaram a reconhecer o novo componente sem alterar as verificações de suspensão/âncora. A primeira ronda integral ainda usou essas fixtures antigas e permanece como diagnóstico; a ronda final é a prova corrente. Correcções de formatação e o acesso explícito ao atributo version_no foram verificados sem supressões de análise estática. - -Validação:77 Feature/877 cobrem CRM, conversão, próxima acção, versões, fila, dossiers e orientação;10/79 posteriores à última correcção de servidor estão sobrepostos, não somados como novos. 1545 casos frontend integrais e41 focados, incluindo12 novos, tipos/formato/lint/build.45 tabelas de QA vazias após término dos processos e obtenção do lock, com identidade, owner e RLS/FORCE conferidos. A migração nova é apenas índice e foi conferida em QA. As provas anteriores de concorrência são preservadas; este incremento não declara uma nova prova multiprocesso de criação. - -Estado: reconciliado AUD-CRM-01 de «Implementado com falha» para «Implementado parcialmente», conservando o estado anterior nesta explicação e todas as provas. As falhas concretas de próximas acções/versões/fila já corrigidas não são repetidas como trabalho inexistente; continuam os outros consumidores/perfis, recuperação durável após fecho/reautenticação, apresentação visual e disponibilização. A preparação actual permanece em memória, isolada por lead/conta; não se afirma persistência após fechar a página. Os bundles anteriores são fingerprints históricos substituídos pela compilação corrente. A auditoria integral do portal mantém-se em curso. - -### 03/11/2026 — AUD-CRM-01: preparação recuperável de nova tarefa, por conta e lead - -[CRM-TASK-PREPARATION-20261103] Preparação de nova tarefa CRM cifrada, por conta/lead, com gravação automática, comparação antes de adoptar e retoma do envio original sem duplicar. 48 Feature/369 asserções antes da última normalização;14/123 específicos finais sobrepostos em13 casos (14 novos no total).57 frontend actuais (16 novos,41 sobrepostos com a ronda integral anterior1545, que não foi repetida). PHPStan/Pint/tipos/formato/lint/build aprovados. QA46 vazias/owner/RLS/lock;1 tabela nova somente em QA.78 recibos/278 provas anteriores preservados. Recibo crm_task_preparation_increment_20261103; parcial, sem instalação/escritas no activo. - -Origem: AUD-CRM-01, saldo CRM-TASK-CREATION-20261103 e orientação de23/10 para conservar escolhas ao actualizar/autenticar. A limitação comprovada era a preparação exclusivamente em memória. A continuidade agora acrescentada aplica-se ao formulário de nova tarefa CRM; não é declarada nos restantes editores CRM, parcerias ou em todos os formulários do portal. Não se altera a regra de qualificação, prazo futuro, responsável, conversão ou titularidade do dossier. - -Persistência: a nova tabela crm_task_preparations guarda uma preparação por conta/lead, versão, identificador/resumo da gravação e snapshot cifrado com Crypt. Segue as convenções dos checkpoints do Balcão e das declarações de formação; as respectivas tabelas têm vínculos/kinds próprios e não foram reutilizadas para dados de CRM. A gravação usa o mesmo bloqueio do lead dos outros comandos, recusa versões ultrapassadas, repete a mesma operação sem outra escrita e mantém auditoria mínima (versão, sem texto privado). O downgrade recusa eliminar preparações existentes. O texto parcial e os campos vazios são preservados antes da normalização HTTP; a criação da tarefa conserva a validação de negócio existente. - -Âmbito efectivo: o endpoint está no grupo administrativo existente com autenticação, email verificado, administração no âmbito e protecções globais de sessão/perfil; a recuperação consulta apenas a conta e o lead actuais. A mudança de revisão de acesso invalida a sessão antiga sem substituir a preparação. Os ensaios usam contas sintéticas com MFA, mas isso não constitui prova de uma obrigação universal adicional de MFA no CRM. Nenhum perfil, alçada ou canal novo foi criado. A preparação não é criação/aprovação de tarefa nem alteração de lead, documento ou dossier. - -Interface: alterações são guardadas após800ms e a tentativa congelada é confirmada no servidor antes de enviar a criação. Uma gravação sem confirmação conserva o mesmo identificador para repetição. O envio de negócio continua a usar a chave idempotente já implementada. A recuperação mostra valores desta página/guardados e exige adopção explícita, conserva alterações posteriores e solicita nova escolha se o utilizador alterou um campo depois de escolher o guardado. Um envio local distinto já enviado tem de ser confirmado antes de adoptar outro; a recuperação não dispara criação. Um recibo de criação já existente confirma o resultado e limpa apenas campos não alterados entretanto, mantendo a próxima preparação. - -Continuidade e falhas: alterações durante o envio também podem ser guardadas com o comando original; callbacks de outra conta/página não enviam tarefas. Preparação totalmente confirmada deixa de repetir o aviso de saída; alterações ainda sem confirmação mantêm o único aviso. Falha de gravação/autenticação é explicada e conserva a página. Sem a tabela, a criação manual anterior permanece; dados cifrados ilegíveis são sinalizados e preservados, com continuação explícita apenas nesta página. Não se promete recuperar alterações ainda não confirmadas no servidor após perda da página, nem acesso a dados de outra conta. Não se usa armazenamento local com dados de outros actores. - -Correcções delimitadas pelos testes: o servidor aceitava contadores inteiros escritos como texto e UUIDs em maiúsculas, mas a projecção podia impedir a retoma; um Feature reproduziu o caso e a normalização devolve números/chaves canónicas sem mudar o texto do utilizador. Outro caso reproduziu alteração do instante na retoma noutro fuso com hora local repetida, incluindo perda de segundos. O formulário mantém agora o instante UTC recuperado até o prazo ser deliberadamente editado; a comparação identifica a hora de Maputo. Ambos os resultados originais permanecem como provas. - -Validação:48 Feature/369 antes da última normalização;14/123 finais exercitam todos os14 novos casos, com13 sobrepostos, sem somar rondas como casos novos.57 testes frontend actuais cobrem os16 novos e os41 anteriores dos consumidores CRM/fila/dossier afectados. A ronda integral anterior1545 permanece histórica e não é apresentada como uma execução integral nova. O novo módulo só é importado pelo formulário CRM e pelo detalhe correspondente; tipos globais e compilação foram repetidos. PHPStan nível7 sem supressões, Pint e formato/lint aprovados;46 tabelas QA vazias após terminação e lock, owner/RLS/FORCE conferidos. Nenhuma migração ou escrita no activo, mensagem externa, aceitação visual ou nova prova multiprocesso é inferida. - -Preparação vazia: um checkpoint já concluído e coincidente com os valores da página não volta a exigir comparação apenas por contadores técnicos. O caso actual é exercitado nos16 novos testes frontend; escolhas de responsável já guardadas continuam identificadas sem modificar dados de negócio. - -Saldo: o formulário de nova tarefa tem agora retoma confirmada por conta/lead e comparação; não o repetir como exclusivamente em memória. Continuam pendentes os restantes formulários/consumidores, variantes por perfil, apresentação visual e disponibilização com a migração no destino. O núcleo manual não depende da nova instalação. AUD-CRM-01 e a auditoria integral permanecem parciais. As provas anteriores e fingerprints compilados ficam preservados como históricos, substituídos pela compilação corrente quando aplicável. - -### 03/11/2026 — AUD-EDU-01/03: acompanhamento interno e revisão contextual de declarações - -[EDUCATION-WORK-QUEUE-20261103] Painel interno dos gestores com acompanhamento próprio, revisão independente e detalhe contextual. Revisão fixa a versão analisada, exige comparação se mudou, conserva edições posteriores e repete a mesma tentativa sem nova decisão. Fundamentos anteriores/novos preservados em snapshot cifrado e consulta privada paginada. 30 Feature/629 asserções (16 novos,14 anteriores);22 frontend (17 novos,cinco anteriores). PHPStan/Pint/tipos/formato/lint/build aprovados;54 tabelas QA vazias, owner/RLS/lock conferidos.79 recibos/289 provas anteriores preservados. Recibo education_work_queue_increment_20261103. Parcial local, sem migração/escritas no activo. - -Origem: AUD-EDU-01/03, D-EDU-02/D-EDU-06/D-EDU-08 e as competências internas já existentes em docs/investmoz/education/decisions.md. Os rascunhos privados e os dez cenários de concorrência já aceites em02/11 não foram reimplementados. A orientação de23/10 exige preservar contexto e apresentar a próxima acção aplicável. O proprietário respondeu «nao existe» à pergunta sobre um cadastro/documento aprovado de representação e consentimento para estudantes, instituições formadoras e empregadores. Esta resposta é uma ausência de fonte, não uma autorização para inventar mandatos, consentimento, perfis externos ou dados individuais de estudantes. Esses três percursos continuam pendentes; o gestor interno já autorizado prossegue. - -Painel: acrescentados filtros Todos, Submetidas por mim e Disponíveis para revisão independente, com indicadores pessoais de declarações por tipo/estado/expiração e rascunhos próprios ainda abertos. Quantidades de trabalhadores e vagas formativas não são somadas como declarações. Rascunhos submetidos deixam de contar como abertos, sem duplicar a declaração derivada. As declarações anteriores aos rascunhos também entram no acompanhamento. O âmbito pessoal não reduz as fontes territoriais dos catálogos. Indicadores gerais e percursos de cadastro, procura/oferta, propostas e rascunhos mantidos. A lista disponível para revisão é consulta; não cria atribuições, tarefas, prazos ou concessões. - -Detalhe privado: nova rota /management/education/{demands|capacities}/{id}, com filtros/páginas no regresso, fonte, período, validade, unidades, empregador aplicável e referências do cadastro actual. Nomes actuais não são apresentados como snapshots históricos. Cache no-store e histórico Inertia cifrado; mesmo acesso administrativo interno, verificação de email e exclusão do auditor. O autor não recebe formulário de auto-revisão; fontes expiradas continuam consultáveis. O servidor conserva recusa de auto-revisão, expiração e versão obsoleta. - -Causa reproduzida: dois testes de componente falharam no formulário anterior — o autor recebia a acção e uma decisão preparada podia enviar a versão nova dos props sem comparação. A prova original mostra comportamento do componente; não demonstra uma decisão indevida aceite pelo servidor ou aceitação visual. O novo formulário fixa a versão e valores analisados, compara campos/referências e só adopta a versão actual por acção explícita. Uma tentativa incerta conserva chave, decisão, motivo e versão originais; callbacks tardios de outra página/conta não apagam a preparação. Confirmação limpa apenas os valores enviados que não foram editados depois. Um único aviso de saída protege a preparação em memória. - -Repetição e autoridade: bloqueio do registo e recibo append-only por actor/tipo/registo/chave, com resumo canónico. Mesma tentativa confirmada devolve o resultado sem outra revisão/versão; chave reutilizada com outro conteúdo e nova tentativa obsoleta são recusadas. O acesso actual é sempre exigido. A consulta devolve somente chaves/versões do actor actual para confirmar resultado; não expõe resumos ou o envelope cifrado. Repetir recibo antigo após decisão posterior ou expiração não reescreve o estado nem prolonga a validade. O contrato antigo sem chave continua sujeito a conflito de versão e também preserva o fundamento. - -Preservação: cada nova revisão acrescenta evento restrito com snapshot Crypt do objecto revisto, estado/motivo/revisor imediatamente anteriores e novos. A consulta privada mostra fundamentos disponíveis, versão, data e nome actual do revisor, com paginação estável por versão. Fundamentos anteriores à implementação que nunca foram armazenados não são reconstruídos. Envelope ilegível conserva metadados/original e explica indisponibilidade. A auditoria permanece append-only; um primeiro ensaio que tentou alterar um evento foi recusado pela guarda existente. O teste foi corrigido para inserir uma amostra sintética separada, sem desactivar a guarda. - -Validação: 30 Feature/629 asserções finais no conjunto Educação afectado (16 novos e14 anteriores).22 frontend actuais (13 de revisão,quatro de painel e os cinco de rascunhos existentes). A ronda integral1545 anterior permanece histórica, sem ser apresentada como execução actual. PHPStan nível7 sem supressões, Pint, tipos globais, formato/lint de sete fontes e build aprovados. O contrato do serviço de histórico passou a devolver dados paginados serializáveis, evitando expor um paginator mutável com parametrização incompatível.54 tabelas vazias verificadas após fim dos processos e aquisição do lock, proprietário e RLS/FORCE conferidos. Sem migrações novas, dados activos, mensagens externas ou nova prova multiprocesso deste comando. O build conserva os avisos já existentes sobre fontes e dimensão de bundles, sem falha. - -Saldo: AUD-EDU-03 passa de não implementado a implementado parcialmente pelo percurso interno do gestor. Restam jornadas de estudantes, instituições e empregadores, definição concreta de representação/consentimento e respectivo isolamento, apresentação visual e entrega no destino. AUD-EDU-01 continua parcial; AUD-EDU-02 mantém a cobertura e saldo próprios já reconciliados. O motivo de revisão ainda não confirmado permanece na página; não se declara recuperação durável dessa preparação após perda da página. O registo de revisão é decisão interna, não acredita instituição/curso nem substitui mandato institucional. A auditoria integral do portal continua em curso. - -### 03/11/2026 — AUD-PROFILE-20: incidentes técnicos e perfil próprio de suporte - -[OPPORTUNITY-TECHNICAL-INCIDENTS-20261103] Registo automático de falhas técnicas de submissão/publicação, referência correlacionada, consulta própria e perfil próprio de Suporte técnico com fila por organização/tipo. Reutiliza auditoria append-only e atribuições existentes, sem aprovação ou acesso documental adicional.15 Feature/264 asserções (oito novos,sete anteriores);12 frontend (seis novos,seis anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Base final QA com59 tabelas vazias, owner/RLS/lock conferidos; primeira execução mista acompanhada separadamente.80 recibos/298 provas anteriores preservados. Recibo opportunity_technical_incidents_increment_20261103. Parcial local; migração do papel somente em QA, sem alterações no activo. - -Origem: Gestao de perfis investeMOZ v1.docx SHA256f9e0f6280566fed8b52d0b36bb814a82e11976fec9ea9f62d64611ff8c824b38, §3.5/p283 e tratamento de falhas p289–293, segregação/atribuição p33/339–346; segmentação bf26caee §8.4/p860. Matriz e código confirmavam que falhas técnicas de submissão/publicação não produziam incidente de negócio consultável. Não se confunde isto com C132, diagnósticos de autenticação, suporte fundiário ou registos de scan/worker existentes. A ronda anterior de Educação foi verificada antes do delta. O proprietário respondeu «Perfil próprio de Suporte técnico» à escolha do destinatário: essa decisão autoriza o papel e a fila; não cria pessoas reais, prazos/SLA, canais externos ou competências de aprovação. - -Registo: OpportunityWorkflowExecution envolve o motor existente, sem alterar as regras das transições. Para submissão/publicação efectivamente disponíveis ao actor, uma excepção técnica após a transacção gera evento restrito separado. Validação, versão ultrapassada, autenticação, permissão e 404 não são convertidos em incidentes. O registo conserva referência UUID útil para acompanhamento/correlação, operação, versão e revisão observadas antes da tentativa, etag tentado, estado, organização/tipo e código técnico genérico. Não copia motivo, contrato, anexos, SQL, mensagem ou trace da excepção. Cada pedido que falha é uma tentativa observada distinta; não se afirma deduplicação de um incidente lógico entre várias falhas. - -Resultado incerto: HTTP503 no-store explica a referência e exige consultar o estado antes de repetir. Não há repetição automática, aprovação, publicação ou inversão de estado pelo incidente. O evento de falha é gravado só depois de a transacção de negócio terminar; os testes provocam falha real na inserção da auditoria final, após alterações de estado/tarefas, e conferem reversão de todos esses dados. Uma perda de ligação no commit pode deixar resultado incerto: a mensagem não promete reversão universal. Se também falha o registo do incidente, devolve incident_recorded=false e a referência, sem alegar persistência; log de fallback contém apenas referência/código. Uma subtransacção protege a ligação quando existe uma transacção envolvente. - -Consulta e encaminhamento: o autor consulta até dez tentativas próprias no detalhe autorizado da oportunidade. A fila /suporte-tecnico/incidentes apresenta20 metadados por página e apenas os âmbitos actuais atribuídos a technical_support. Organização/tipo capturados também têm de coincidir com o registo actual; contexto desconhecido ou posteriormente mudado não é inferido. A fila não expõe título/contrato, documento, identidade do promotor, etag, JSON bruto ou link para um processo reservado. Auditor prevalece como restrição; revogação/expiração são reavaliadas. A fila é o encaminhamento interno por perfil, não prova de uma mensagem entregue ou de um tratamento concluído. - -Papel: acrescentado ao mecanismo existente de atribuição independente por Superutilizador/MFA, com tipo, organização, motivo, vigência, revogação e auditoria. Nova versão profiles-technical-support-20261103 para essas atribuições; restantes papéis conservam a versão anterior. A interface apresenta Suporte técnico e o link apenas pela capacidade do servidor. O novo papel não integra hasOperationalReadScope, Promotor, Validador, Publicador ou administração legada; não recebe aprovações, concessões, acesso a anexos ou alçada por inferência. Pode coexistir com papéis legítimos anteriores nos limites da política existente. Não foi criada uma obrigação universal adicional de MFA para este perfil; a outorga continua a exigir a competência administrativa e MFA já vigentes. - -Instalação: a migração080000 amplia somente a restrição de nomes de papéis. Segue a guarda existente de instalação autenticada dos perfis fora de testing e exige QA isolada nos testes. O downgrade recusa remover a compatibilidade se existirem atribuições, mesmo históricas. Não altera atribuições antigas nem concede o novo papel automaticamente. Preparada e aplicada apenas na base descartável; integração desta actualização no instalador e disponibilização no destino ainda por concluir. - -Validação:15 Feature/264 finais no código actual (oito novos e sete de PortalProfileAccess).12 frontend exercitam leitor próprio, navegação por capacidade, fila vazia/metadados e transporte de erro sem repetir escrita, mais seis casos anteriores de profileJson. Tipos globais, PHPStan nível7 sem supressões, Pint, sete fontes formato/lint e build aprovados. A suite integral1545 anterior permanece histórica. A primeira execução mista de incidentes/canónico/perfis tem resultado separado running_observed; não é declarada suite global aprovada. A primeira fixture de incidentes omitia a gravação do contrato completo e o servidor recusou correctamente a submissão422; foi corrigida a fixture, conservando as validações. Corrigida também a expectativa do contrato de atribuição201, sem mudar a API. Provas falhadas preservadas como diagnóstico. Duas bases QA distintas foram usadas enquanto a primeira execução ainda estava confirmadamente activa; não se reiniciou por falta de output. A execução final de15 casos terminou;59 tabelas vazias na base technical_support, owner/RLS/FORCE e lock conferidos. A primeira execução mista permanece separada: se ainda activa, o seu log mutável e a limpeza dessa base não são incluídos nas provas aceites; continuar a acompanhar o mesmo processo e conferir rollback quando terminar. Sem escritas/migrações activas, contas reais, mensagens externas ou prova visual. - -Saldo: AUD-PROFILE-20 passa a implementado parcialmente. O registo, preservação delimitada e encaminhamento por fila/perfil estão agora implementados; continuam tratamento do incidente (assunção, notas, resolução/reabertura e histórico), alertas próprios/painel de saúde, outros pontos de falha/upload/worker/integrações, escalonamentos e parâmetros operacionais conforme definição aplicável, instalador e entrega, variantes e apresentação visual. A decisão sobre o perfil está resolvida e não deve ser pedida de novo. Próxima acção: acrescentar o tratamento auditado à fila usando este mesmo papel e a referência, sem tocar na decisão da oportunidade. A auditoria integral permanece em curso. - -### 03/11/2026 — AUD-PROFILE-20: tratamento auditado e recuperação do envio de suporte - -[TECHNICAL-INCIDENT-HANDLING-20261103] Tratamento de incidentes pelo perfil existente: assunção/substituição explícita, notas cifradas, devolução à fila, resolução e reabertura, histórico privado paginado e filtros pelo estado actual. Versão e tentativa identificada preservam notas e impedem repetição de efeitos.18 Feature/339 asserções (dez novos,oito anteriores);28 frontend (16 novos,12 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. Um cenário com dois processos e espera real no incidente:200/409, replay só de leitura, investimento e raiz intactos. QA final59 tabelas vazias; prova concorrente retém só amostras sintéticas declaradas.81 recibos/306 provas anteriores preservados. Recibo technical_incident_handling_increment_20261103. Parcial local, zero novas migrações/escritas activas. - -Origem e âmbito: continuação do incremento OPPORTUNITY-TECHNICAL-INCIDENTS-20261103 e da decisão expressa do proprietário «Perfil próprio de Suporte técnico». Reutilizados o mesmo papel technical_support, âmbitos/validade/revogação e os incidentes já registados. O tratamento é técnico e não decide investimentos. Não foram criadas competências de Promotor, Validador, Publicador, administrador, SLA, calendários ou pessoas reais; a regra do dono para encerrar/reabrir dossiers permanece intacta. - -Percurso: nova ficha /suporte-tecnico/incidentes/{reference}, ligada à fila e ao contexto de página/estado. Permite assumir tratamento, substituir explicitamente o responsável actual por si, acrescentar nota, devolver à fila, resolver e reabrir. A equipa autorizada no âmbito partilha o tratamento; não se introduziu uma autoridade exclusiva do responsável que não tinha sido definida pela Tempo. Cada acção exige nota e a versão analisada. Resolver um incidente não submete, publica, aprova ou reverte a oportunidade. Notas de incidente resolvido não reabrem implicitamente. Fila Todos/Na fila/Em tratamento/Resolvido consulta o estado mais recente, com paginação normal e regresso ao mesmo contexto. - -Uma fonte de histórico: cada tratamento acrescenta evento restrito à auditoria append-only existente, correlacionado à raiz; nenhum evento anterior é actualizado/eliminado. Preservados estado, responsável, versão e datas anteriores/aplicados; nota cifrada com Crypt. A nota não é copiada para o incidente original ou para o investimento. A ficha mostra autores pelo nome actual da conta, com10 eventos por página; não inventa nomes históricos. Envelope ilegível é assinalado e preservado. Estado actual inválido não volta silenciosamente a Na fila e recusa nova escrita. A projecção opcional na fila e no editor mostra indisponibilidade; o estado técnico ilegível não bloqueia a leitura/edição normal do investimento, demonstrada por HTTP. - -Autoridade e isolamento: raiz lida pelo mesmo filtro de organização/tipo capturados e actuais, mais atribuição efectiva de suporte, validade e restrição Auditor. No comando, reavaliado sob bloqueio FOR UPDATE OF event apenas na raiz do incidente. Não se bloqueia/edita o investimento como forma de obter autoridade. Notas internas ficam no detalhe autorizado; o autor da tentativa recebe somente estado/versão/data técnica na consulta própria, sem notas, chaves ou responsável interno. Assumir ignora um destinatário injectado pelo cliente e usa a conta autenticada. A atribuição não se amplia por igualdade de nome, perfil acumulado ou mera posse da referência. - -Repetição segura: operation_key UUID normalizado, resumo canónico de versão/acção/nota e actor, dentro da raiz bloqueada. Mesmo comando confirma o resultado anterior sem outra nota/versão ou mudança de responsável. Outra nota com a mesma chave e uma nova chave sobre versão obsoleta são recusadas. Recibo antigo após uma resolução posterior não a desfaz. Falha na inserção final reverte o tratamento; a tentativa original pode ser repetida explicitamente. A operação não dispara outro incidente em cascata nem repete automaticamente comandos do investimento. - -Formulário: congela comando, versão, nota e chave antes do POST; guarda a preparação na memória da página. Resposta incerta conserva o envio original e a nota editada depois. Confirmação limpa apenas texto não alterado entretanto. Consulta autorizada pode confirmar o recibo sem novo POST; mudança da equipa exige comparação e confirmação explícita. Uma preparação obsoleta só é abandonada após leitura de versão superior que impede o envio antigo e acção explícita do utilizador. Consulta na mesma versão não descarta uma tentativa incerta. Callbacks antigos/de outra conta não apagam a nota nem desbloqueiam o envio seguinte. Um único aviso protege saída/recarregamento; não se afirma recuperação durável da nota ainda não confirmada depois da perda da página. O próprio perfil e a consulta do recibo não concedem acesso adicional. - -Validação:18 Feature/339 no código final, dez casos novos e os oito de incidentes/perfis anteriores.28 frontend actuais,15 do novo formulário mais um novo caso de ligação/contexto e os12 consumidores/transportes anteriores. Tipos globais, PHPStan nível7 sem supressões, Pint e nove fontes de formato/lint passaram; build com avisos de fontes opcionais/tamanho já conhecidos. Ronda integral1545 anterior continua histórica. Um ensaio sintético real com dois processos observou o primeiro bloqueado numa barreira QA após adquirir a raiz e o segundo à espera dessa mesma transacção. Após libertar, o primeiro recebeu200 e o segundo409; resolução posterior e repetição antiga conservaram versão2/resolvido, oportunidade, raiz e zero tarefas. Não é teste de carga ou de todas as intercalações. - -Conservação QA: incident_handling_20261103_test terminou e ficou com59 tabelas vazias; lock, identidade, owner/RLS/FORCE conferidos. O clone descartável incident_handling_concurrency_20261103b_test retém4 contas sintéticas,uma organização,uma oportunidade,duas atribuições,três eventos e zero tarefas, com visibilidade conferida. A nova execução nesse clone foi recusada com exit1 por dados existentes, sem os redefinir. O primeiro ensaio concorrente tinha comparação de atributos antes de recarregar os defaults de PostgreSQL; corrigida a fixture de comparação e repetido noutro clone, preservando o primeiro e o seu diagnóstico. A guarda CLI passou a devolver exit1 explicitamente numa excepção, em vez de depender do handler da aplicação. Nenhuma tabela nova, migração ou operação activa decorre deste tratamento. - -Execução mista anterior encerrada: o processo53686 terminou com45 casos,41 aprovados,quatro falhados e1004 asserções, com um aviso de teste arriscado. As quatro falhas pertencem à fixture antiga de incidentes sem contrato gravado, não à validação canónica/perfis; a expectativa de logging não chamada originou o aviso. Os40 casos anteriores do canónico/perfis passaram naquela execução; não se reclassifica a execução completa como aprovada ou candidata imutável. Os casos de incidentes corrigidos passaram depois nos15 casos do incremento anterior e voltam a passar nos18 actuais. A base opportunity_incidents_20261103_test também ficou vazia nas59 tabelas, com lock/owner/RLS/identidade conferidos. O registo anterior running_observed fica preservado como observação histórica e está agora superado por este resultado terminal. - -Saldo: registo, fila, perfil e tratamento técnico com histórico/recuperação delimitada implementados e verificados localmente. Restam alertas/notificações próprias, saúde e outros pontos de falha/upload/worker/integrações, regras operacionais/escalonamentos quando definidas, integração no instalador e disponibilização, apresentação visual e retoma durável da preparação não confirmada. Não voltar a pedir a escolha do perfil nem a tratar o ciclo agora implementado como inexistente. AUD-PROFILE-20 e o objectivo transversal continuam parciais; próxima acção é integrar a actualização no instalador existente e continuar os alertas autorizados por âmbito, sem novos canais externos por inferência. - -### 03/11/2026 — AUD-PROFILE-20: actualização de Suporte técnico pelo instalador existente - -[SUPPORT-PROFILE-INSTALLATION-20261103] Actualização do perfil de Suporte técnico integrada no instalador autenticado existente: prévia, MFA, provas do destino/código, confirmação e recibo idempotente. Schema e ledger partilham a mesma verificação no servidor e na disponibilidade do perfil.18 Feature finais/230 asserções (dez novos,oito do instalador anterior); regressão inicial36/569;30 frontend (15 novos,15 do tratamento anterior),PHPStan/Pint/tipos/formato/lint/build aprovados. Backup PostgreSQL e arquivo de candidato/original privado sintético efectivamente restaurados em QA: 190 tabelas,30 sequências,1567 ficheiros e três envelopes MFA legíveis. Actualização e repetição conservaram todas as tabelas salvo uma entrada de migração e um recibo; zero atribuições de suporte inferidas. QA de testes62 tabelas vazias.82 recibos/318 provas anteriores preservados. Recibo support_profile_installation_increment_20261103. Parcial local, sem instalação/escrita activa. - -Origem: continuação da decisão expressa do proprietário «Perfil próprio de Suporte técnico» e do tratamento já demonstrado. O instalador da base de perfis permanece a autoridade existente. Nova prévia/aplicação em /management/profile-install/technical-support, acessível pela instalação de perfis; exige identidade verificada e autoridade actual de instalação, incluindo precedência da restrição Auditor. Escrita e replay exigem MFA recente da sessão. Não altera as condições de acesso quotidiano do suporte nem escolhe pessoas, SLA, canais ou responsáveis por inferência. - -Instalação delimitada: migra exclusivamente 2026_11_03_080000_add_technical_support_profile, já existente no incremento anterior, sob a transacção/lock e recibo do instalador. Reavalia dependências, destino, código, prova e estrutura analisada antes de executar. Atribuições, contas, dupla administrativa, dados de negócio e flags não são criados/redefinidos pela actualização. A atribuição do papel continua a operação explícita e auditada na Gestão de perfis. O replay devolve o recibo anterior sem repetir DDL; motivo diferente com a mesma chave é recusado. Falha na auditoria final reverte constraint e ledger. - -Uma interpretação de estrutura para runtime e instalador: TechnicalSupportProfileSchema verifica a CHECK validada e exacta portal_role_name e o registo da migração. O ledger isolado deixa de anunciar o perfil disponível. Reconhece a versão anterior de quatro papéis e a nova de cinco. Se a migração está registada mas a CHECK validada ainda é exactamente a anterior, oferece reposição delimitada com as mesmas provas e autenticação, preservando o registo da migração. CHECK ausente, enfraquecida, desconhecida ou cinco papéis sem ledger não são sobrescritos/adoptados implicitamente. Downgrade conserva a recusa perante atribuições de suporte, incluindo revogadas. - -Prova técnica existente fortalecida: mantém a janela de24 horas e backup/restauro, ficheiros, compatibilidade e QA já exigidos. Flags devem ser booleanos true; texto «false», metadados de outro tipo, data futura/expirada, destino/código diferente e ficheiro adulterado não confirmam preparação. O hash dos bytes da prova participa no plano: outra prova válida exige nova análise. Não se acrescentou uma aprovação humana, uma fonte organizacional ou um calendário. No-op de actualização já instalada segue o padrão anterior, sem repetir migração ou conceder privilégios. - -Formulário: motivo e confirmação próprios desta operação; congela plano, motivo e chave antes do POST. Resultado incerto permite apenas repetição explícita do original ou consulta autorizada do recibo próprio. Ausência do recibo não descarta a tentativa; mudança do plano exige comparação e nova confirmação. Resposta de outra conta/destino/chave/código não confirma. MFA expirada impede retry até nova confirmação de sessão. Callbacks antigos não alteram outra preparação. Confirmação limpa só o motivo ainda inalterado; edições posteriores permanecem. Consulta antiga sem o recibo conhecido não desbloqueia outra operação. Corrigida mensagem antiga de erro que persistia depois de consulta recuperada. Preparação continua em memória, sem promessa de retoma durável após perda da página. - -Protecção da preparação: um único guard comum protege saída/recarregamento. A página anterior de instalação também protege motivo e IDs dos dois titulares. Depois de resposta de escrita conhecida, campos efectivamente enviados deixam de gerar aviso falso, mesmo se a consulta seguinte falhar; alterações posteriores e campos não enviados continuam protegidos. Os percursos de inicialização separada e confirmação pelo segundo titular não foram substituídos. - -Verificações:36 Feature/569 na primeira regressão de instalação, incidentes e tratamento; depois da correcção/normalização final do formulário,18 Feature/230 focados nos dez novos casos e oito do instalador anterior.30 frontend finais incluem15 novos e15 do tratamento prévio. PHPStan nível7 nos quatro serviços/controlador alterados sem supressões; Pint nas cinco fontes PHP; tipos globais e seis fontes de formato/lint passaram; build concluído com os avisos já conhecidos. Erros iniciais de frontend foram reproduzidos e corrigidos. Cache de Pint devolvia resultado desactualizado na reparação; cache específica nova aplicou a formatação e o teste final passou. Não se repete nem se reclassifica como actual a ronda integral1545 histórica. Testes de componentes/HTTP não equivalem a aceitação visual em browser. - -Ensaio operacional distinto das fixtures: SupportProfileInstallationTest usa ficheiros sintéticos para testar o contrato de readiness e declara-o expressamente. A prova operacional adicional criou dois destinos novos em127.0.0.1:55441 como investmoz_test: support_profile_installation_operational_20261103c_test e support_profile_installation_restore_20261103c_test. Template conferido antes da cópia: sem dados de negócio e com os seeds existentes de spatial_ref_sys(8500),questionnaire_versions(2) e ai_controls(7) preservados. A primeira guarda recusou essas tabelas de referência antes de criar qualquer clone; a condição foi corrigida para conferir as contagens exactas, sem apagar os seeds. Nenhuma base existente redefinida. Snapshot read-only/repeatable-read exportado para pg_dump e restaurado por pg_restore; comparadas todas as tabelas por bytes ordenados e sequências, owner/RLS/FORCE, mais legibilidade dos três envelopes MFA sintéticos. O primeiro ensaio restaurou tabelas e sequências, mas a sua guarda rejeitou RLS existente por esperar incorrectamente todas as tabelas sem RLS. A comparação confirmou16 tabelas com RLS/FORCE idênticos na origem/restauro. Preservado esse clone/diagnóstico, corrigida a guarda para exigir equivalência de owner/RLS e visibilidade efectiva da identidade QA, e repetido em dois destinos novos de sufixo b. Nenhuma política ou permissão foi desligada/alterada para o ensaio. No clone b, a actualização e o replay ocorreram, mas a asserção PHP do ensaio comparava identidade de objecto stdClass com o array do recibo JSON. Corrigida a comparação para valores canónicos tipados, preservado também esse clone e repetida a prova integral no sufixo c. O resultado falhado do ensaio b não é convertido numa aprovação global. Arquivo de código/build e um original privado sintético extraído com guarda de caminhos e hashes conferidos. Não arquiva .env nem documentos de clientes e não afirma restauro de um destino activo. - -Após essa prova real, o serviço autenticado do instalador com actor sintético e MFA aplicou a actualização e confirmou o mesmo recibo no replay. De todas as tabelas, só migrations e audit_events mudaram, com exactamente uma linha adicional em cada; contas, dupla, atribuições anteriores, oportunidade e restantes tabelas conservaram o hash. Nenhum perfil de suporte concedido. O clone operacional e o restauro anterior são retidos como provas sintéticas; nova execução nesse destino é recusada com exit1 antes de qualquer reset. O ensaio não é aceitação de cliente, instalação activa nem instalação no SGF/SGC. QA de testes terminou com62 tabelas vazias, lock/owner/RLS/identidade conferidos, incluindo dupla, pedidos de perfis e aprovações de segurança. - -Saldo: integração da actualização de suporte no instalador implementada e demonstrada localmente; a disponibilização/instalação no destino continua a acção autenticada própria com provas desse destino. Restam alertas próprios por âmbito, saúde/outros limites de falha, parametrização/escalonamentos aplicáveis quando definidos, retoma durável da preparação e aceitação visual. AUD-PROFILE-20 e o objectivo transversal permanecem parciais. Conservar decisões já recebidas sobre suporte, dono do dossier, línguas/modelos e Educação; não voltar a pedir essas definições nem inventar fontes ausentes. Próxima acção: continuar avisos internos de incidentes aos suportes efectivos, reutilizando mecanismos existentes e preservando autorização actual. - -### 03/11/2026 — AUD-PROFILE-20: avisos internos de incidentes por consultar - -[SUPPORT-INCIDENT-NOTICES-20261103] Avisos internos de incidentes por consultar para o Suporte técnico efectivo, com contador próprio na navegação, filtro antes da paginação e marca explícita de consulta por actor/raiz. A consulta não é tratamento, resolução, aprovação ou acesso documental.25 Feature finais/376 asserções (sete novos,18 de instalação anteriores);31 frontend (nove novos,22 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. QA62 tabelas vazias e identidade/owner/RLS/FORCE conferidos.83 recibos/330 provas anteriores preservados. Recibo support_incident_notices_increment_20261103. Parcial local, sem migração ou escrita activa. - -Origem e recorte: desenvolvimento autorizado a partir da decisão do proprietário «Perfil próprio de Suporte técnico». Aviso interno ao papel e âmbito efectivos, reutilizando a fila e o histórico existentes. Escolha técnica de apresentação: contador no link de Suporte técnico da navegação dos perfis, filtro Por consultar/Todos os avisos e acção explícita de consulta em cada incidente, na fila e no detalhe. Não se inventam destinatarios nominativos, email/SMS/outros canais, SLA ou escalonamentos. Nenhuma mensagem externa foi enviada. - -Autoridade unica: contador, filtro, detalhe e marca usam a mesma query de incidentes autorizados: papel vigente e verificação de Auditor, organização/tipo capturados e actuais e oportunidade existente. Sobreposicao de atribuições não duplica o incidente. Revogacao, expiração, falta de verificação de identidade e mudanca de contexto retiram a visibilidade; ser gestor legado ou autor da tentativa não concede suporte. Sem dados de processos, documentos ou notas no aviso da navegação. Outros actores não recebem o estado de consulta de um colega. - -Estado próprio: Por consultar significa ausência da marca explícita deste actor para esta raiz. Abrir uma página GET não escreve a marca. Marcar aviso como consultado regista um evento restrito append-only em audit_events, fonte portal-opportunity-support-notices e acção incident_consulted. A raiz é reautorizada sob o mesmo bloqueio de linha antes da consulta/inserção. A repetição devolve a primeira data/confirmação sem duplicar eventos. O actor provem da sessão e não de um destinatario injectado no corpo. A marca não altera a raiz original, a versão de tratamento, responsável, notas, oportunidade, tarefas ou atribuições. Incidente resolvido pode ter aviso por consultar; consulta não equivale a resolução. Cada novo incidente tem uma raiz própria e um novo aviso; alteracoes posteriores de tratamento não são novos avisos neste recorte. - -Filtros e continuidade: a exclusão de avisos ja consultados ocorre no SQL autorizado antes do limite/paginação, pelo que incidentes antigos por consultar não são ocultados por muitos recentes consultados. Estado técnico e Por consultar combinam-se; os links dos filtros e detalhe preservam ambos, página de origem e regresso. Metadados de tratamento invalidos continuam assinalados como indisponiveis na fila, sem impedir consulta do aviso. O histórico de tratamento ignora os eventos de consulta e continua a mostrar apenas as suas próprias acções. - -Formulário sem dados reintroduzidos: a consulta e um comando com corpo vazio para a raiz e conta actuais, sem outro motivo ou confirmação de decisão. Bloqueia duplo clique enquanto aguarda. Confere actor/referencia/read da resposta e, em perda de resposta, oferece repetição explícita da mesma acção comutativa. Não repete HTTP automaticamente. Previa autorizada com a marca própria confirma o estado e prevalece sobre resposta falhada tardia; props antigas não voltam a colocar um aviso confirmado como não consultado. Callback de outra conta/raiz ou apos desmontar não actualiza a página nova. A actualização parcial preserva estado/scroll e notas em preparação; usa o guard ja existente do tratamento, sem outro aviso de saida. - -Falhas: inserção final recusada reverte a marca e permite nova tentativa explícita. O contador é uma projecao opcional: uma falha SQL devolve indisponibilidade sem zero inventado e usa transacção/savepoint para não deixar a transacção do chamador abortada. Teste PostgreSQL concreto de coluna temporariamente indisponivel demonstrou a falha, continuacao da leitura de users e recuperação da contagem depois de reposta a coluna, exclusivamente dentro da base descartavel. Nenhuma guarda RLS/owner/isolamento foi desligada para esse ensaio. - -Verificação:25 Feature finais/376 no código final, sete casos novos mais18 de ambos os instaladores. A execução inicial de43 casos terminou com41 aprovados,uma falha e um erro,664 asserções. Os36 casos anteriores passaram; a falha nova era a ordem normalizada do cabeçalho Cache-Control e o erro era uma fixture com expires_at anterior ao starts_at, recusada pela constraint portal_role_period. Corrigidos ambos os dados do ensaio, preservado o diagnóstico e repetidos os25 casos finais. A opção preserveScroll na chamada de reload foi removida porque o Inertia instalado preserva scroll/estado automaticamente e os seus tipos recusam essa opção nessa chamada.31 frontend finais, sete casos de confirmação/recuperação/contexto e dois de contador/filtros, com22 anteriores. PHPStan nivel7 nos quatro serviços/controlador alterados, sem supressões; Pint em cinco fontes PHP, tipos globais, oito fontes de formato/lint e build passaram. A ronda integral1545 continua prova histórica. QA support_incident_notices_20261103_test terminou com62 tabelas vazias, incluindo identidades, atribuições, dupla, pedidos, aprovações e auditoria, conferidas sob lock, owner/RLS/FORCE e identidade investmoz_test em55441. Sem novas tabelas ou migrações; não se afirma um novo ensaio concorrente nem aceitação visual. - -Conservação e saldo:83 recibos/330 provas anteriores preservados. O ensaio efectivo de backup/restauro do incremento de instalação continua histórico para o candidato ali arquivado; não é reclassificado como prova de instalação deste novo fingerprint. O instalador inclui também o novo componente na impressão do candidato e exige prova actual do destino/código para alterar schema. Mantém-se disponibilização autenticada no destino e aceitação visual, saúde e outros pontos de falha/upload/worker/integrações, avisos de actualizações posteriores de tratamento, regras/escalonamentos aplicaveis e retoma durável da preparação não confirmada. Alertas de novos incidentes por consultar deixam de ser lacuna de implementação neste recorte; AUD-PROFILE-20 e o objectivo transversal continuam parciais. Próxima acção: continuar limites técnicos de upload/integração e saúde operativa com as fontes existentes, sem inventar política organizacional. - -### 03/11/2026 — AUD-PROFILE-20: incidentes de uploads e preservação de originais em falhas - -[RESOURCE-TECHNICAL-INCIDENTS-20261103] Incidentes de upload de documentos/imagens e preparação WebP integrados no mesmo suporte, avisos e tratamento por âmbito. Limpeza conservadora conserva originais referenciados e bytes de resultado incerto; falhas na limpeza não escondem o erro original.23 Feature/285 asserções (oito novos,cinco de recursos e dez do instalador); um caso adicional sem GD/duas asserções;37 frontend (seis novos,31 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados. GD/WebP carregado apenas no processo CLI de QA; configuração normal sem alteração. QA64 tabelas vazias, com identidade/owner/RLS/FORCE conferidos.84 recibos/339 provas anteriores preservados. Recibo resource_technical_incidents_increment_20261103. Parcial local, sem migração ou escrita activa. - -Origem e âmbito: continuação da decisão do proprietário «Perfil próprio de Suporte técnico» e do saldo de falhas de upload no requisito existente. Aproveitados o papel, âmbitos, fila, avisos individuais e tratamento já implementados. Acrescentados os pontos síncronos de carregamento de documentos/imagens e preparação de derivadas. Não foram criados destinatários, canais externos, SLA, perfis adicionais ou competências de decisão. Outros limites técnicos continuam no saldo; não se declara cobertura de todas as falhas do portal. - -Uma classificação comum de falhas: OpportunityTechnicalExecution é reutilizado pelo adaptador de submissão/publicação e pelos pontos de upload/preparação. A chamada já tem acesso efectivo de edição conferido; o incidente só é capturado depois de a transacção de negócio terminar/desfazer. Validação, autenticação, autorização, ausência de registo e respostas esperadas inferiores a500 são preservadas, incluindo o HttpResponseException409 usado nos recursos. Não repetem HTTP, gravação ou decisão automaticamente. Nos uploads, a fronteira inclui também a construção da confirmação e leitura do ETag posterior à gravação: uma falha posterior não pode ser apresentada como sucesso confirmado nem pressupor rollback do que já foi gravado. - -Resposta e privacidade: preservada a excepção de compatibilidade, com resposta JSON503 própria, referência UUID e incident_recorded verdadeiro/falso. Falha a guardar o próprio incidente continua assinalada honestamente. A resposta e a raiz não incluem SQL, texto da excepção, bytes, nome do ficheiro, título, motivo ou payload do recurso. A raiz conserva somente a conta, oportunidade/organização/tipo, operação e versões/estado técnicos já usados pelo mecanismo. O autor consulta os seus últimos dez incidentes também na página de recursos, com acesso actual, no-store e histórico cifrado. O suporte continua restrito ao âmbito actual/capturado e não ganha acesso ao recurso original ou ao investimento; HTTP demonstrou a fila disponível e o editor de recursos403 para o mesmo suporte. - -Operações identificáveis: upload_document, upload_image e prepare_image juntam-se a submit/publish. Cartão do autor, fila e ficha partilham os nomes Carregamento de documento/Carregamento de imagem/Preparação de imagens WebP. Operação desconhecida deixa de ser apresentada por defeito como Publicação. A mensagem genérica da fila foi ajustada para a operação. O catálogo de leitura do servidor reconhece apenas estas operações no recorte. Avisos por consultar e tratamento usam a mesma raiz e mantêm-se independentes da operação de investimento e da análise de segurança. - -Originais e limpeza: corrigida a eliminação incondicional no catch do upload/processamento. OpportunityResourceFileCleanup considera somente chaves no prefixo privado previsto e não apaga qualquer chave ainda referida por documents, incluindo históricos/excluídos logicamente. Perda de ligação reconhecida pelo detector do próprio Laravel conserva os bytes sem usar uma leitura de ausência que poderia preceder um commit incerto. Falha na verificação da referência também conserva os bytes, com transacção/savepoint para não deixar o chamador abortado. Só se tenta retirar um novo ficheiro sem referência confirmada. Falha/false na eliminação produz aviso sanitizado e não substitui o erro original, nem expõe o caminho ao suporte. Não há purge automático de bytes retidos; essa reconciliação permanece necessária. O ramo de ligação incerta foi ensaiado por injecção de falha observável, não por corte real de rede ou todas as intercalações possíveis de commit. - -Visibilidade efectiva: a referência só é considerada ausente se row_security_active confirmar que a leitura não está sujeita a RLS. RLS activa ou visibilidade indeterminada conserva os bytes. Um caso PostgreSQL real activou RLS/FORCE apenas na tabela descartável e usou SET LOCAL ROLE pg_read_all_data, papel preexistente sem criar contas/grants. A mesma referência ficou oculta: contagem0 e row_security_active true. A limpeza conservou o ficheiro; depois de RESET ROLE para a identidade original de QA, a referência continuava a existir, contagem1, e current_user voltou a investmoz_test. A diferença de identidades está declarada e demonstra por que ausência numa leitura filtrada não prova ausência de referência. RLS/role e registos do ensaio foram revertidos na transacção de teste; a conferência final voltou a encontrar as64 tabelas vazias e a visibilidade normal. Não se desliga RLS no produto para decidir uma limpeza. - -Escritas parciais: o store inicial agora conhece a chave antes de tentar guardar e trata a falha parcial mesmo antes da transacção de negócio. Na preparação de derivadas, a chave nova é registada para limpeza antes do put, cobrindo drivers que escrevem parte e devolvem false. O ensaio actual gerou uma imagem sintética, verificou o original com CleanScannerFixture, injectou a falha de armazenamento durante a primeira derivada e demonstrou original cifrado intacto, versão/payload da imagem e oportunidade inalterados, uma única linha de documento original e ausência dos novos bytes sem referência. Esse scan sintético não prova segurança de um ficheiro real. - -Dependência GD explícita: a configuração normal deste PHP continua sem GD/WebP. A extensão já disponível foi carregada apenas com -d extension=gd no processo CLI isolado, permitindo executar realmente o percurso anterior e os cinco casos de recursos existentes. Metadados dos dois processos confirmam GD/WebP true/true e false/false, sem alterar php.ini ou activar capacidades no servidor acompanhado. Outro ensaio, no PHP normal, demonstrou423 e zero incidentes indevidos quando o processamento não está disponível. Não se considera o processamento operacionalmente disponível no destino por ter passado num processo de QA configurado para o ensaio. - -Formulário: os testes usam a página real de recursos e o transporte real do seu formulário. Depois de503, o título, motivo, objecto do ficheiro seleccionado, chave de criação e ETag enviados permanecem na preparação; apenas a repetição explícita volta a enviar. Ler o novo incidente no mesmo contexto não reinicializa os campos. A referência recebida é apresentada ao autor. Estes dois casos verificam memória da página e não prometem retoma durável após navegação, recarregamento, autenticação ou perda da página. Não foram acrescentados motivos repetidos, aprovações ou formulários de suporte ao upload. - -Validação:23 Feature/285 finais, com os oito casos novos,cinco de recursos e dez do instalador autenticado. A primeira execução teve27 casos,25 aprovados,uma falha e um erro,408 asserções. Os20 casos anteriores passaram naquela execução. A implementação funcional dos oito casos de incidentes/transições e sete de avisos não foi alterada depois; os cinco de recursos voltaram a passar na execução final. As duas falhas pertenciam às novas fixtures: UploadedFile fake reportava MIME de PDF pelo nome e não o MIME inválido pretendido; outro documento sintético não tinha o estado obrigatório. Corrigidos o MIME explícito e o estado/cifra/classificação da fixture, preservado o diagnóstico e repetidos os22 casos. A revisão da guarda de visibilidade acrescentou depois o oitavo caso novo e foi verificada nos23 casos finais,285 asserções. O ensaio sem GD passou um caso/duas asserções.37 frontend finais incluem três operações conhecidas, o fallback desconhecido e os dois casos de formulário, com31 anteriores. PHPStan nível7 em nove fontes de aplicação sem supressões, Pint em dez fontes PHP, tipos globais, nove fontes de formato/lint e build passaram. A última alteração visual foi apenas tornar genérica a descrição da falha na fila; os checks de interface/build abrangem essa redacção final. A ronda integral1545 continua histórica; não se afirma aceitação visual em browser ou por pessoas reais. - -Conservação e saldo: resource_incidents_20261103_test terminou com64 tabelas vazias, incluindo agora opportunity_images e opportunity_locations além das62 anteriores. Conferidos lock, identidade investmoz_test/55441 e visibilidade owner/RLS/FORCE. Nenhuma tabela/migração nova ou escrita activa. Preservados84 recibos/339 provas anteriores, fontes, dados, originais e percursos aceites. O instalador inclui os dois serviços novos no fingerprint, e os dez casos próprios passaram com essa integração. O backup/restauro real anterior continua a prova do candidato arquivado, não uma prova nova de instalação deste código. Restam despacho/execução de scans e falhas de workers/integrações, saúde operacional e outros limites de falha, reconciliação de bytes retidos, disponibilidade GD no destino, entrega/visual e retoma durável. Gravações de metadados sem ficheiro, localizações, ciclo de vida e reutilização da biblioteca mantêm os seus percursos anteriores; não foram declaradas novas fronteiras de incidentes neste recorte. AUD-PROFILE-20 e o objectivo transversal continuam parciais. Próxima acção: continuar os pontos de despacho/execução dos scans com os mecanismos e autoridade existentes. - -### 03/11/2026 — AUD-PROFILE-20: despacho, workers e resultados antigos da análise de documentos - -[SCAN-TECHNICAL-INCIDENTS-20261103] Falhas no despacho e execução da análise de documentos ligadas ao Suporte técnico por contexto capturado e acesso actual. Tentativas e callbacks identificados no histórico existente; resultados antigos não substituem resultados posteriores, e falha de confirmação da fila não reverte um documento já limpo.30 Feature/365 asserções finais (15 novos,cinco de recursos,dez do instalador), com42/574 anteriores sobrepostos;43 frontend (seis novos). PHPStan/Pint/tipos/formato/lint/build aprovados.67 tabelas QA vazias. Uma mensagem de fila real consumida por outro processo, com ClamD deliberadamente indisponível: inconclusivo, quarentena, original cifrado intacto,zero temporários e incidente próprio.85 recibos/351 provas preservados;14 provas novas. Recibo scan_technical_incidents_increment_20261103. Parcial local,zero escrita/migração activa. - -Origem e fronteira: continuação da decisão expressa «Perfil próprio de Suporte técnico» e do saldo de scans/workers já registado. Reutilizados papel, grants efectivos por organização/tipo, fila, avisos e tratamento existentes. Não foram atribuídos acessos adicionais a ficheiros, competência de aprovação, destinatários externos, SLA ou canais. A repetição de análises continua sujeita a DocumentManagementAccess e ao controlador existente; ser Suporte técnico não concede essa competência. - -Despacho após confirmação: OpportunityScanDispatch regista o callback afterCommit, incluindo quando existe uma transacção exterior. Rollback não envia trabalho. O contexto mínimo é capturado dentro da transacção autorizada que guarda o recurso/derivada e o novo estado da oportunidade. Falha de transporte ou confirmação tardia deixa o recurso já gravado disponível no seu percurso normal, com incidente separado; apenas documento ainda pending pode passar a failed/quarantined. Documento já clean, infected, scanning ou deleted não é sobrescrito pelo catch de envio. O caso síncrono que executa a análise e depois perde a confirmação da fila mantém clean/active e o histórico único. Não há repetição automática da operação de investimento. - -Autoria e privacidade: raízes de sistema usam actor_user_id null e reported_for_user_id para identificar a conta que iniciou o recurso, sem fazer o sistema passar por essa pessoa. Identificador de execução serve de referência idempotente; fases repetidas confirmam a primeira raiz compatível sem duplicar ou reescrever o primeiro facto. Registam-se apenas oportunidade, organização/tipo, versões/estado, operação e código técnico permitido. SQL, excepção, nomes, bytes, títulos e payloads não entram no incidente. O autor só lê incidentes atribuídos à sua conta com acesso actual e correspondência entre organização/tipo capturados e actuais. Transferir o contexto oculta a raiz antiga sem a apagar. Suporte mantém os mesmos limites. Contextos antigos sem proveniência suficiente continuam a analisar normalmente sem inventar destinatário de oportunidade. - -Tentativas sem migração: DocumentScanAttempts reutiliza audit_events e documents.malware_scan_attempts. A aquisição sob lock regista execução, entrega, contador e hash/tamanho efectivamente utilizados. A gravação final só pertence à mesma execução/entrega/contador ainda em scanning. Um callback antigo é registado como descartado e não altera o documento nem cria um resultado de malware enganador. O histórico guarda o descritor dos bytes tentados, mesmo se o cabeçalho entretanto mudou; mudança de hash produz inconclusivo em vez de libertar ficheiro. Resultado normal concluído impede repetir a mesma execução; falha terminal assinalada como repetível permite a repetição explícita prevista pelo motor. Não são inventadas aprovações nem alterados tries3, timeout150, uniqueFor600 e backoff15/60 existentes. - -Compatibilidade e falhas terminais: campos novos têm defaults para payloads serializados antes do incremento. Quando não existe executionId, o job usa o UUID da mensagem real. Conferido no Laravel instalado que o callback failed recebe a instância de fila numa nova desserialização; os testes usam payload antigo real e callback novo com UUID correspondente. Uma falha antiga não sobrepõe análise posterior, estado clean/infected ou descriptor actualizado. Falha genérica terminal usa scan_failed_after_retries/engine unknown; hash divergente antes da execução usa not_run. Não se atribui falsamente todo o erro ao ClamAV. Workers já em execução com código antigo precisam de drenagem/reinício na entrega; o código novo não actualiza processos antigos em memória. - -Temporários e bytes: escrita privada verifica permissões0600 e número de bytes escrito, elimina o temporário no finally e conserva o erro principal caso a limpeza também falhe. Aviso sanitizado distingue limpeza não confirmada. Inconclusivo mantém quarentena; infectado é resultado de segurança válido, sem incidente técnico por esse simples facto. Falha a guardar telemetria não liberta o documento. Originais cifrados e histórico permanecem preservados. - -Interface: operação comum «Análise de segurança de documento» e fases de envio, resultado inconclusivo, falha de worker e limpeza não confirmada aparecem nos cartões, fila e ficha pelos mesmos rótulos. Código desconhecido tem mensagem genérica e não é mostrado como texto técnico cru. O cartão esclarece que o recurso já foi registado e orienta a acompanhar o estado antes de pedir nova análise. A ficha mantém comandos, versões, chaves e protecção de preparações existentes. Não há envio automático de mensagens externas nem nova concessão de leitura do original. - -Prova operacional delimitada: scan_worker_operational_20261103_test foi clonada vazia na instância isolada55441/investmoz_test, com três contas sintéticas e fila exclusiva scan-worker-20261103-test. O serviço real de recursos gravou PDF cifrado e uma mensagem na tabela jobs. Outro processo PHP (worker6412, produtor29712) consumiu essa mensagem com queue:work --once e fornecedor ClamD real deliberadamente indisponível em127.0.0.1:1. Resultado único inconclusive/scanner_unavailable/ClamAV, documento em quarentena, tentativa1, uma raiz de sistema, original cifrado com mesmo hash,zero temporários, fila vazia e failed_jobs0. Consulta do autor e fila/aviso do suporte no âmbito foram confirmadas. A comparação das190 tabelas só encontrou diferenças em audit_events,document_malware_scans,documents,jobs. Owners e16 tabelas RLS existentes preservados; o snapshot declara explicitamente a identidade superuser/bypass de QA. O fingerprint do candidato é 6ec833fd7d1b56890fa55566c66bf63b203681e34aa44186efa021f600fdff78. A guarda recusou reinicializar esta base/prova existente. Isto demonstra um consumo real em processo separado com indisponibilidade controlada, não engine saudável, certificado clean, carga, corrida entre dois workers ou instalação activa. - -Validações:42 Feature/574 iniciais incluíram14 casos novos,cinco de recursos,oito de incidentes de recursos,oito de tratamento e sete de avisos. A ronda final30/365 acrescentou o15.º caso novo e verificou os15 novos,cinco de recursos e dez do instalador com fontes finais congeladas. São rondas sobrepostas, não72 casos distintos. Os43 frontend incluem seis novos e37 anteriores. PHPStan nível7 em sete fontes de aplicação sem supressões, Pint em oito fontes PHP, tipos globais, formato/lint em seis fontes e build passaram. Um erro inicial de carregamento da fixture por colisão com PHPUnit::result final foi corrigido renomeando o helper; o diagnóstico foi preservado e não contado como teste aprovado. GD foi carregado apenas no processo CLI de QA como no incremento anterior, sem mudar a configuração activa. As67 tabelas de ensaio terminaram vazias, com lock, owner, RLS/FORCE e identidade conferidos.85 recibos/351 provas anteriores preservados e14 novas provas arquivadas. Não se repetiu a ronda integral1545 histórica nem se declara aceitação visual/browser ou por utilizadores reais. - -Saldo e próxima acção: AUD-PROFILE-20 continua parcial. Não há outbox transaccional ou garantia de entrega exactamente uma vez; permanece a janela de crash entre commit e envio e o comportamento do lease de unicidade quando o transporte é incerto. A prova de um worker não demonstra saúde contínua da fila/engine, todos os módulos sem contexto, falhas de todas as integrações ou concorrência física. Reconciliação de bytes retidos, disponibilidade GD no destino, retoma durável de formulários, backup/restauro do candidato final, instalação autenticada e validação visual continuam no saldo. O restauro anterior pertence ao candidato arquivado. Nenhuma migração, escrita activa ou comunicação externa. Continuar a fiabilidade do despacho e saúde operacional pelos mecanismos e permissões existentes, sem atribuir poderes de nova análise ao suporte por inferência. - -### 03/11/2026 — AUD-PROFILE-20: repetição de análises e confirmação efectiva do envio - -[SCAN-RETRY-20261103] Repetição da análise distingue aceite, reserva existente, contexto alterado, envio não confirmado e envio diferido. Reserva existente não altera o documento nem duplica o pedido; falha tardia não sobrepõe clean/infected/scanning. Mesma autoridade documental, revalidada após commit, com auditoria da preparação e original preservado. Botão dos anexos de zonas usa resposta Inertia; avisos aparecem também na gestão documental.36 Feature/378 asserções (11 novos,15 de scans,dez do instalador),24/228 iniciais sobrepostos e47 frontend (quatro novos),PHPStan/Pint/tipos/formato/lint/build aprovados.69 tabelas QA vazias. Ensaio com reserva em cache PostgreSQL e fila reais: segundo pedido preservou190 tabelas; outro processo consumiu uma mensagem e libertou a reserva do seu dono. ClamD deliberadamente indisponível manteve quarentena, cifra e histórico,zero temporários.86 recibos/365 provas preservados;14 novas provas. Recibo scan_retry_increment_20261103. Parcial local,zero escrita/migração activa. - -Causa delimitada: DocumentMalwareController colocava pending antes de ScanDocumentForMalware::dispatch(...)->afterCommit e mostrava sempre «Nova análise colocada na fila». O Laravel instalado pode recusar esse dispatch por um lease ShouldBeUnique já existente; o PendingDispatch não devolve esse resultado ao controlador. Assim, um documento inconclusivo/falhado podia perder o seu estado apesar de nenhum novo pedido ser enviado. Além disso, o botão de repetição nos anexos de zonas usava api/fetch JSON contra um endpoint que devolvia redireccionamento. A shell de gestão documental só apresentava flash.success, ocultando avisos. São defeitos técnicos dos percursos existentes, sem nova decisão organizacional necessária. - -Reutilização do motor: DocumentScanDelivery usa o UniqueLock e Dispatcher do próprio Laravel, preservando o mesmo identificador por documento, owner do lease, TTL600, tries3, timeout150 e backoff15/60. O adapter torna observáveis accepted/duplicate/stale e limpa o contexto oculto da fila no finally, inclusive se o transporte lançar excepção. Só liberta o próprio lease quando nenhuma entrega foi tentada; uma falha de confirmação depois da chamada ao transporte conserva-o, pois a mensagem pode já ter sido aceite. O worker conserva a libertação pelo owner prevista no Laravel. Não se força desbloqueio para permitir um segundo envio e não se infere existência de job vivo/engine saudável a partir de uma reserva. OpportunityScanDispatch usa este mesmo adapter; incidentes de recursos, autor e Suporte continuam pelos mecanismos anteriores. - -Repetição autorizada: DocumentScanRetry valida inicialmente a autoridade DocumentManagementAccess e os estados pending/inconclusive/failed, mantendo404/403/422 usuais. Regista afterCommit; rollback exterior descarta o callback sem tocar no documento, auditar preparação ou enviar. No callback, só depois de adquirir o lease, volta a consultar a pessoa e o âmbito documental efectivo, bloqueia a linha e confere hash, estado de scan, contador e updated_at contra o exemplar autorizado. Mudança de acesso ou exemplar resulta stale, sem reset nem envio, libertando apenas o lease adquirido por esse callback. A mesma transacção guarda pending/quarantined e scan_retry_requested com actor, documento, referência UUID e estado anterior. Uma reserva já existente nem sequer executa esta preparação e conserva todos os campos e histórico. - -Falhas e resultados posteriores: a chamada ao transporte só ocorre depois de a preparação ser confirmada. Falha ou confirmação perdida devolve unconfirmed, com referência segura e aviso para consultar o estado antes de repetir. Só documento ainda pending, não excluído, com o mesmo hash e contador, pode ser marcado failed/quarantined pelo catch. Scan já clean/active, infected, scanning ou resultado posterior não é substituído. Os testes executam realmente um CleanScannerFixture no dispatch e depois injectam perda de confirmação: uma história clean, original cifrado intacto e estado active permanecem. Essa fixture sintética não certifica ficheiros reais. Se a própria persistência/verificação estiver incerta, conserva-se privacidade e aviso sanitizado; não se declara um resultado de malware que não foi obtido. - -Respostas e interface: HTML/Inertia usa success apenas para aceitação pelo serviço de envio, sem prometer execução. Duplicate explica «reserva de análise» e ausência de outro pedido; stale pede actualizar o estado; unconfirmed mostra referência; deferred descreve o envio após confirmação da gravação, sem inventar confirmação antecipada. A variante JSON responde com outcome/reference/message e no-store,503 só para envio não confirmado, sem redireccionamento ou texto da excepção. Gestão documental mostra warning como alerta preservando conteúdo e success como status. Nos anexos das zonas, o botão usa router.post, mantém scroll, controla busy e mostra erro de validação/revisão; o flash é apresentado pela Frame existente. A consulta pública não ganha botão de repetição. Não foram criadas perguntas, motivos redundantes ou novos formulários. - -Âmbito de autoridade: mantém-se a gestão documental já existente; o perfil Suporte técnico, mesmo atribuído, não ganha competência de pedir uma nova análise, ler ficheiros ou aprovar investimentos. O pedido manual é genérico por document_id e não presume uma oportunidade ou destinatário a partir de ligações possivelmente múltiplas/antigas. A auditoria tem a referência do pedido e o aviso técnico sanitizado; contexto de oportunidade não é inventado. A captura aprovada para recursos de oportunidades e os seus incidentes continua independente. Atribuir contexto e destinatário a outras origens só pode reutilizar referências/autorização efectivas desses percursos. - -Prova operacional actual: scan_retry_operational_20261103_test foi clonada vazia da QA isolada, com uma conta sintética de gestor e um PDF cifrado sintético. O serviço de repetição criou uma mensagem na fila exclusiva scan-retry-20261103-test e uma reserva real em cache_locks PostgreSQL; conferido uniqueLockOwner do payload igual ao owner guardado. O segundo pedido devolveu duplicate e conservou exactamente os snapshots de todas as190 tabelas. O processo worker25960, distinto do produtor25340, consumiu a mensagem real e removeu o lease do seu dono: jobs0,failed_jobs0,cache_locks0. O ClamD real deliberadamente indisponível em127.0.0.1:1 produziu um único inconclusive/scanner_unavailable/ClamAV e quarentena, com tentativa1, auditoria de pedido/início/fim, cifra original com mesmo hash e zero temporários. Sem contexto de oportunidade, nenhuma raiz de incidente de oportunidade foi inventada. Entre preparação e fim, só audit_events,cache_locks,document_malware_scans,documents,jobs mudaram. Conferidos owners e RLS/FORCE; snapshot declara a identidade superuser/bypass de QA e conserva16 tabelas RLS existentes. Candidato 4a8835aaa62c85224092faa7109f88ea67f9f860ba6d857fa13f838bb6b5e6f5. A guarda recusou reinicializar a base/prova já existente. A prova anterior de um worker fica histórica para o fingerprint anterior. - -Validação e preservação:36 Feature/378 finais incluem11 novos de repetição,15 de scans e dez do instalador autenticado com as fontes congeladas. Os24/228 iniciais abrangiam nove novos e os15 de scans; são rondas sobrepostas, não60 casos distintos. Os47 frontend incluem quatro novos de shell/transportes e43 anteriores. PHPStan nível7 em cinco fontes de aplicação sem supressões, Pint em seis fontes PHP, tipos globais, formato/lint em três fontes e build passaram. O fingerprint do instalador inclui os novos serviços, controlador e duas fontes de interface; os dez casos foram aprovados com essa cobertura. QA terminou com69 tabelas vazias, incluindo cache/cache_locks além das67 anteriores, sob lock e owner/RLS/FORCE conferidos. Preservados86 recibos/365 provas anteriores, fontes, originais e percursos,14 provas novas. Não se repetiu a ronda integral1545 histórica nem se declara aceitação visual/browser ou por utilizadores reais. - -Saldo e próxima acção: AUD-PROFILE-20 continua parcial. O lease existente não é prova de trabalho vivo e a sua conservação após transporte ambíguo pode impedir outro envio até execução ou expiração. Permanece a janela de crash entre commit e envio; este incremento não implementa outbox transaccional nem entrega exactamente uma vez. Um worker com engine indisponível e um lease em base partilhada não provam concorrência física, carga, engine saudável ou saúde contínua. Subsistem outras integrações/origens, reconciliação de bytes retidos, disponibilidade GD no destino, retoma durável, backup/restauro do candidato final, instalação autenticada e visual. Nenhuma migração, escrita activa ou mensagem externa. Continuar saúde operacional e fiabilidade do despacho, reutilizando os mecanismos e competências existentes. - -### 03/11/2026 — AUD-COUNTRY-01/02 e AUD-PROFILE-25: perfil e empresas sem duplicação por repetição - -[INVESTMENT-PROFILE-COMMANDS-20261103] Perfil de investimento e declarações privadas de empresas com pedido idempotente por conta, confirmação após resposta perdida, preparação conservada, comparação explícita de versões e uma guarda de saída. Erros por campo apresentados uma vez, textos longos em área multilinha e limites alinhados com o servidor.17 Feature/248 asserções (seis novos e11 existentes),60 frontend (13 novos e47 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois processos concorrentes reais aguardaram o mesmo lock de utilizador e receberam a mesma empresa/v1: uma declaração cifrada,um evento de negócio e um recibo de comando.87 recibos/379 provas anteriores preservados;16 provas novas. Recibo investment_profile_commands_increment_20261103. Parcial local,zero escrita/migração activa. - -Lacunas verificadas no código: o novo formulário de empresa enviava version0 sem chave de operação; uma repetição após perda de resposta podia criar outra declaração com outro UUID. O perfil tinha verificação de versão mas não recibo repetível. O componente era remontado pela versão e o novo formulário pela quantidade de empresas, podendo apagar preparações por actualizações da página. Os erros apareciam junto ao campo e outra vez no resumo; respostas de até2000 caracteres usavam input de uma linha e alguns limites excediam os do servidor. O critério existente de gravação segura/erros e países permitia corrigir estes defeitos sem criar uma nova regra organizacional. - -Um comando por intenção: InvestmentProfileCommands usa a chave UUID opcional e o audit_events existente, no âmbito exclusivo da conta autenticada, sob o lock users já usado pelo controlador. O pedido normalizado identifica operação, alvo, versão de base e payload; fica cifrado no recibo restrito. A ordem das chaves do payload e a caixa do UUID não produzem outro comando. A mesma chave/conteúdo devolve exactamente o ID/versão originais, sem cifrar outra vez, incrementar versão, inserir outra empresa ou repetir o evento de negócio. Chave com conteúdo/alvo/operação diferentes produz409. O replay de uma criação/v1 depois de uma alteração/v2 devolve o recibo/v1 e conserva o registo actual/v2. Permissões e propriedade são conferidas pelo percurso existente; outra conta não consulta nem reutiliza o recibo privado. Declarações com mesmo nome em contas distintas continuam distintas; não se criam organizations ou memberships. A chave é opcional para conservar clientes legados, cujo comportamento anterior não se declara idempotente. - -Preparação e confirmação na interface: editor e hook comuns do perfil/declarações congelam a versão, os valores e a chave até confirmar o resultado. Falha de rede/503 ou resposta malformada conserva-os e permite só a repetição explícita do mesmo pedido, sem retry automático ou limpar campos. Repetição de criação recebe o mesmo UUID; só o formulário confirmado é limpo. Uma resposta antiga de outro actor ou componente já desmontado não confirma nem recarrega a sessão actual. Actor está identificado na resposta privada de consulta; API de consulta e página têm no-store/private, e o histórico Inertia da página é cifrado. Esta preparação é memória da página, não retoma durável após fecho/recarregamento/expiração. - -Concorrência de versões: chave de montagem passa a identificar conta/empresa, em vez de versão/quantidade. Uma resposta de actualização mantém as edições locais. Se existe versão mais recente, guardar fica suspenso até consulta e comparação explícitas; a leitura não escreve nem substitui valores. A comparação mostra campos divergentes, versão local e guardada, com escolha entre adoptar a versão mantendo a preparação ou carregar os valores guardados mediante confirmação da substituição. Ler um novo exemplar também bloqueia nova escrita até essa escolha, mesmo quando as props da página ainda são antigas. Ler durante um pedido sem resposta não o descarta nem autoriza outra intenção; a confirmação repetível vem primeiro. Depois de validação422, os valores permanecem editáveis e o pedido corrigido recebe nova chave. Sessão/acesso alterados conservam a preparação e exigem consulta no mesmo contexto antes de confirmar. - -Formulários e dados: continuam os campos já existentes de contacto, residência, sector, experiência e capacidade; nome/email continuam nas definições da conta. A declaração conserva nome, constituição, registo, sector, relação e descrição, sem assumir representação legal. A residência ISO, país de constituição, país histórico e origem da solicitação permanecem distintos. O histórico livre é transportado sem inferência. País de constituição requerido pelo percurso existente é indicado no selector e o erro legado payload.country fica associado a esse campo, uma só vez. Outros erros por campo também deixam de se repetir no resumo. Telefone30, registo100, sector/função150, experiência/descrição2000 e capacidade1000 correspondem à validação do servidor; textos longos são multilinha. Existe uma guarda de saída para as preparações do perfil/declarações e confirmação ao preparar manifestação por POST quando há dados por guardar, sem múltiplos avisos por formulário. - -Prova concorrente delimitada: a base workspace_profile_concurrency_20261103b_test foi clonada vazia na instância55441/investmoz_test, com uma conta sintética. Dois processos PHP distintos,21992 e1848, chamaram o controlador com o mesmo comando de criação. O primeiro adquiriu o lock da linha users; pg_stat_activity confirmou o segundo em espera real por Lock antes do commit. Ambos obtiveram o ID27ec073d-0bb3-4d51-a440-f020145f5424/v1. Comparadas190 tabelas: só audit_events e investment_company_declarations mudaram. Ficaram uma declaração cifrada,um company_declared e um recibo command_applied, sem organização/membership ou outras mutações. Owners e16 tabelas RLS existentes conservados; snapshot declara a identidade superuser/bypass de QA. Estes processos chamam o controlador directamente; o middleware HTTP foi verificado nos Feature, não neste ensaio. A guarda recusou reinicializar a base/prova existente. O ensaio anterior na base sem sufixob fica histórico: após afinar o bloqueio de escrita depois de consultar uma versão nova, repetiu-se a concorrência com as fontes finais congeladas. Os hashes das cinco fontes executáveis constam da prova final. - -Validação e diagnósticos:17 Feature/248 finais, com seis novos de comandos e11 existentes de workspace/país organizacional, preservando isolamento, snapshot de submissões e compatibilidade. A ronda inicial17/248 sobrepõe-se à final.60 frontend são13 novos da página real/hook/transporte e47 casos anteriores de suporte, recursos e avisos. Os nove primeiros casos frontend passaram inicialmente; ao acrescentar a confirmação POST, um diagnóstico de59 casos teve58 aprovados e um erro porque a fixture não montava window no evento de clique. Corrigida a fixture, preservado o diagnóstico e acrescentado o13.º caso de adopção explícita de nova versão;60 finais aprovados. PHPStan nível7 em duas fontes de aplicação sem supressões, Pint em três fontes PHP, tipos globais, cinco fontes de formato/lint e build aprovados. Os checks iniciais identificaram uma chamada header não pertencente ao tipo Response do Symfony e uma opção preserveScroll não existente em ReloadOptions do Inertia actual; corrigidas as APIs reais, sem casts/supressões. Documentação primária do identificador PHPStan consultada. Não se repetiu a ronda integral1545 histórica nem se afirma aceitação visual/browser ou por pessoas reais. - -Preservação e saldo: QA terminou com79 tabelas vazias, incluindo agora as colecções do workspace e eventos, com lock, identidade, owner/RLS/FORCE conferidos.87 recibos/379 provas anteriores mantidos e16 provas novas arquivadas. Nenhuma tabela/migração nova, escrita activa ou comunicação externa. AUD-COUNTRY-01/02 e AUD-PROFILE-25 continuam parciais: o editor do cadastro mestre de país organizacional mantém o seu percurso separado, cuja recuperação/repetição integral ainda deve ser tratada; as contas registadas não ganham uma pergunta de residência na autenticação simples. Persistem outros formulários/perfis/consumidores, retoma durável, expiração, visual/móvel/browser, país real autorizado da organização onde ainda não preenchido, backup/restauro do candidato e disponibilização autenticada. Preservam-se as fontes e provas anteriores, sem pedir novamente decisões/cadastros já confirmados. Próxima acção: continuar a recuperação do editor organizacional e os consumidores restantes, com a mesma fonte única e permissões existentes. - -### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: editor organizacional com confirmação e recuperação - -[ORGANIZATION-COUNTRY-EDITOR-20261103] País de constituição da organização com confirmação repetível por conta, país/referência congelados até confirmar, comparação explícita de versões e preparação conservada. Autorização actual e Auditor conferidos antes de devolver o recibo; fonte, histórico e snapshots anteriores preservados. Editor partilha a guarda de saída do perfil e consulta a permissão actual para recuperar uma representação restabelecida.23 Feature/295 asserções (seis novos e17 anteriores),69 frontend (nove novos e60 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias. Dois representantes/processos e espera real pelo lock da organização: uma alteração/v2, outra409, fonte vencedora intacta.88 recibos/395 provas preservados;16 novas provas. Recibo organization_country_editor_increment_20261103. Parcial local,zero escrita/migração activa. - -Origem e lacuna: continuação do saldo do perfil/empresas anterior. O editor do país organizacional ainda era remontado pela versão e enviava PUT sem recibo de comando, não permitindo confirmar uma gravação após perder a resposta. A correcção reutiliza InvestmentProfileCommands e useInvestmentProfileEditor, CountryCatalogue/CountrySelect, a versão e o cadastro organizations existentes. Mantém-se o país de constituição distinto da residência, país histórico e origem da solicitação. Não se cria organização ou representação por nome, não se preenche o país real da Tempo por inferência e não se exige nova validação genérica das fontes já aceites. - -Servidor e recibo: OrganizationCountry aceita operation_key UUID opcional, mantendo clientes legados. Bloqueia a pessoa, os seus vínculos existentes e a organização; verifica novamente a autorização depois de adquirir o lock da organização, cobrindo uma exclusão lógica enquanto aguardava. Só a representação activa com a competência já existente e sem restrição de Auditor pode gravar ou obter confirmação repetida. O comando identifica operação organization_country, organização, versão, país e referência exactos. O mesmo conteúdo/chave devolve a versão/país originais, sem outra actualização, timestamp de proveniência ou evento de negócio. Mudança de país, referência, alvo ou operação com a chave usada dá409. Replay depois de uma alteração posterior conserva o registo actual, devolvendo apenas o recibo original. A mesma transacção mantém o histórico de antes/depois cifrado e o recibo cifrado no audit_events já existente; a chave não constitui nova autorização. - -Interface comum: o editor deixa de usar a versão como chave de montagem e mantém o país/referência enquanto compara novos dados. Perda de resposta ou confirmação inválida congela a intenção original e permite repetir explicitamente esse pedido. A resposta tem de corresponder à versão seguinte e ao país enviado para ser aceite. A consulta não escreve, não limpa a preparação nem cria outra intenção. Leituras rápidas partilham um pedido em curso; guardar/adoptar respeitam a leitura ainda activa. Depois de consultar uma versão diferente, é preciso adoptar explicitamente a versão mantendo a preparação ou carregar os dados guardados mediante confirmação de substituição. Campos e erros continuam identificados, com cada erro mostrado uma vez, referência entre5 e2000 caracteres e país ISO obrigatório conforme o servidor existente. - -Representação actual e recuperação: consulta sem competência de escrita mostra os valores com os campos desabilitados e sem comando de gravação. O método do hook também recusa submissão directa nesse estado. A leitura recente pode retirar a possibilidade de repetir um pedido ainda incerto se a representação foi revogada; os campos preparados permanecem na página. Se o vínculo é restabelecido e uma nova consulta no mesmo actor/organização confirma escrita, o editor permite voltar a confirmar/editar após a escolha adequada, mesmo que as props antigas da página ainda sejam de leitura. Essa permissão consultada só prevalece enquanto a base das props é a mesma; nova versão/permissão da página volta a ser considerada. Todas as escritas e replays continuam sujeitos à autorização do servidor. O editor integra a única guarda de saída da página, juntamente com perfil/declarações. Mudança de conta desmonta a preparação antiga; não se declara retoma durável após navegação, recarregamento ou expiração. - -Histórico e reutilização: conservados source_system, external_id, versão e proveniência da organização, a marca de declaração do representante e o histórico cifrado antes/depois. Os testes anteriores de país mestre e workspace continuam a provar que mudar o mestre não altera declarações/submissões anteriores ou a residência. A reutilização do país para uma declaração continua a ser uma operação explícita separada; o botão não passa a copiar alterações do mestre automaticamente. A recuperação/idempotência desse botão permanece no saldo próprio. Não houve instalação de extensão, migração nova, alteração de flags ou concessão de perfil neste incremento. - -Concorrência real delimitada: organization_country_editor_20261103_test foi clonada vazia na instância55441/investmoz_test, com duas contas e dois vínculos sintéticos de officer na mesma organização. Os processos 22568 e 28816 enviaram comandos distintos sobre a versão1. O primeiro reteve a linha de organização; pg_stat_activity confirmou o segundo em espera real por Lock. O primeiro guardou FR/v2 e a sua referência; o segundo recebeu409 ao adquirir o lock, sem substituir o país nem a proveniência. Na comparação de190 tabelas, só audit_events e organizations mudaram: uma organização,um evento de país e um recibo de comando cifrado. Decifrados e conferidos actor/alvo/versão/país/referência do comando, sem texto da referência na raiz do recibo. Owners e16 tabelas RLS existentes conservados; o snapshot declara a identidade superuser/bypass de QA. As cinco fontes executáveis estão ligadas por hash ao candidato final. A guarda recusou reinicializar a base/prova existente. Os processos chamam o controlador directamente; middleware HTTP e repetição do comando estão nos Feature. Este ensaio não prova todas as intercalações, carga ou aceitação por pessoas reais. - -Verificações e diagnóstico corrigido:23 Feature/295 finais, com seis novos de comandos organizacionais e17 existentes do país/workspace/perfil. A primeira ronda22/288 passou antes do sexto caso. Um ensaio posterior23/288 teve22 aprovados e um erro na nova fixture: tentou inserir dois vínculos activos da mesma conta/organização. O índice parcial imz_memberships_user_id_organization_id_uq já impede isso; a hipótese de defeito por primeiro vínculo foi retirada e a leitura de represented mantida como estava. O caso final muda o papel do vínculo único e verifica a mesma competência na consulta e na escrita. Não se alterou ou enfraqueceu o índice. Diagnóstico preservado.69 frontend finais incluem nove novos e60 anteriores;20 iniciais cobriam os sete primeiros novos e13 do perfil. Acrescentados o bloqueio de leituras simultâneas e a recuperação de permissão restabelecida. PHPStan nível7 em duas fontes sem supressões, Pint em duas fontes PHP, tipos globais, cinco fontes de formato/lint e build passaram. O primeiro build ficou arquivado antes do ajuste final da recuperação de permissão; a compilação final cobre esse ajuste. Não se repetiu a ronda integral1545 histórica nem se afirma aceitação visual/browser. - -Preservação e próxima acção:79 tabelas de QA terminaram vazias, com lock, identidade, owner/RLS/FORCE conferidos. Mantidos88 recibos/395 provas anteriores e arquivadas16 novas. Nenhuma migração/escrita activa ou comunicação externa. AUD-COUNTRY-02 e AUD-PROFILE-25 continuam parciais: restam o botão de reutilização do país, outros consumidores/perfis, retoma durável/expiração, visual/móvel, preenchimento real autorizado onde falta país, backup/restauro do candidato e disponibilização autenticada. Os pedidos legados sem chave conservam a semântica anterior e não são declarados idempotentes. Continuar a reutilização explícita e os consumidores restantes, preservando a fonte única e os limites de representação existentes. - -### 03/11/2026 — AUD-COUNTRY-02 e AUD-PROFILE-25: reutilização de país com pré-visualização e confirmação repetível - -[ORGANIZATION-COUNTRY-REUSE-20261103] Reutilização explícita do país organizacional com consulta/pré-visualização, confirmação, recibo repetível cifrado e fonte/versões preservadas. Guarda edições e bloqueia acções concorrentes da mesma declaração enquanto o pedido não tem confirmação. Representação de leitura actual e propriedade conferidas também no replay; snapshots/submissões anteriores não são reescritos.29 Feature/364 asserções (seis novos e23 anteriores),79 frontend (dez novos e69 anteriores),PHPStan/Pint/tipos/formato/lint/build aprovados.79 tabelas QA vazias, constraint da falha removida por rollback e índice de representação intacto. Dois processos reais aguardaram o mesmo lock e receberam o mesmo resultado/v2, com uma cópia cifrada e um recibo.89 recibos/411 provas preservados;16 provas novas. Recibo organization_country_reuse_increment_20261103. Parcial local,zero escrita/migração activa. - -Lacuna e origem: continuação do saldo explícito do editor organizacional. O botão anterior enviava directamente a reutilização, sem consulta actual, chave de operação ou recuperação de resposta perdida, e podia ser accionado enquanto havia edições privadas no mesmo formulário. A correcção reutiliza a operação, fonte, versões e propriedade já existentes; não acrescenta nome, NUIT, país, referência ou comprovativo para voltar a preencher. O país continua a ser lido da organização autorizada e copiado explicitamente, sem identificar ou fundir entidades por igualdade de nome. - -Servidor: o pedido opcionalmente identificado por UUID bloqueia a pessoa, a declaração privada e a fonte; readableSnapshot bloqueia a representação e a organização, conferindo novamente o acesso depois da espera. A leitura basta para reutilizar: viewer conserva a operação de leitura existente e não ganha edição do mestre. A propriedade da declaração e a representação actual são exigidas antes de devolver um recibo. O comando liga a operação organization_country_reuse, alvo, versão da declaração, organização e versão da fonte. Repetição da mesma intenção devolve a versão/país originais, sem alterar cifra, reused_at, proveniência, versão ou auditoria outra vez. Chave com outro alvo/fonte/versão/operação dá409. IDs da fonte e alvo são os UUIDs guardados, incluindo quando o cliente usou maiúsculas; nomes não participam na correspondência. - -Fonte e histórico: um replay autorizado continua a recuperar o país da primeira cópia mesmo que a fonte ou a declaração tenham sido alteradas depois, ou que o país actual da fonte esteja em falta. Isso confirma o pedido histórico e não volta a copiar o valor antigo sobre o registo actual. Nova reutilização exige as versões actuais e país informado. O antes/depois e a cópia identificada mantêm a informação utilizada; as manifestações anteriores conservam os valores e snapshots originais, e novas manifestações recebem a declaração efectivamente guardada. Residência, constituição, país histórico e origem permanecem separados. O país é obtido no servidor, sem aceitar um país ou snapshot fabricados no corpo do cliente. - -Privacidade e atomicidade: InvestmentProfileCommands conserva os recibos anteriores em result e suporta result_encrypted para o resultado que contém país. Intenção e resultado da reutilização ficam cifrados no recibo restrito, mantendo compatibilidade de leitura com os recibos antigos. O JSON de confirmação tem no-store/private. Injectada uma falha de persistência no recibo dentro da QA: o503 sanitizado não expôs SQLSTATE e reverteu em conjunto a actualização da declaração e o evento de negócio. A consulta final confirmou a ausência da constraint temporária e a manutenção do índice parcial imz_memberships_user_id_organization_id_uq. Nenhuma tabela/migração nova ou guarda funcional foi removida. - -Interface: um painel dentro do editor da declaração consulta a página privada actual e apresenta país da declaração, país a copiar, organização, versão e referência guardada. Só a confirmação explícita envia POST. Não se permite copiar sobre edições por guardar, leitura/gravação em curso, conflito ou outro pedido incerto da mesma declaração. O editor partilha um mutex com a reutilização e a guarda única de saída da página. Durante envio incerto, os campos ficam conservados e a repetição mantém exactamente a chave e as duas versões; fonte alterada entretanto não muda esse comando. Consultar o estado não confirma por semelhança de valores nem prepara outra cópia. Depois de confirmação válida, actualiza-se apenas o país na preparação previamente sem edições, conservando os outros campos e recarregando a cópia identificada. Uma resposta inválida ou de outra conta não limpa/confirma a preparação. - -Comparação e recuperação: uma fonte mais recente já conhecida na página bloqueia a pré-visualização antiga; fonte obtida numa consulta mais recente pode ser apresentada mesmo com props antigas, até se conhecer outra alteração. Mudança da declaração detectada durante consulta encaminha para a comparação do formulário, sem escrever.409/422 conservam os valores e exigem nova consulta/intenção; falha sem confirmação conserva o pedido. Falta de sessão/acesso impede repetição até consulta no mesmo actor e organização confirmar o contexto de leitura restabelecido. A preparação continua em memória da página, com aviso de saída, sem promessa de retoma durável após fechar/recarregar/autenticar-se. - -Prova concorrente real: organization_country_reuse_20261103_test foi clonada vazia na instância55441/investmoz_test. Uma conta sintética, com vínculo viewer, reutilizou a fonte FR/v3 para a sua declaração MZ/v1. Os processos 12544 e 1808 enviaram o mesmo comando; pg_stat_activity confirmou espera real pelo lock da pessoa. Ambos receberam version2/countryFR e no-store, mas ficou uma só alteração da declaração,um evento de reutilização e um recibo. O payload actual é exactamente a cifra do primeiro after_payload; a cópia conserva organização/v3, referência, actor e reused_at iniciais. Comando e resultado foram decifrados/conferidos na prova; não houve recifra ou outra cópia no replay. Entre190 tabelas, só audit_events e investment_company_declarations mudaram; fonte, vínculo e restantes dados ficaram iguais. Owners e16 tabelas RLS existentes preservados; o snapshot declara a identidade superuser/bypass da QA. Oito fontes executáveis estão ligadas por hash ao candidato. A guarda recusou reinicializar a base/prova. Os processos chamam o controlador; middleware HTTP é prova separada nos Feature, sem afirmar carga ou todas as intercalações. - -Validação e diagnósticos:29 Feature/364 finais, com seis novos de reutilização e23 anteriores de comandos organizacionais, país, perfil e workspace. A primeira ronda teve29 casos,27 aprovados,duas falhas e349 asserções. Uma repetição com UUIDs em maiúsculas encontrou intenção diferente porque a cópia ainda usava o argumento textual da organização: corrigido para o ID canónico do registo, sem reescrever snapshots históricos. O teste de falha esperava500, mas o tratamento existente devolve503 sanitizado; corrigida essa expectativa e verificados rollback e ausência de SQL na resposta. Diagnóstico preservado.79 frontend finais incluem dez novos e69 anteriores;32 iniciais cobriam os dez novos e22 do perfil/editor. PHPStan nível7 em três fontes sem supressões, Pint em quatro fontes PHP, tipos globais, sete fontes de formato/lint e build aprovados. A ronda integral1545 continua histórica, e não se afirma aceitação visual/browser ou por pessoas reais. - -Rastreabilidade dos executores: o recibo anterior organization_country_editor_increment_20261103 conservava na lista tooling_sha256 nomes de helpers da etapa workspace, por uma cópia de metadados. Mantêm-se esse recibo e todas as suas provas exactamente como estavam. Este incremento acrescenta prior_tooling_supplement_sha256 para os ficheiros efectivamente usados e retidos de check-organization-country-editor-qa, verify-organization-country-editor-concurrency e record-organization-country-editor, e liga os próprios executores actuais pelos caminhos correctos, incluindo este recorder. A suplementação de rastreabilidade não altera os resultados, fontes, observações de concorrência ou estado de instalação anteriores. - -Preservação e próxima acção:79 tabelas de teste vazias, lock/identidade/owner/RLS/FORCE conferidos e fixture de falha revertida.89 recibos/411 provas anteriores preservados e16 novas provas arquivadas. Nenhuma migração/escrita activa ou comunicação externa. AUD-COUNTRY-02 e AUD-PROFILE-25 continuam parciais: clientes legados sem chave mantêm semântica anterior; restam outros consumidores/perfis, retoma durável/expiração, visual/móvel/browser, preenchimento real autorizado onde falta país, backup/restauro do candidato e disponibilização autenticada. A fonte aprovada não volta a ser submetida a uma validação genérica nem se inventam representantes. Próxima acção: confrontar os consumidores restantes e a recuperação de preparações com a matriz, reutilizando os mecanismos agora comuns. - - -### 04/11/2026 — resolução dos conflitos gravados na reconciliação - -Pedido expresso da Tempo: resolver os conflitos de `codex/investemoz-reconciliation-20261029`. Base preservada em `backup/reconciliation-before-conflict-fix-20261104` (`4a881252`). Resolvidos oito blocos em quatro ficheiros, sem integrar na main ou instalar no portal. - -O catálogo conserva o layout lateral/responsivo e os filtros expansíveis, a selecção validada com recuperação de falha do armazenamento, as acções de limpar nos corredores e na lista, os resultados relacionados distintos da pesquisa, a paginação bloqueada durante pesquisa/falha e o mapa único com camadas e limites administrativos pelo território aplicado. Não atribui localização distrital nem coordenadas a uma indicação provincial. Manual e matriz conservam os registos de ambos os lados; matriz com 3.555 requisitos únicos e 49 colunas. As provas aceites e pendências visuais mantêm-se; esta resolução não constitui aceitação visual ou disponibilização activa. - -Verificação do delta: 25 testes frontend dirigidos aprovados; TypeScript e compilação QA aprovados; lint dos dois ficheiros React sem erros após normalizar o título do sector; pesquisa de marcadores e `git diff --check` limpos. Compilação apenas em `public/build-qa-opportunities`, com aviso de dimensão de chunks. Sem alterações de schema, base de dados, permissões, serviços ou outros worktrees. Recibos locais: `outputs/reconciliation-conflicts-20261104/`. - - -### 04/11/2026 — integração da reconciliação na main exclusivamente local - -Pedido expresso da Tempo: integrar a reconciliação na `main` local, preservar as alterações, verificar conflitos e testes, sem enviar para o remoto. A `main` anterior (`4b3c7e16`) foi preservada em `backup/main-before-reconciliation-20261104`. A integração de `codex/investemoz-reconciliation-20261029` (`f17e807c`) fez fast-forward: a main anterior é antepassada da origem. Não houve nova resolução automática nem descarte de conteúdo; a árvore integrada foi conferida idêntica à origem. Os oito conflitos gravados já estavam resolvidos no commit de origem e não existem marcadores em app/resources/routes/tests/docs. Sem alterações por gravar anteriores ou alterações nos outros worktrees. - -Verificação local: 1.672 testes frontend aprovados, zero falhas; TypeScript global aprovado; compilação QA aprovada em `public/build-qa-opportunities` (avisos de fontaine opcional e dimensão dos chunks); sintaxe dos 468 ficheiros PHP alterados aprovada; `git diff --check` limpo. Matriz preservada com 3.555 requisitos únicos e 49 colunas. Recibos e logs: `outputs/reconciliation-main-local-20261104/integrity.json`. Testes dependentes de PostgreSQL não reexecutados: não havia listener da QA isolada em 55441. Provas anteriores preservadas, sem as apresentar como nova execução. Esta integração não declara aceitação funcional/visual integral, disponibilização no portal nem execução de migrações. Sem push, escrita na base activa, publicação de conteúdos ou alteração de serviços/permissões. - - -### 04/11/2026 — base QA exclusiva e testes da main local - -Pedido expresso da Tempo: preparar QA isolada e executar os testes de base de dados da main local, sem tocar na base activa nem enviar alterações ao remoto. Base de código `66a5dbf3`, após integrar a reconciliação. Criado cluster PostgreSQL/PostGIS novo em directório exclusivo `C:/Users/macbook/.config/investmoz/main-qa-20261104-pgdata`, apenas em `127.0.0.1:55441`, com cinco bases terminadas em `_test`. Guardas conferem nome, porta e directório real antes de migrações/testes; sem configuração em cache, DB_URL ou fallback activo. InvesteMoz, SGF e os restantes clusters não foram reiniciados nem reconfigurados. QA permanece disponível; nenhuma instalação de serviço ou alteração global do PHP. - -Resultado final por caso distinto, substituindo o resultado inicial apenas quando houve repetição documentada: **1.325 aprovados, 28.377 asserções, zero falhas por resolver nesta ronda**. Todos os 274 ficheiros Feature cobertos, mais 94 casos unitários e ciclo de schema com 3.106 asserções. Inclui Competitividade 7/93 e filtros provinciais 4/364. A ronda principal inicial teve 877 casos, 873 aprovados, duas falhas e dois erros; os quatro casos passaram em repetição dirigida após carregar GD/WebP apenas no processo QA e corrigir uma expectativa antiga de auditoria. O teste conserva os 13 eventos de negócio, verifica os oito eventos já existentes de início/resultado de quatro scans e confirma ausência de duplicação no replay. Não se alterou o código da aplicação. - -Preparação e diagnósticos preservados: dois snapshots QA anteriores restaurados em bases separadas e actualizados pelas migrações locais; histórico de uma migração da oferta reconciliado só no clone, após comparar colunas, constraints, índices, políticas e RLS com o schema actual. Dois testes com traits combinados de RefreshDatabase tinham sido mal agrupados: executor da cópia de referência interrompido, logs conservados, cópia restaurada e testes separados; não foi perda de dados activos. Fixture fiscal própria executada em schema limpo, sem apagar versões legítimas do snapshot. Chave local compatível do snapshot verificada e disponibilizada apenas ao executor como chave anterior, sem expor, alterar chave ou reescrever registos. Originais editoriais existentes copiados para a fixture QA com hashes verificados. Falhas iniciais não são apagadas nem apresentadas como regressões resolvidas no produto sem causa demonstrada. - -Preservação: 523 JSON históricos conferidos/restaurados por SHA256, 17 saídas novas arquivadas separadamente; dumps originais QA inalterados. Matriz mantém 3.555 requisitos únicos e 49 colunas. Pint, sintaxe do teste alterado e diff-check aprovados. Sem push, publicação, migração/escrita activa ou alteração de permissões activas. Estas provas não substituem a conferência visual autenticada nem encerram requisitos transversais; pendências anteriores conservadas. Recibo: `docs/investmoz/unification/main-local-database-qa-20261104.json`; resultados por teste, tentativas iniciais, executores e JUnit em `outputs/main-db-qa-20261104/`. - - -### 04/11/2026 — conferência visual da main na QA isolada e correcção do CSV provincial - -Percurso executado no Edge em `http://127.0.0.2:18644`, base exclusiva `main_visual_20261104_test` no cluster QA `127.0.0.1:55441`, com actor e conteúdos sintéticos. Autenticação Fortify normal com MFA: editar, guardar v2, recarregar e conferir os valores; aprovar v3; guardar novo rascunho v4; terminar sessão e conferir publicamente apenas v3, sem o marcador do rascunho. Histórico v1–v4 preservado. Esta prova conclui o recorte visual local de Competitividade; não equivale a execução no portal remoto ou aceitação da equipa em dados reais. - -Filtro apenas por Maputo Província, com sector Agronegócio: cinco oportunidades existentes mais quatro fixtures sintéticas nos níveis província/distrito/posto/localidade resultaram em nove na grelha, lista, mapa e CSV. Distrito de Matola apresentou três; regressar a toda a província recuperou nove e limpou distrito/posto/localidade. Nenhuma coordenada criada: mapa informa zero locais e nove sem coordenadas. Hash das oportunidades anteriores idêntico antes/depois. Limite administrativo desta província indisponível na QA, explicitamente indicado; cobertura cartográfica transversal continua pendente. - -Detectada e corrigida divergência no CSV: coluna Província vazia apesar da localização canónica/contexto de corredor disponível. Exportação reutiliza a apresentação territorial existente, conserva as oito primeiras colunas e o escape contra fórmulas, acrescentando Localização e âmbito. Contexto do corredor indica expressamente que distrito/posto não foram indicados; não grava nem inventa localização. CSV descarregado pela interface após correcção: nove linhas, todas com província e âmbito coerentes. - -Delta aprovado: 17 testes de base de dados, 609 asserções; PHPStan sem erros e Pint aprovado. Provas anteriores de 1.325 testes/28.377 asserções preservadas, sem repetição integral. Recibo com hashes e capturas: `docs/investmoz/unification/main-local-visual-qa-20261104.json`; artefactos em `outputs/main-visual-qa-20261104/`. Apenas main local e QA; sem push, escrita activa ou alteração de permissões activas. Conferência dos filtros no portal de destino e pendências gerais ACT-02/V2-07/V2-10 continuam abertas. - - -### 04/11/2026 — ACT-20261029-02: limites do nível imediatamente inferior e lacunas de cobertura - -Continuação sequencial na main local sobre `6dde36b5`, reutilizando V2-07/V2-10, serviço de geometria, permissões e mapa único. Inventário prévio confirmou camadas/legenda/fontes já existentes e contexto limitado à selecção/antepassados; nenhuma perda confirmada. Os 12 artefactos do recibo visual anterior foram novamente conferidos por SHA256, sem alteração. Provas aceites de 1.325 testes e demais incrementos preservadas, sem repetição integral. - -O catálogo solicita `include_children=1` no endpoint administrativo existente. A opção acrescenta apenas referências do nível imediatamente inferior: distritos de uma província, postos de um distrito e localidades de um posto. Sem a opção conserva o âmbito anterior. Geometrias continuam sujeitas à classificação, acesso efectivo e snapshots/hashes de divulgação existentes; não há publicação, importação ou nova autorização. O território seleccionado tem prioridade, seguido dos antepassados e subdivisões. Até 100 geometrias e 500 referências inferiores, com truncagem explícita. - -Resposta acrescenta `child_territory` e `child_coverage` com nível, referências acessíveis e territórios representados, distinguindo contagem territorial de polígonos. Interface identifica subdivisão/contexto/território seleccionado, conserva fonte/edição e explicita que falta de limite na consulta não significa inexistência do território, nem terreno disponível. Nenhuma oportunidade é reposicionada e nenhuma coordenada é presumida. - -Delta aprovado: 11 testes de base de dados/125 asserções (cinco novos e seis de acesso existente), nove testes frontend, PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Inclui exclusão de outra província/netos, limites públicos/internos, referência eliminada, ausência de geometria, priorização e truncagem de geometrias/referências, validação do parâmetro e descarte de resposta anterior ao mudar a opção. Primeira tentativa da fixture falhou por faltar país-pai; corrigida a fixture, mantendo a integridade territorial e os logs iniciais. - -Conferência visual no Edge, exclusivamente QA `127.0.0.2:18644`/`main_visual_20261104_test`: Maputo Província mostra zero limites de oito referências distritais acessíveis, lacuna explicitada, nove oportunidades mantidas sem ponto inventado. O snapshot não contém limites públicos para demonstrar visualmente os polígonos inferiores; estes foram exercitados por testes sintéticos. Recibo/hashes: `docs/investmoz/unification/map-subdivision-local-20261104.json`; captura em `outputs/map-subdivision-20261104/`. - -**ACT-02 permanece parcial.** Camadas factuais de recursos, infra-estruturas, mão-de-obra e potencial económico, cobertura de dados/geometrias e conferência no portal de destino continuam pendentes. Este recorte não encerra V2-07/V2-10 nem substitui aceitação da equipa. Sem push, migração, escrita activa, importação, alteração de permissões ou reinício de serviços. - - -### 04/11/2026 — ACT-20261029-02: camadas de evidência pública de recursos e infra-estruturas - -Incremento sequencial na main local sobre `bbc05f1d`, reutilizando V2-07/V2-10, mapa único, filtros, pontos/áreas públicos e contexto administrativo já demonstrados. Inventário de código e cópia QA antes de fixtures: 48 oportunidades publicadas e duas sínteses proactivas públicas, mas nenhuma evidência pública local das categorias resource/infrastructure. Os campos existentes de zonas e fontes editoriais não foram convertidos automaticamente em disponibilidade ou geometrias temáticas; evidências privadas não foram publicadas. Não é perda confirmada de dados nem diagnóstico do remoto. Conferidos por SHA256 os 23 artefactos dos dois recibos visuais/administrativos anteriores, todos inalterados. - -A API existente de mapa acrescenta `thematic_records` a partir de `ProactiveInvestment::publicData`: somente evidência seleccionada na síntese publicada, categorias recursos/infra-estruturas e propósito local. Conserva facto, fonte, localizador, período, âmbito, cobertura, verificação registada, situação e limitações. Exclui metodologia e outras categorias; não copia o rascunho privado. Mantém a consulta territorial, limite/truncagem e autorização pública anteriores. As áreas acrescentam o identificador da oportunidade para filtragem, sem atribuir a geometria à evidência. - -No mesmo mapa, o selector permite todas as oportunidades, recursos documentados ou infra-estruturas documentadas. A camada filtra apenas pontos/áreas existentes das fichas correspondentes; não alarga a pesquisa geral, não altera CSV nem cria posições. Fichas sem ponto continuam consultáveis no painel de evidências/fontes. Contagens referem fichas, não quantidade/capacidade de recursos. Âmbito da evidência distingue-se da localização da oportunidade; marcadores não representam posição exacta ou disponibilidade de recurso/infra-estrutura. Escolha recuperada na sessão do navegador, com tolerância a armazenamento indisponível/inválido. Falta de evidência, período ou fonte é explícita, sem zero presumido. - -Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filtros provinciais), 14 testes frontend (cinco novos e nove existentes), PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Inclui exclusão de rascunhos/publicação futura/acesso restrito, leitura apenas da síntese pública, fonte/período/limites, província/distrito, reutilização das coordenadas existentes, alternância/reposição de camadas, fichas sem ponto, carregamento/ausência/truncagem, escape de texto e recuperação da escolha. Provas gerais anteriores preservadas, sem repetir a bateria completa. - -Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais. - -**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços. - - -### 04/11/2026 — ACT-20261029-02: mão-de-obra documentada e contexto económico - -Incremento qualitativo na main local sobre `21ebad73`, reutilizando mapa, evidências, síntese publicada, divulgação expressa e fontes/períodos existentes. Inventário na cópia QA: duas evidências públicas locais de actividade anteriores (fichas sintéticas 350/383), nenhuma de mão-de-obra/oferta/procura; recursos/infra-estruturas da demonstração anterior conservados. As declarações labour_demands/training_capacities têm acesso EducationAccess interno; emprego/indicadores financeiros canónicos não fazem parte da publicProjection. Observações de zonas conservam divulgação/unidades/metodologia próprias. Não foram expostas nem agregadas essas fontes privadas por existir revisão interna. As fontes oficiais aceites e as decisões de divulgação anteriores não foram reabertas. - -Acrescentada categoria explícita Mão-de-obra no editor e validação da evidência existente, sem migração ou reclassificação automática dos textos anteriores. Guardar, recuperar, pré-visualizar e confirmar publicação usam o percurso existente. A camada económica reutiliza apenas evidências públicas locais de actividade/oferta/procura, mantendo `source_category` original, facto, fonte, localizador, período, verificação, âmbito, cobertura e limitações. Agrupá-las para consulta é uma escolha de apresentação, não aprovação de viabilidade nem índice de potencial. - -Ambas as opções entram no selector do mapa único; a escolha é recuperada na sessão. Recursos/infra-estruturas, geometrias públicas, filtros territoriais, fichas sem ponto e contagens anteriores mantêm-se. Nenhuma posição é criada ou atribuída ao recurso/mão-de-obra. Necessidade ou qualificação não equivale a trabalhador disponível; previsão de emprego não é emprego efectivo. Contexto económico não calcula retorno, score ou viabilidade. Períodos/fontes incompatíveis permanecem separados, sem totais ou zero presumido. - -Delta aprovado: sete testes de BD/77 asserções (cinco do mapa, incluindo o novo caso; dois de publicação, um novo e um de acesso/fonte privada já existente), 22 testes frontend, PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Teste do percurso: criar evidência workforce → recuperar → confirmar pela publicação existente → consultar mapa → alterar rascunho privado sem substituir a categoria/fonte públicas. Testes mantêm metodologia/internos fora do mapa, categorias originais, períodos distintos e ausência de quantidades/índices inferidos. Não se repetiu a bateria geral aceite. - -Conferência visual no Edge exclusivamente na QA `127.0.0.2:18644`/`main_visual_20261104_test`: contexto económico reutiliza a evidência de actividade já publicada da ficha 383, sintética e explicitamente identificada. Mão-de-obra usa uma única fixture nova, também sintética; escolha e fonte recuperadas após recarregar. Nenhuma coordenada/geometria criada; hash de todas as oportunidades anteriores idêntico antes/depois. Conferidos 36 artefactos dos três recibos anteriores, todos com SHA256 inalterado. Recibo: `docs/investmoz/unification/workforce-economic-map-local-20261104.json`; inventário, DOM, capturas e hashes em `outputs/workforce-economic-map-20261104/`. - -**ACT-02 permanece parcial.** Cobertura factual laboral/económica, séries, unidades e metodologia quantitativa comparável, georreferenciação própria documentada e cobertura cartográfica continuam pendentes. A demonstração sintética não mede oferta laboral nem potencial regional real. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, migração, publicação automática, escrita activa, alteração de permissões ou reinício de serviços. - - -### 04/11/2026 — ACT-20261029-02: observações quantitativas públicas de emprego e contexto económico - -Incremento na main local sobre `a9241ff2`. Inventário prévio: fichas de parques já conservam observações com valor, unidade, período, âmbito, população/base, metodologia, conhecimento e divulgação seleccionada. Reutilizada apenas a versão pública de `operational_details.public.integral.observations`, sem desencriptar preparação privada. Na cópia QA havia oito fichas públicas e zero observações quantitativas divulgadas; não foi declarada perda nem ausência no remoto. As 51 provas anteriores foram conferidas por SHA256 antes da ronda e novamente no fim, todas inalteradas; bateria geral aceite preservada sem repetição integral. - -A API de mapa acrescenta `quantitative_context` a partir do mesmo conjunto de zonas já devolvido no contexto territorial: emprego para mão-de-obra; investimento, produção, exportações e compras locais para contexto económico. Reutiliza os filtros/autorização existentes, sem alargar a pesquisa de oportunidades nem transformar indicadores do parque em indicadores das oportunidades. Filtros específicos que já excluem esse conjunto devolvem âmbito não incluído, em vez de uma falsa medição vazia. Até 30 fichas e 200 observações; truncagem explícita. Geometrias, divulgação, fontes e versões anteriores conservadas. - -O painel do mapa mostra cada valor com a sua unidade, período, âmbito, população/base, metodologia, fonte/data, versão pública e ligação à ficha. Zero documentado e valor desconhecido são distintos; precisão decimal conserva-se como texto. Divergências e metadados em falta permanecem visíveis. Emprego não é oferta de trabalhadores disponíveis; natureza prevista/efectiva depende da descrição da fonte. Não se somam populações ou períodos, não se convertem unidades/moedas e não se criam médias, índices ou previsões de retorno. Contagens de oportunidades e de observações territoriais têm âmbitos distintos. Erro, carregamento, cadastro indisponível, âmbito não consultado e ausência de observações são estados diferentes. - -Verificação dirigida aprovada: 11 testes BD/99 asserções (seis novos e cinco do mapa temático existente), 18 testes frontend (três novos e 15 existentes), PHPStan sem erros, tipos, Pint, lint e compilação QA aprovados. Inclui zero/decimais, desconhecido/divergência, metadados incompletos, exclusão de preparação privada/ficha não publicada, preservação do envelope, província/distrito, limites de observações/fichas e âmbito excluído. Primeira tentativa teve uma expectativa inadequada sobre a serialização JSON antes da normalização jsonb; comparação corrigida para duas leituras efectivas do servidor. Fixture frontend com rótulo repetido corrigida; não se relaxaram regras do produto. Logs BD iniciais mantidos. - -Conferência visual exclusivamente em `127.0.0.2:18644`/`main_visual_20261104_test`: uma ficha sintética nova com cinco observações. Camada laboral mostra zero previsto e emprego indirecto por determinar, em duas linhas; económica mostra 125.7500 toneladas, 100000.00 MZN e 25.50 USD em divergência, em três linhas, com as respectivas fontes e períodos. Valores exclusivamente de teste, sem aplicação económica real. Nenhuma coordenada/geometria criada; hash de todas as fichas territoriais anteriores idêntico antes/depois. Recibo e hashes: `docs/investmoz/unification/quantitative-map-local-20261104.json`; inventário, capturas e DOM em `outputs/quantitative-map-20261104/`. - -**ACT-02 permanece parcial.** Cobertura factual nacional/regional, séries comparáveis, oferta laboral, natureza das grandezas e metodologia quantitativa de potencial económico continuam pendentes conforme dados aplicáveis. A demonstração sintética não é estatística real, índice regional ou diagnóstico do portal remoto. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, instalação, escrita activa, migração, publicação automática ou alteração de permissões/serviços. - -Precisão adicional demonstrada: número JSON `1234567890123.456789` recuperado sem arredondamento. O valor é extraído como texto decimal do mesmo snapshot público carregado, sem o converter num float PHP nem misturar metadados e versão com uma leitura posterior. O teste dirigido de precisão e PHPStan passaram após esta correcção. diff --git a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv index ae70cf05..1454fa23 100644 --- a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv +++ b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv @@ -395,7 +395,7 @@ MASTER-9dee08d0-0004,"O portal deve servir como um balcão ou agregador facilita MASTER-9dee08d0-0005,Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:,portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 118 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 122 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 135,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-9dee08d0-0005: Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor: | MASTER-efd550fd-0005: Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor: | MASTER-9f5719c8-0006: Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:,P2,MASTER-9dee08d0-0005: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0005: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0006: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0005 | MASTER-efd550fd-0005 | MASTER-9f5719c8-0006,3,"[{""id"":""MASTER-9dee08d0-0005"",""pedido"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 118""],""aceitacao"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-efd550fd-0005"",""pedido"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 122""],""aceitacao"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-9f5719c8-0006"",""pedido"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 135""],""aceitacao"":""Princípios de experiência do utilizador: O portal deve ser desenhado a partir das principais tarefas do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0006,"Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 124 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 128 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 141 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 145,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0006: Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado. | MASTER-efd550fd-0006: Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado. | MASTER-9f5719c8-0007: Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado. | MASTER-626cae3d-0004: Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado.",P2,MASTER-9dee08d0-0006: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0006: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0007: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0004: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0006 | MASTER-efd550fd-0006 | MASTER-9f5719c8-0007 | MASTER-626cae3d-0004,4,"[{""id"":""MASTER-9dee08d0-0006"",""pedido"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 124""],""aceitacao"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-efd550fd-0006"",""pedido"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 128""],""aceitacao"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-9f5719c8-0007"",""pedido"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 141""],""aceitacao"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-626cae3d-0004"",""pedido"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 145""],""aceitacao"":""Cada página deve reduzir dúvidas, evitar jargão excessivo, apresentar chamadas de acção claras e oferecer um caminho visível para apoio especializado."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0007,"Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 125 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 129 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 142 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 146,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0007: Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional. | MASTER-efd550fd-0007: Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional. | MASTER-9f5719c8-0008: Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional. | MASTER-626cae3d-0005: Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional.",P2,MASTER-9dee08d0-0007: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0007: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0005: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0007 | MASTER-efd550fd-0007 | MASTER-9f5719c8-0008 | MASTER-626cae3d-0005,4,"[{""id"":""MASTER-9dee08d0-0007"",""pedido"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 125""],""aceitacao"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-efd550fd-0007"",""pedido"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 129""],""aceitacao"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-9f5719c8-0008"",""pedido"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 142""],""aceitacao"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-626cae3d-0005"",""pedido"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 146""],""aceitacao"":""Calculadora ou simulador de incentivos: permitir ao investidor estimar, de forma orientadora, possíveis impostos, benefícios fiscais e requisitos aplicáveis em função da província, do sector, da localização em ZEE ou ZFI e do volume de investimento, deixando claro que o resultado depende de validação legal e institucional."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, -MASTER-9dee08d0-0008,"Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 126,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-9dee08d0-0008: Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos.",P2,MASTER-9dee08d0-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0008,1,"[{""id"":""MASTER-9dee08d0-0008"",""pedido"":""Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 126""],""aceitacao"":""Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, +MASTER-9dee08d0-0008,"Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 126,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [02/11/2026: levantamento de codigo e incremento parcial preparados; quatro linguas solicitadas, cobertura transversal pendente. Ver roteiro-manual-qa-i0-i3.md.]","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-9dee08d0-0008: Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos.",P2,MASTER-9dee08d0-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0008,1,"[{""id"":""MASTER-9dee08d0-0008"",""pedido"":""Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 126""],""aceitacao"":""Suporte multilingue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de ação e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manutenção dos conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0009,"Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 127 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 131 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 144 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 148,CRM/solicitações,//; /Simulador; /api/v1/documents/recommendations; /api/v1/investment/submissions; /api/v1/investment/submissions/{id}; /api/v1/investment/submissions/{id}/attachments; /api/v1/investment/submissions/{id}/attachments/{attachment}; /api/v1/investment/submissions/{id}/submit; /apoio; /balcao-virtual; /como-investir; /documentos,"investors/contacts/leads/tasks, OpportunityContacts, acompanhamento interno existente. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Converter sem duplicar, tarefa/responsável/próxima ação recuperáveis; corrigir apenas falha comprovada. Critério individual original preservado; cobertura atual ainda não individualizada.",Relações mestre/contexto e autorizações; não depende de CRM externo. C131 sóQA. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-9dee08d0-0009: Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento. | MASTER-efd550fd-0009: Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento. | MASTER-9f5719c8-0010: Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento. | MASTER-626cae3d-0007: Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento.",P2,MASTER-9dee08d0-0009: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0009: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0010: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0007: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0009 | MASTER-efd550fd-0009 | MASTER-9f5719c8-0010 | MASTER-626cae3d-0007,4,"[{""id"":""MASTER-9dee08d0-0009"",""pedido"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 127""],""aceitacao"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""CRM/solicitações""},{""id"":""MASTER-efd550fd-0009"",""pedido"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 131""],""aceitacao"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""CRM/solicitações""},{""id"":""MASTER-9f5719c8-0010"",""pedido"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 144""],""aceitacao"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""CRM/solicitações""},{""id"":""MASTER-626cae3d-0007"",""pedido"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 148""],""aceitacao"":""Área Reservada ou Dashboard do Investidor: permitir ao investidor acompanhar o estado das submissões, visualizar documentos pendentes, receber notificações, agendar reuniões virtuais, consultar histórico de interacções e solicitar assistência direta junto dos serviços de facilitação do investimento."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""CRM/solicitações""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.interest_requests: 4 registos; public.leads: 0 registos; public.investors: 3 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Converter sem duplicar, tarefa/responsável/próxima ação recuperáveis; corrigir apenas falha comprovada. Critério individual original preservado; cobertura atual ainda não individualizada.","investors/contacts/leads/tasks, OpportunityContacts, acompanhamento interno existente",Relações mestre/contexto e autorizações; não depende de CRM externo. C131 sóQA.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: acompanhamento. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,acompanhamento,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/CrmController.php; app/Services/DeclaredOriginStatistics.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"InterestSubmissionTest, InvestmentWorkspaceTest, PortalOriginCompatibilityTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0010,"Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio constante.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 129,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-9dee08d0-0010: Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio constante.",P2,MASTER-9dee08d0-0010: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0010,1,"[{""id"":""MASTER-9dee08d0-0010"",""pedido"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio constante."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 129""],""aceitacao"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio constante."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. | 21/10/2026: pedido expresso da Tempo para uma única navbar, sem retirar acessos; aplicação de AGENTS.md, decisões de 12/10/2026. Agrupamento Tempo, posições, breakpoint 1280px e altura 72px são escolhas de apresentação, não novas regras operacionais. Prova local isolada do header em tools/portal-header-qa.mjs e outputs/header-navbar-20261021/qa-results.json; não encerra o critério integral nem representa implantação no activo.",documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0011,A navegação deve reflectir o ciclo de vida do investidor:,portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 134 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 135 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 148 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 152,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,"28/10:menus 6e8de43a instalados e delta técnico conferido;conferência visual autenticada pendente;aceitações anteriores preservadas. Histórico: 28/10:reorganização implementada/verificada estruturalmente em QA,sem instalação;validação visual/sessão real pendente;âmbito anterior preservado. Histórico: Sem evidência suficiente | Registo da linha entregue (continuacao): 28/10:revisão de apresentação emQA após relato Tempo;verificação do delta pendente,aceitação anterior preservada no seu âmbito. Histórico: Sem evidência suficiente","28/10:omissões/ocultação corrigidas no código instalado;resta observar a sessão real e responsividade sem presumir perda de permissões. Lacuna anterior: 28/10:omissão de subdestinos e ocultação da área de trabalho corrigidas no candidato QA;falta conferência visual e capacidades reais da sessão,sem presumir perda de permissões. Lacuna histórica: Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada. | Registo da linha entregue (continuacao): 28/10:confirmadas omissão de subdestinos na barra lateral e ocultação da área de trabalho no menu da conta;props/acesso da sessão real não demonstrados,sem presumir falta de permissões. Lacuna histórica: Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-9dee08d0-0011: A navegação deve reflectir o ciclo de vida do investidor: | MASTER-efd550fd-0011: A navegação deve reflectir o ciclo de vida do investidor: | MASTER-9f5719c8-0012: A navegação deve reflectir o ciclo de vida do investidor: | MASTER-626cae3d-0009: A navegação deve reflectir o ciclo de vida do investidor:,P2,MASTER-9dee08d0-0011: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0011: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0012: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0009: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0011 | MASTER-efd550fd-0011 | MASTER-9f5719c8-0012 | MASTER-626cae3d-0009,4,"[{""id"":""MASTER-9dee08d0-0011"",""pedido"":""A navegação deve reflectir o ciclo de vida do investidor:"",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 134""],""aceitacao"":""A navegação deve reflectir o ciclo de vida do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-efd550fd-0011"",""pedido"":""A navegação deve reflectir o ciclo de vida do investidor:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 135""],""aceitacao"":""A navegação deve reflectir o ciclo de vida do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-9f5719c8-0012"",""pedido"":""A navegação deve reflectir o ciclo de vida do investidor:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 148""],""aceitacao"":""A navegação deve reflectir o ciclo de vida do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-626cae3d-0009"",""pedido"":""A navegação deve reflectir o ciclo de vida do investidor:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 152""],""aceitacao"":""A navegação deve reflectir o ciclo de vida do investidor:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global. @@ -419,7 +419,7 @@ MASTER-9dee08d0-0012,"Carteira PII 2026-2030: cada sector deve apresentar oportu MASTER-9dee08d0-0013,"Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, disponibilidade técnica das entidades públicas e validação jurídica dos fluxos de dados.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 161,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0013: Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, disponibilidade técnica das entidades públicas e validação jurídica dos fluxos de dados.",P2,MASTER-9dee08d0-0013: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0013,1,"[{""id"":""MASTER-9dee08d0-0013"",""pedido"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, disponibilidade técnica das entidades públicas e validação jurídica dos fluxos de dados."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 161""],""aceitacao"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, disponibilidade técnica das entidades públicas e validação jurídica dos fluxos de dados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0014,O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:,portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 186 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 177 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 190 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 194,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-9dee08d0-0014: O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique: | MASTER-efd550fd-0014: O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique: | MASTER-9f5719c8-0015: O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique: | MASTER-626cae3d-0012: O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:,P2,MASTER-9dee08d0-0014: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0014: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0015: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0012: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0014 | MASTER-efd550fd-0014 | MASTER-9f5719c8-0015 | MASTER-626cae3d-0012,4,"[{""id"":""MASTER-9dee08d0-0014"",""pedido"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 186""],""aceitacao"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-efd550fd-0014"",""pedido"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 177""],""aceitacao"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-9f5719c8-0015"",""pedido"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 190""],""aceitacao"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-626cae3d-0012"",""pedido"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 194""],""aceitacao"":""O conteúdo e os fluxos de trabalho do portal devem refletir rigorosamente o quadro legal vigente em Moçambique:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0015,"Instruções claras sobre a obrigatoriedade de registo do capital de entrada junto do Banco de Moçambique para assegurar o direito de transferência de lucros, dividendos e capital investido de volta ao país de origem.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 191,dashboard/perfis,/api/v1/investment/companies/{id?}; /api/v1/investment/notifications; /api/v1/investment/notifications/{id}/read; /api/v1/investment/profile; /api/v1/investment/submissions/{id}/messages; /api/v1/investment/submissions/{id}/revisions/{version}; /dashboard; /investidor/companies/{id?}; /investidor/manifestacoes/{id}/messages; /investidor/manifestacoes/{id}/revisions/{version}; /investidor/notifications; /investidor/notifications/{id}/read,"Fortify, PortalProfileAdministration/Access, grants, policies, portal_security_approvals e menus atuais. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Reutilizar provas existentes; suplementar autorização/revogação/elevação por ação/consumidor, sem sistema paralelo. Critério individual original preservado; cobertura atual ainda não individualizada.","030000→040000 instalados, seis categorias ON; contas/grants reais concluídos. Autorizações por tipo/org e independência mantidas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0015: Instruções claras sobre a obrigatoriedade de registo do capital de entrada junto do Banco de Moçambique para assegurar o direito de transferência de lucros, dividendos e capital investido de volta ao país de origem.",P1,MASTER-9dee08d0-0015: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0015,1,"[{""id"":""MASTER-9dee08d0-0015"",""pedido"":""Instruções claras sobre a obrigatoriedade de registo do capital de entrada junto do Banco de Moçambique para assegurar o direito de transferência de lucros, dividendos e capital investido de volta ao país de origem."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 191""],""aceitacao"":""Instruções claras sobre a obrigatoriedade de registo do capital de entrada junto do Banco de Moçambique para assegurar o direito de transferência de lucros, dividendos e capital investido de volta ao país de origem."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""dashboard/perfis""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.investment_accounts: 0 registos; public.investment_company_declarations: 0 registos; public.investment_submissions: 3 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Reutilizar provas existentes; suplementar autorização/revogação/elevação por ação/consumidor, sem sistema paralelo. Critério individual original preservado; cobertura atual ainda não individualizada.","Fortify, PortalProfileAdministration/Access, grants, policies, portal_security_approvals e menus atuais","030000→040000 instalados, seis categorias ON; contas/grants reais concluídos. Autorizações por tipo/org e independência mantidas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: perfis. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,perfis,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/DashboardController.php; app/Services/CountryCatalogue.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"InvestmentWorkspaceTest, InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, -MASTER-9dee08d0-0016,"Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 208 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 195 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 208 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 213,simuladores,/api/v1/questionnaires/{code}; /api/v1/simulation-drafts; /api/v1/simulation-drafts/claim; /api/v1/simulation-drafts/claim-preview; /api/v1/simulation-drafts/current; /api/v1/simulation-drafts/linkable-businesses; /api/v1/simulation-drafts/{id}; /api/v1/simulation-drafts/{id}/business-link; /api/v1/simulation-drafts/{id}/conversions; /api/v1/simulation-drafts/{id}/touch; /api/v1/simulations; /api/v1/simulations/history,"SimulationExecution, resultados/cenários/fontes, rascunhos e dossier existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cenário→cálculo→gravação→resultado/dossier correto→nova sessão→PDF/derivadas autorizadas. Sem aprovação/score inventado. Critério individual original preservado; cobertura atual ainda não individualizada.,"Regras financeiras/fiscais separadas; fonte oficial aceite, parâmetros/âmbito/período podem faltar; não substituir por0/taxa atual. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0016: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-efd550fd-0016: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-9f5719c8-0017: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-626cae3d-0014: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania.",P2,MASTER-9dee08d0-0016: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0016: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0014: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0016 | MASTER-efd550fd-0016 | MASTER-9f5719c8-0017 | MASTER-626cae3d-0014,4,"[{""id"":""MASTER-9dee08d0-0016"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 208""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-efd550fd-0016"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 195""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-9f5719c8-0017"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 208""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-626cae3d-0014"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 213""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.simulation_form_drafts: 22 registos; public.simulation_scenarios: 16 registos; public.simulations: 16 registos; public.simulation_tax_rules: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global. | 23/10/2026 — adequação do hero por pedido expresso da Tempo. Aplicadas as orientações permanentes AGENTS.md de 12/10 e 22/10/2026: regras da Tempo, escolhas técnicas identificadas e preservação de dados/histórico. Rotação, WebP e composição são escolhas de implementação. Pesquisa mantém o catálogo existente; não constitui pesquisa global de legislação/licenciamento nem nova restrição organizacional.",Cenário→cálculo→gravação→resultado/dossier correto→nova sessão→PDF/derivadas autorizadas. Sem aprovação/score inventado. Critério individual original preservado; cobertura atual ainda não individualizada.,"SimulationExecution, resultados/cenários/fontes, rascunhos e dossier existentes","Regras financeiras/fiscais separadas; fonte oficial aceite, parâmetros/âmbito/período podem faltar; não substituir por0/taxa atual.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: simuladores. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. | 23/10/2026 — adequação do hero por pedido expresso da Tempo: docs/investmoz/public-portal-hero-validation.json; tools/portal-hero-qa.mjs; outputs/portal-hero-20261023/qa-results.json e capturas. Componentes reais com API/navegação sintéticas, sem base activa. Prova limitada ao hero, pesquisa de oportunidades e preservação da entrada documental; critérios mais amplos não encerrados.",simuladores,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/SimulationTaxParameterResolver.php; resources/js/components/simulation-form.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"SimulationExecutionTest, SimulationFormDraftTest, SimulationDraftContinuityTest, SimulationTaxRuleGovernanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, +MASTER-9dee08d0-0016,"Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 208 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 195 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 208 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 213,simuladores,/api/v1/questionnaires/{code}; /api/v1/simulation-drafts; /api/v1/simulation-drafts/claim; /api/v1/simulation-drafts/claim-preview; /api/v1/simulation-drafts/current; /api/v1/simulation-drafts/linkable-businesses; /api/v1/simulation-drafts/{id}; /api/v1/simulation-drafts/{id}/business-link; /api/v1/simulation-drafts/{id}/conversions; /api/v1/simulation-drafts/{id}/touch; /api/v1/simulations; /api/v1/simulations/history,"SimulationExecution, resultados/cenários/fontes, rascunhos e dossier existentes. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cenário→cálculo→gravação→resultado/dossier correto→nova sessão→PDF/derivadas autorizadas. Sem aprovação/score inventado. Critério individual original preservado; cobertura atual ainda não individualizada.,"Regras financeiras/fiscais separadas; fonte oficial aceite, parâmetros/âmbito/período podem faltar; não substituir por0/taxa atual. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0016: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-efd550fd-0016: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-9f5719c8-0017: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania. | MASTER-626cae3d-0014: Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania.",P2,MASTER-9dee08d0-0016: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0016: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0014: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0016 | MASTER-efd550fd-0016 | MASTER-9f5719c8-0017 | MASTER-626cae3d-0014,4,"[{""id"":""MASTER-9dee08d0-0016"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 208""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-efd550fd-0016"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 195""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-9f5719c8-0017"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 208""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""},{""id"":""MASTER-626cae3d-0014"",""pedido"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 213""],""aceitacao"":""Barra de Pesquisa Descontextualizada: O campo de busca deve sugerir temas directamente ligados ao investimento, como “registo de projecto na APIEX”, “benefícios fiscais”, “repatriamento de dividendos”, “Zonas Económicas Especiais” e “licenciamento simplificado”, em vez de exemplos associados a serviços gerais de cidadania."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""simuladores""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.simulation_form_drafts: 22 registos; public.simulation_scenarios: 16 registos; public.simulations: 16 registos; public.simulation_tax_rules: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global. | 23/10/2026 — adequação do hero por pedido expresso da Tempo. Aplicadas as orientações permanentes AGENTS.md de 12/10 e 22/10/2026: regras da Tempo, escolhas técnicas identificadas e preservação de dados/histórico. Rotação, WebP e composição são escolhas de implementação. Pesquisa mantém o catálogo existente; não constitui pesquisa global de legislação/licenciamento nem nova restrição organizacional.",Cenário→cálculo→gravação→resultado/dossier correto→nova sessão→PDF/derivadas autorizadas. Sem aprovação/score inventado. Critério individual original preservado; cobertura atual ainda não individualizada.,"SimulationExecution, resultados/cenários/fontes, rascunhos e dossier existentes","Regras financeiras/fiscais separadas; fonte oficial aceite, parâmetros/âmbito/período podem faltar; não substituir por0/taxa atual.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: simuladores. Esforço de código adicional só após lacuna reproduzida.,"outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual. | 23/10/2026 — adequação do hero por pedido expresso da Tempo: docs/investmoz/public-portal-hero-validation.json; tools/portal-hero-qa.mjs; outputs/portal-hero-20261023/qa-results.json e capturas. Componentes reais com API/navegação sintéticas, sem base activa. Prova limitada ao hero, pesquisa de oportunidades e preservação da entrada documental; critérios mais amplos não encerrados.",simuladores,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/SimulationTaxParameterResolver.php; resources/js/components/simulation-form.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"SimulationExecutionTest, SimulationFormDraftTest, SimulationDraftContinuityTest, SimulationTaxRuleGovernanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,," | 03/11/2026: pesquisa rápida local em preparação; páginas e sete grupos públicos, palavras em ordem livre e sem acentos, paginação e aviso de fonte indisponível. Provas isoladas sem BD; consulta real, desempenho, ficheiros, dados privados e cobertura integral pendentes. Não instalada no activo. | 04/11/2026: candidata local com cores Tempo, resultados combinados por relevância e paginação global de cinco, variantes ortográficas e pesquisa de edições editoriais públicas; provas isoladas sem base. Consulta e desempenho com dados reais, ficheiros originais e módulos privados continuam pendentes; sem instalação no activo.","0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-9dee08d0-0017,"Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo.",portal do investidor\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 209 | portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 196 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 209 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 214,oportunidades,/api/v1/business-opportunities; /api/v1/business-opportunities/{slug}; /investidor/terra-duat; /investidor/terra-duat/novo; /investidor/terra-duat/{id}; /investidor/terra-duat/{id}/actualizacoes; /investidor/terra-duat/{id}/documentos; /investidor/terra-duat/{id}/documentos/{attachment}; /investidor/terra-duat/{id}/editar; /investidor/terra-duat/{id}/imprimir; /investidor/terra-duat/{id}/solicitar-apoio; /management/opportunities,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.; SectorInvestment e páginas existentes: conteúdo, oportunidades públicas, associações cadastradas e ações; contexto no mesmo InvestorPath e pré-seleção canónica do setor.","Correcção sectorial669cb897 instalada27/10,validada sobre9fda6d6e;cartões para URLs próprias sem apresentação de todos os detalhes. | Histórico preservado: Disponibilizado em 15/10/2026, setores-fintech-QA-d5b4dc354265 DOC01: 16 fontes e compilação; sete entradas setoriais e especialização Fintech no dossier; três artigos publicados (recursos reais 27/28/29), imagem 24 reutilizada por identidade/hash. Flags existentes preservadas; sem migrations/categorias novas. B e COUNTRY02 preservados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Implementado parcialmente — entradas setoriais e três artigos ativos,Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-9dee08d0-0017: Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo. | MASTER-efd550fd-0017: Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo. | MASTER-9f5719c8-0018: Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo. | MASTER-626cae3d-0015: Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo.",P2,MASTER-9dee08d0-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-efd550fd-0017: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0018: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0015: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-9dee08d0-0017 | MASTER-efd550fd-0017 | MASTER-9f5719c8-0018 | MASTER-626cae3d-0015,4,"[{""id"":""MASTER-9dee08d0-0017"",""pedido"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""fontes"":[""portal do investidor\\Reformulacao do portal do investidor.docx; SHA 9dee08d0ebbbb262651a01ffc7e0ade97323664bda59fe8ce0b07ead82736ce1; w:p 209""],""aceitacao"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-efd550fd-0017"",""pedido"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 196""],""aceitacao"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-9f5719c8-0018"",""pedido"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 209""],""aceitacao"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-626cae3d-0015"",""pedido"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 214""],""aceitacao"":""Falta de Profundidade nos Cards: As descrições dos sectores estratégicos devem abandonar frases genéricas e apresentar informação específica de cada área, incluindo oportunidades, localização, tipo de investidor-alvo, principais incentivos, entidades competentes e documentos necessários para iniciar o processo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.opportunities: 6 registos; public.opportunity_images: tabela ausente; public.opportunity_documents: tabela ausente; public.opportunity_location_drafts: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global. | QA 15/10/2026: setores-fintech-QA-d5b4dc354265; sete entradas comerciais/contexto no dossier e três artigos preparados. B/COUNTRY02/aceitações preservados; sem disponibilização ativa. | Disponibilização expressamente autorizada pela Tempo: «Autorizo a disponibilizar». Executada com backup/restauro fresco verificado; apenas conferência operacional, sem repetir aceitação QA. [RECONCILIACAO-43-20261019] 5: Sem saldo de código no recorte visual aceite.","Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada. | Entrega operacional deste delta concluída. Mercado Financeiro geral vazio e restante acervo mantêm os seus estados. Licenças, requisitos e documentos específicos Fintech por atividade permanecem por determinar; não bloqueiam a preparação independente nem se consideram concluídos. Mantém-se o detalhe integral de incentivos, entidades e documentos específicos por setor por completar. | Recorte QA demonstrado, sem encerrar critérios globais. Histórico económico combinado conservado, fora de novas escolhas; oportunidade6 não inferida como Fintech. Sem fusões por nome. Recuperação existente conferida por leitura e hashes; outra sessão/dispositivo e percursos aceites não reensaiados. Conferência dos anexos pelo utilizador pendente. | Recorte aprovado disponibilizado; requisitos globais permanecem abertos. Atividade historica combinada e oportunidade6 sem reclassificacao. Conferencia dos anexos finais pelo utilizador pendente. Sem repetir testes aceites, formularios ou L1. @@ -969,7 +969,7 @@ MASTER-f70ce307-0002,5.9.1. Documentos obrigatórios e controlos dos campos MIN2 MASTER-51b8f0ad-0002,5.9.1. Documentos obrigatórios e controlos dos campos MIN62,portal do investidor\Portal V4\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 72,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,MASTER-51b8f0ad-0002: 5.9.1. Documentos obrigatórios e controlos dos campos MIN62,P2,MASTER-51b8f0ad-0002: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-51b8f0ad-0002,1,"[{""id"":""MASTER-51b8f0ad-0002"",""pedido"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN62"",""fontes"":[""portal do investidor\\Portal V4\\upgrade do portal de investimentos v2.docx; SHA 51b8f0ad3296d1064a5c12b450874fc72640869f10a164319cd7f3153dd3a086; w:p 72""],""aceitacao"":""5.9.1. Documentos obrigatórios e controlos dos campos MIN62"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-efd550fd-0002,"Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 98 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 111,oportunidades,/api/v1/business-opportunities; /api/v1/business-opportunities/{slug}; /investidor/terra-duat; /investidor/terra-duat/novo; /investidor/terra-duat/{id}; /investidor/terra-duat/{id}/actualizacoes; /investidor/terra-duat/{id}/documentos; /investidor/terra-duat/{id}/documentos/{attachment}; /investidor/terra-duat/{id}/editar; /investidor/terra-duat/{id}/imprimir; /investidor/terra-duat/{id}/solicitar-apoio; /management/opportunities,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-efd550fd-0002: Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade. | MASTER-9f5719c8-0003: Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade.",P2,MASTER-efd550fd-0002: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0002 | MASTER-9f5719c8-0003,2,"[{""id"":""MASTER-efd550fd-0002"",""pedido"":""Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 98""],""aceitacao"":""Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-9f5719c8-0003"",""pedido"":""Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 111""],""aceitacao"":""Facilitação e acompanhamento: permitir que os investidores identifiquem os requisitos, as entidades competentes, os documentos necessários, os incentivos aplicáveis e os canais de contacto para cada oportunidade."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.opportunities: 6 registos; public.opportunity_images: tabela ausente; public.opportunity_documents: tabela ausente; public.opportunity_location_drafts: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/OpportunityManagement.php; app/Services/OpportunityResources.php; resources/js/pages/management/opportunity-draft.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"OpportunityManagementTest, OpportunityResourcesTest, OpportunityOriginReviewTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-efd550fd-0003,Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:,portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 102 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 115 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 124,governação/outros,/api/v1/investment/admin/interests/{interest}/status; /management/history; /management/interests; /management/interests/{interest}; /management/interests/{interest}/consent/contact; /management/interests/{interest}/consent/proponent; /management/opportunities; /management/opportunities/create; /management/opportunities/drafts; /management/opportunities/{id}/draft; /management/opportunities/{id}/edit; /management/opportunities/{id}/lifecycle,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.",MASTER-efd550fd-0003: Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem: | MASTER-9f5719c8-0004: Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem: | MASTER-626cae3d-0001: Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:,P2,MASTER-efd550fd-0003: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0004: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0001: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0003 | MASTER-9f5719c8-0004 | MASTER-626cae3d-0001,3,"[{""id"":""MASTER-efd550fd-0003"",""pedido"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 102""],""aceitacao"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-9f5719c8-0004"",""pedido"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 115""],""aceitacao"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""},{""id"":""MASTER-626cae3d-0001"",""pedido"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 124""],""aceitacao"":""Os eixos estruturantes e os requisitos funcionais que devem estar presentes incluem:"",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""governação/outros""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,Requisito transversal; consultar estado-ativo-after.json,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Localizar obrigação verificável e consumidores/contrato atuais antes de estimar implementação ou declarar conclusão. Critério individual original preservado; cobertura atual ainda não individualizada.,"Entidades, schema/configuração e serviços existentes; correspondência individual por estabelecer","Ler secção/versão correspondente; distinguir requisito funcional, decisão e exemplo. Fontes oficiais já aceites.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: governação e demais cláusulas. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,governação e demais cláusulas,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",AGENTS.md — componentes do domínio encontrados; correspondência integral deste requisito não presumida,; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, -MASTER-efd550fd-0008,"Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 130 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 143 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 147,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-efd550fd-0008: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos. | MASTER-9f5719c8-0009: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos. | MASTER-626cae3d-0006: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos.",P2,MASTER-efd550fd-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0009: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0006: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0008 | MASTER-9f5719c8-0009 | MASTER-626cae3d-0006,3,"[{""id"":""MASTER-efd550fd-0008"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 130""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-9f5719c8-0009"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 143""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-626cae3d-0006"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 147""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, +MASTER-efd550fd-0008,"Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 130 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 143 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 147,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual. [02/11/2026: levantamento de codigo e incremento parcial preparados; quatro linguas solicitadas, cobertura transversal pendente. Ver roteiro-manual-qa-i0-i3.md.]","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-efd550fd-0008: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos. | MASTER-9f5719c8-0009: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos. | MASTER-626cae3d-0006: Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos.",P2,MASTER-efd550fd-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0009: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0006: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0008 | MASTER-9f5719c8-0009 | MASTER-626cae3d-0006,3,"[{""id"":""MASTER-efd550fd-0008"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 130""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-9f5719c8-0009"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 143""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-626cae3d-0006"",""pedido"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 147""],""aceitacao"":""Suporte multilíngue: disponibilizar, no mínimo, versões completas em português e inglês, com alternância visível em todas as páginas principais e tradução consistente dos formulários, guias, mensagens de erro, botões de acção e documentos de apoio essenciais. A inclusão futura de francês ou mandarim deve depender dos públicos-alvo prioritários e da capacidade de manter os conteúdos."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-efd550fd-0010,"Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 132 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 145 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 149,biblioteca,//; /Simulador; /api/v1/ai/documents; /api/v1/documents/recommendations; /api/v2/investment/admin/legal-sources; /api/v2/investment/admin/legal-sources/{id}/{action}; /apoio; /balcao-virtual; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /como-investir; /documentos; /documentos/{id},"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,"MASTER-efd550fd-0010: Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo. | MASTER-9f5719c8-0011: Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo. | MASTER-626cae3d-0008: Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo.",P2,MASTER-efd550fd-0010: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0011: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0008: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0010 | MASTER-9f5719c8-0011 | MASTER-626cae3d-0008,3,"[{""id"":""MASTER-efd550fd-0010"",""pedido"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 132""],""aceitacao"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-9f5719c8-0011"",""pedido"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 145""],""aceitacao"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""},{""id"":""MASTER-626cae3d-0008"",""pedido"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 149""],""aceitacao"":""Requisitos mínimos de acessibilidade: O portal deve garantir contraste adequado, leitura simples em dispositivos móveis, navegação por teclado, textos alternativos para imagens e ícones, rótulos claros em formulários e mensagens de erro compreensíveis. Estes requisitos são essenciais para que investidores com diferentes níveis de literacia digital consigam utilizar a plataforma sem apoio contínuo."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""biblioteca""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.documents: 4 registos; public.portal_resources: 4 registos; public.portal_resource_links: 19 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Cobrir consulta/importação/doc/derivada/hash/perfil e revogação; preservar original; divulgação separada. Não inferir relação territorial. Critério individual original preservado; cobertura atual ainda não individualizada.,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF.,Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: documentos e legado. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,documentos e legado,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Http/Controllers/PortalServicesController.php; app/Jobs/ScanDocumentForMalware.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"PortalServicesTest, DocumentLibrarySchemaCompatibilityTest, ImportDocumentBatchTest, ClamDScannerIntegrationTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-efd550fd-0012,"d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 149 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 162 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 166,oportunidades,/api/v1/business-opportunities; /api/v1/business-opportunities/{slug}; /investidor/terra-duat; /investidor/terra-duat/novo; /investidor/terra-duat/{id}; /investidor/terra-duat/{id}/actualizacoes; /investidor/terra-duat/{id}/documentos; /investidor/terra-duat/{id}/documentos/{attachment}; /investidor/terra-duat/{id}/editar; /investidor/terra-duat/{id}/imprimir; /investidor/terra-duat/{id}/solicitar-apoio; /management/opportunities,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-efd550fd-0012: d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis. | MASTER-9f5719c8-0013: d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis. | MASTER-626cae3d-0010: d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis.",P2,MASTER-efd550fd-0012: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0013: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0010: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0012 | MASTER-9f5719c8-0013 | MASTER-626cae3d-0010,3,"[{""id"":""MASTER-efd550fd-0012"",""pedido"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 149""],""aceitacao"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-9f5719c8-0013"",""pedido"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 162""],""aceitacao"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""},{""id"":""MASTER-626cae3d-0010"",""pedido"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 166""],""aceitacao"":""d) Carteira PII 2026-2030: cada sector deve apresentar oportunidades associadas ao PII 2026-2030, com indicação da localização, da entidade promotora, da fase de preparação, das necessidades de financiamento, do impacto económico esperado e dos documentos de referência disponíveis."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""oportunidades""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.opportunities: 6 registos; public.opportunity_images: tabela ausente; public.opportunity_documents: tabela ausente; public.opportunity_location_drafts: tabela ausente,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.",Reconciliar contrato/cláusula e provas por categoria; completar apenas falha/variante executável identificada. Response normativo não é completo. Critério individual original preservado; cobertura atual ainda não individualizada.,"OpportunityManagement, OpportunityCanonicalContract/Response, OpportunityReviewMateriality, PortalProfileAccess, OpportunityResources","030000→040000 já instalados; contratos/resources existentes, sessão/MFA, ClamD e worker para ficheiros; gates das seis categorias ON. Variantes modulares/offers continuam separadas.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: oportunidades. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,oportunidades,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/OpportunityManagement.php; app/Services/OpportunityResources.php; resources/js/pages/management/opportunity-draft.tsx — componentes do domínio encontrados; correspondência integral deste requisito não presumida,"OpportunityManagementTest, OpportunityResourcesTest, OpportunityOriginReviewTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.",Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, MASTER-efd550fd-0013,"Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados.",portal do investidor\backup\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 157 | portal do investidor\backup\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 170 | portal do investidor\backup\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 174,Balcão/orientação,/balcao-virtual/contextos; /balcao-virtual/dossiers; /balcao-virtual/dossiers/{id}; /balcao-virtual/dossiers/{id}/documentos; /balcao-virtual/dossiers/{id}/documentos/{document}; /balcao-virtual/dossiers/{id}/documentos/{document}/conferencia; /balcao-virtual/dossiers/{id}/etapas; /balcao-virtual/dossiers/{id}/fontes; /balcao-virtual/dossiers/{id}/orientacao; /balcao-virtual/dossiers/{id}/pedidos; /balcao-virtual/dossiers/{id}/pressupostos; /balcao-virtual/dossiers/{id}/recomendacoes,"VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Ativo investemoz:5432, 295 tabelas, COUNTRY02/030000/040000 instalados; seis categorias e administração habilitadas. Leitura atual não demonstra esta cláusula individual. Legado, percurso integrado, modulares/ofertas e notificações desabilitados.",outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,Sem evidência suficiente,"Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.","MASTER-efd550fd-0013: Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados. | MASTER-9f5719c8-0014: Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados. | MASTER-626cae3d-0011: Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados.",P2,MASTER-efd550fd-0013: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-9f5719c8-0014: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas | MASTER-626cae3d-0011: Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas,MASTER-efd550fd-0013 | MASTER-9f5719c8-0014 | MASTER-626cae3d-0011,3,"[{""id"":""MASTER-efd550fd-0013"",""pedido"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor 1.docx; SHA efd550fd2a9d2a21785d7b3c140d4608f1ba27c52f156e2709e9fbf388a1a569; w:p 157""],""aceitacao"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-9f5719c8-0014"",""pedido"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v2.docx; SHA 9f5719c8b0cf78855f727d980b77a8f9409fc7f93e303e25d355d009a07d5734; w:p 170""],""aceitacao"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""},{""id"":""MASTER-626cae3d-0011"",""pedido"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""fontes"":[""portal do investidor\\backup\\Reformulacao do portal do investidor v3.docx; SHA 626cae3d584658842ca36b658e7b5b3cc98d87036747e65b29274f0209734e5a; w:p 174""],""aceitacao"":""Para transformar o portal num balcão único interoperável, as integrações de sistema devem ser tratadas como uma ambição funcional dependente de acordos institucionais, da disponibilidade técnica das entidades públicas e da validação jurídica dos fluxos de dados."",""estado"":""parcial"",""variantes"":""Todas as ocorrências exatas preservadas nas fontes; variantes de texto têm linhas distintas"",""modulo"":""Balcão/orientação""}]",Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Não demonstrado individualmente; localizar critério e executar em QA.,Texto exatamente equivalente no mesmo módulo; sem fusão semântica aproximada,parcial,public.desk_cases: 1 registos; public.desk_requests: 0 registos; public.desk_institutional_links: 0 registos; public.desk_messages: 0 registos,"A evidência existente é do domínio ou uma declaração histórica; não identifica a demonstração integral desta cláusula. Não afirmar implementado/parcial apenas por componente, menu ou teste global.","Pedido contextual→gravar→submeter→nova sessão→gestor→mensagem/documentos/resultado, reaproveitando A/B. Critério individual original preservado; cobertura atual ainda não individualizada.","VirtualDesk, pedidos/casos, anexos, contexto dossier e acompanhamento","Perfis próprios do Balcão; serviços/campos e decisões externas aplicáveis, sem inventar destinatário/prazo.",Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Reconciliação e prova individual antes de estimar alteração,Estimativa partilhada no lote correspondente de visao-consolidada-modulos.md; não somar por linha/cláusula/campo. Grupo: balcão. Esforço de código adicional só após lacuna reproduzida.,outputs/investmoz-audit-current-20261012/runtime-active.json; runtime-qa18445.json. Inventário/GET do domínio não demonstra esta cláusula individual.,balcão,12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,Verificar individualmente este critério no contrato e percurso aplicável; a matriz inicial conserva texto/fonte sem o promover a aceitação.,"QA de UI quando browser disponível; reutilizar o domínio existente. Dados/decisões específicos no backlog, sem segunda validação de fonte oficial.",app/Services/VirtualDesk.php; app/Services/Ai/InvestorGuidance.php — componentes do domínio encontrados; correspondência integral deste requisito não presumida,InvestorGuidanceTest; suite global QA e GET por perfil disponíveis. Evidência do domínio não demonstra integralmente esta cláusula; UI individual pendente.,Não demonstrado individualmente; localizar critério e executar em QA.,,,,"0,5–2 h de análise/prova por cláusula sem correspondência, agrupada por contrato/consumidor; não somar estas faixas como projetos independentes. Implementação indeterminada até localizar lacuna.",,, diff --git a/docs/investmoz/v2/auditoria-portal/roteiro-manual-qa-i0-i3.md b/docs/investmoz/v2/auditoria-portal/roteiro-manual-qa-i0-i3.md index e624cdbc..da455a08 100644 --- a/docs/investmoz/v2/auditoria-portal/roteiro-manual-qa-i0-i3.md +++ b/docs/investmoz/v2/auditoria-portal/roteiro-manual-qa-i0-i3.md @@ -1,5 +1,17 @@ # Roteiro executável de interface — I0–I3 QA +## Tradução transversal — levantamento e plano, 02/11/2026 + +O pedido actual determina a tradução nas quatro línguas já apresentadas no selector: português, inglês, francês e espanhol. A referência anterior MASTER-9dee08d0-0008 prevê pelo menos português e inglês; o pedido actual explicita as quatro línguas já expostas. O levantamento é de código, não comprova a situação no ambiente activo nem substitui os recibos de reposição ou a comparação com o último estado demonstrado. + +- Existe um contexto de idioma persistido no navegador e um dicionário em `tempo-brand.tsx`; a sua cobertura anterior concentrava-se no menu e rodapé. A tradução devolve o original quando não encontra uma chave. Os componentes institucionais `Trans` recorrem ao mesmo dicionário, mas várias das suas frases não têm entrada. +- Há 125 ficheiros em `resources/js/pages` (incluindo ficheiros auxiliares): páginas públicas, autenticação, gestão, oportunidades, carteira, percurso, dossier, simulador, terra, parcerias e outras áreas contêm textos portugueses directos. Formulários e componentes partilhados em `resources/js/lib` e `resources/js/components` também contêm rótulos e mensagens directos. A IA possui selector e textos próprios em português/inglês, sem integração completa com o idioma global. Catálogos e questionários de API têm pontos fixados em `pt-MZ`; mensagens de validação Laravel estão em português. Documentos, dados cadastrados, fontes e exportações precisam de tratamento distinto da interface e preservação do original. +- Incremento de código preparado: idioma do documento HTML acompanha o selector; textos comuns do acesso ao conteúdo, caminho de navegação, aviso de homologação, contacto de apoio e selector passam pelo contexto; algumas etiquetas institucionais passam a ter entradas nas três línguas. Os títulos sem entrada continuam no original. Esta cobertura é parcial, não representa conclusão do requisito nem publicação no activo. +- Continuação: etiquetas e placeholders de acesso e registo, apresentação do respectivo título, controlo acessível de visualização da palavra-passe e duas mensagens exactas de autenticação usam o mesmo contexto. Mensagens variáveis, restantes validações, outros ecrãs de autenticação e conteúdos de QA continuam por traduzir. Valores submetidos e comportamento de autenticação não foram alterados. O `types:check` e o build do primeiro incremento passaram; este acréscimo requer nova verificação. +- Comparação com `D:\Projects\revistatempo` e `D:\Projects\Tempo_Investidor\tempo-api`: a Revista usa componentes/hooks explicitamente marcados, POST `/api/translate`, protecção de tokens e cache; a API chama LibreTranslate e devolve o original em caso de falha, inclusive com HTTP 200. Não se demonstrou cobertura integral automática na Revista. Adaptado o cliente para os textos institucionais públicos já marcados com `Trans`, com URL configurável por `VITE_TRANSLATION_API_URL`, preservação de tokens, deduplicação e cache em memória apenas para respostas diferentes do original. Este incremento não envia dados de formulários, dossiers ou outras informações privadas para o serviço. A conectividade real, cobertura restante, resultados e exportações continuam pendentes de verificação e implementação; não declarar a plataforma traduzida. + +Sequência restante: (1) inventariar por rota e componente, comparando com o último estado demonstrado e reutilizando provas e recibos existentes; (2) consolidar catálogo versionado e detecção de chaves ausentes para as quatro línguas; (3) migrar navegação e páginas públicas, autenticação e formulários; (4) migrar oportunidades, carteira, percurso adaptativo, dossier, simulador e áreas privadas/gestão sem alterar regras nem dados; (5) tratar mensagens do servidor, catálogos, conteúdos cadastrados e relatórios, preservando origens e indicando quando não existe versão traduzida; (6) verificar alternância, persistência, regressão dos fluxos, acessibilidade e exportações em QA isolado e registar cobertura por requisito nesta matriz e neste manual. Traduções de documentos oficiais não substituem os originais. + ## C37 — causa confirmada; seleção de conta QA corrigida — P0, visual pendente 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. diff --git a/resources/js/components/input-error.tsx b/resources/js/components/input-error.tsx index f323cee9..e3ba62b7 100644 --- a/resources/js/components/input-error.tsx +++ b/resources/js/components/input-error.tsx @@ -1,17 +1,19 @@ import type { HTMLAttributes } from 'react'; import { cn } from '@/lib/utils'; +import { useTempoUi } from '@/components/tempo-brand'; export default function InputError({ message, className = '', ...props }: HTMLAttributes & { message?: string }) { + const { t } = useTempoUi(); return message ? (

- {message} + {t(message)}

) : null; } diff --git a/resources/js/components/institutional-source/source-text.tsx b/resources/js/components/institutional-source/source-text.tsx index 4d375db5..ccd33aee 100644 --- a/resources/js/components/institutional-source/source-text.tsx +++ b/resources/js/components/institutional-source/source-text.tsx @@ -1,7 +1,54 @@ +import { useEffect, useState } from 'react'; import { useTempoUi } from '@/components/tempo-brand'; +import { translateText } from '@/translation/service'; +import { protectTranslationTokens, restoreTranslationTokens } from '@/translation/utils'; -// Bridge the original Trans calls to this platform's existing language context. -export function Trans({ children }: { children: string }) { - const { t } = useTempoUi(); - return {t(children)}; +// Only the fixed public institutional texts using this component are sent to Tempo. +const cache = new Map(); +const pending = new Map>(); + +function translateInstitutionalText(text: string, language: string): Promise { + const key = JSON.stringify([language, text]); + const cached = cache.get(key); + if (cached) return Promise.resolve(cached); + const existing = pending.get(key); + if (existing) return existing; + + const protectedText = protectTranslationTokens(text); + const request = translateText({ + text: protectedText.text, + sourceLanguage: 'pt', + targetLanguage: language, + }).then(({ translatedText }) => { + // Do not accept a response that lost an identifier, URL or protected term. + for (const token of protectedText.replacements.keys()) { + if (!translatedText.includes(token)) throw new Error('Translation lost a protected token'); + } + const result = restoreTranslationTokens(translatedText, protectedText.replacements); + // Tempo's API returns the input on upstream failure: do not cache it as success. + if (result !== text) cache.set(key, result); + return result; + }).finally(() => pending.delete(key)); + pending.set(key, request); + return request; +} + +export function Trans({ children }: { children: string }) { + const { language, t } = useTempoUi(); + const localText = t(children); + const [result, setResult] = useState<{ key: string; text: string } | null>(null); + const key = JSON.stringify([language, children]); + + useEffect(() => { + if (language === 'pt' || localText !== children || !children.trim()) return; + let active = true; + translateInstitutionalText(children, language).then((text) => { + if (active) setResult({ key, text }); + }).catch(() => { + if (active) setResult(null); + }); + return () => { active = false; }; + }, [children, key, language, localText]); + + return {result?.key === key ? result.text : localText}; } diff --git a/resources/js/components/password-input.tsx b/resources/js/components/password-input.tsx index e6a9b236..db241de4 100644 --- a/resources/js/components/password-input.tsx +++ b/resources/js/components/password-input.tsx @@ -3,6 +3,7 @@ import type { ComponentProps, Ref } from 'react'; import { useState } from 'react'; import { Input } from '@/components/ui/input'; import { cn } from '@/lib/utils'; +import { useTempoUi } from '@/components/tempo-brand'; export default function PasswordInput({ className, @@ -10,6 +11,7 @@ export default function PasswordInput({ ...props }: Omit, 'type'> & { ref?: Ref }) { const [showPassword, setShowPassword] = useState(false); + const { t } = useTempoUi(); return (
@@ -23,11 +25,7 @@ export default function PasswordInput({ type="button" onClick={() => setShowPassword((prev) => !prev)} className="text-muted-foreground hover:text-foreground focus-visible:ring-ring absolute inset-y-0 right-0 flex items-center rounded-r-md px-3 focus-visible:ring-[3px] focus-visible:outline-none" - aria-label={ - showPassword - ? 'Ocultar palavra-passe' - : 'Mostrar palavra-passe' - } + aria-label={showPassword ? 'Ocultar palavra-passe' : 'Mostrar palavra-passe'} tabIndex={-1} > {showPassword ? ( diff --git a/resources/js/components/portal-hero.tsx b/resources/js/components/portal-hero.tsx index 7f7a8937..a2cc918f 100644 --- a/resources/js/components/portal-hero.tsx +++ b/resources/js/components/portal-hero.tsx @@ -241,14 +241,14 @@ export default function PortalHero({ }); }} role="search" - aria-label="Pesquisar oportunidades" + aria-label="Pesquisar no InvesteMoz" className="mt-7 w-full max-w-4xl" >
setQuery(event.target.value)} - placeholder="Ex.: agronegócio, Nampula, energia..." + placeholder="Ex.: agronegócio, Nampula, legislação..." className="h-12 w-full min-w-0 flex-1 rounded-xl border-0 bg-white px-4 text-base text-slate-900 outline-none placeholder:text-slate-500" />
@@ -127,15 +129,15 @@ export default function Login({ status, canResetPassword, qaAccount }: Props) { data-test="login-button" > {processing && } - Entrar + {t('Entrar')}
{/* @chisel-registration */}
- Ainda não tem conta?{' '} + {t('Ainda não tem conta?')}{' '} - Criar conta + {t('Criar conta')}
{/* @end-chisel-registration */} diff --git a/resources/js/pages/auth/register.tsx b/resources/js/pages/auth/register.tsx index 409efe2b..75b98678 100644 --- a/resources/js/pages/auth/register.tsx +++ b/resources/js/pages/auth/register.tsx @@ -1,4 +1,5 @@ import { participationIdentity } from '@/lib/participation-identity'; +import { useTempoUi } from '@/components/tempo-brand'; import { Form, Head } from '@inertiajs/react'; import InputError from '@/components/input-error'; import PasswordInput from '@/components/password-input'; @@ -15,9 +16,10 @@ type Props = { }; export default function Register({ passwordRules }: Props) { + const { t } = useTempoUi(); return ( <> - +
- +
- + @@ -76,7 +78,7 @@ export default function Register({ passwordRules }: Props) {
{processing && } - Criar conta + {t('Criar conta')}
- Já tem conta?{' '} + {t('Já tem conta?')}{' '} - Entrar + {t('Entrar')}
diff --git a/resources/js/pages/investment/shared.tsx b/resources/js/pages/investment/shared.tsx index ffcca67a..1d883454 100644 --- a/resources/js/pages/investment/shared.tsx +++ b/resources/js/pages/investment/shared.tsx @@ -1,6 +1,6 @@ import { Head, Link, usePage } from '@inertiajs/react'; import type { ReactNode } from 'react'; -import { PortalMenu } from '@/layouts/portal-navigation'; +import { PortalMenu } from '@/components/portal-menu'; import { cn } from '@/lib/utils'; import type { TerritorialSourceEvidence } from '@/components/territorial-source-evidence'; import type { diff --git a/resources/js/pages/portal/article.tsx b/resources/js/pages/portal/article.tsx index 66d11248..d5f0985b 100644 --- a/resources/js/pages/portal/article.tsx +++ b/resources/js/pages/portal/article.tsx @@ -1,5 +1,5 @@ import { Head, Link } from '@inertiajs/react'; -import { PortalMenu } from '@/layouts/portal-navigation'; +import { PortalMenu } from '@/components/portal-menu'; import EditorialReading, { type EditorialArticle, } from '@/components/editorial-reading'; diff --git a/resources/js/pages/portal/document.tsx b/resources/js/pages/portal/document.tsx index b371ef12..761b95ff 100644 --- a/resources/js/pages/portal/document.tsx +++ b/resources/js/pages/portal/document.tsx @@ -1,5 +1,5 @@ import { Head, Link } from '@inertiajs/react'; -import { PortalMenu } from '@/layouts/portal-navigation'; +import { PortalMenu } from '@/components/portal-menu'; import { PublicDocumentContent, type PublicDocument, diff --git a/resources/js/pages/portal/fiscal-forms.tsx b/resources/js/pages/portal/fiscal-forms.tsx index c10d6a0d..745226cc 100644 --- a/resources/js/pages/portal/fiscal-forms.tsx +++ b/resources/js/pages/portal/fiscal-forms.tsx @@ -1,15 +1,7 @@ import { Head, Link, router } from '@inertiajs/react'; import { useEffect, useState } from 'react'; import { PortalMenu } from '@/layouts/portal-navigation'; -import { - fiscalForms, - fiscalFormFields, - fiscalPreparationIssues, - newFiscalPreparation, - readFiscalPreparation, - type FiscalFormKind, - type FiscalPreparation, -} from '@/lib/fiscal-form-preparation'; +import { fiscalForms, fiscalFormFields, fiscalPreparationIssues, newFiscalPreparation, readFiscalPreparation, type FiscalFormKind, type FiscalPreparation } from '@/lib/fiscal-form-preparation'; const input = 'mt-1 block w-full rounded border border-slate-400 bg-white p-3 text-slate-900'; diff --git a/resources/js/pages/portal/search.tsx b/resources/js/pages/portal/search.tsx new file mode 100644 index 00000000..935defe7 --- /dev/null +++ b/resources/js/pages/portal/search.tsx @@ -0,0 +1,54 @@ +import { Head, Link } from '@inertiajs/react'; +import { useEffect, useState } from 'react'; +import { Search as SearchIcon } from 'lucide-react'; + +type Result = { title: string; description: string | null; url: string; category: string }; +type Results = { data: Result[]; total: number; current_page: number; last_page: number; per_page: number; unavailable: string[] }; + +function pageNumbers(current: number, last: number): (number | string)[] { + const pages = [...new Set([1, last, ...Array.from({ length: 5 }, (_, i) => current - 2 + i)])] + .filter((page) => page >= 1 && page <= last).sort((a, b) => a - b); + return pages.flatMap((page, i) => i > 0 && page - pages[i - 1] > 1 ? [`gap-${page}`, page] : [page]); +} + +export default function Search({ query, results }: { query: string; results: Results }) { + const [input, setInput] = useState(query); + useEffect(() => setInput(query), [query]); + const { data, total, current_page: current, last_page: last, per_page: perPage, unavailable } = results; + const pageUrl = (page: number) => `/pesquisa?${new URLSearchParams({ q: query, page: String(page) })}`; + const start = total ? (current - 1) * perPage + 1 : 0; + const end = Math.min(start + data.length - 1, total); + + return
+ +
+
+

Pesquisa no InvesteMoz

+ + + setInput(event.target.value)} maxLength={120} className="min-h-12 min-w-0 flex-1 rounded-lg border border-slate-300 bg-white px-4 text-base text-[#101820] outline-none focus:ring-2 focus:ring-[#ed1c24]" placeholder="Oportunidades, documentos, sectores..." /> + + +
+
+
+

Pesquise por palavras em qualquer ordem. Pode escrever com ou sem acentos. Os documentos são pesquisados pelos seus dados descritivos.

+ {unavailable.length > 0 &&

Não foi possível consultar: {unavailable.join(', ')}. Os restantes resultados continuam disponíveis; tente novamente mais tarde.

} + {query &&

{total > 0 ? `Resultados ${start}–${end} de ${total}` : 'Nenhum resultado nas fontes consultadas'} para “{query}”.

} + {query && total === 0 &&

Experimente outras palavras ou uma expressão mais curta.

} +
    + {data.map((item) =>
  1. +

    {item.category}

    + {item.title} + {item.description &&

    {item.description}

    } +
  2. )} +
+ {last > 1 && } +
+
; +} diff --git a/resources/js/pages/portal/services.tsx b/resources/js/pages/portal/services.tsx index a3ab064e..9f287808 100644 --- a/resources/js/pages/portal/services.tsx +++ b/resources/js/pages/portal/services.tsx @@ -7,7 +7,7 @@ import { } from '@/components/public-document-content'; import { Head, Link, useForm, usePage } from '@inertiajs/react'; import { useState } from 'react'; -import { PortalMenu } from '@/layouts/portal-navigation'; +import { PortalMenu } from '@/components/portal-menu'; import { newSubmissionKey } from '@/lib/portal-api'; import { ProvinceSelect } from '@/components/investment-territory'; import { SimulationForm } from '@/components/simulation-form'; diff --git a/resources/js/translation/page-translator.tsx b/resources/js/translation/page-translator.tsx new file mode 100644 index 00000000..e317d860 --- /dev/null +++ b/resources/js/translation/page-translator.tsx @@ -0,0 +1,119 @@ +import { useEffect } from 'react'; +import { useTempoUi } from '@/components/tempo-brand'; +import { translateText } from '@/translation/service'; +import { protectTranslationTokens, restoreTranslationTokens } from '@/translation/utils'; + +// Never change the structure of React's DOM or the value of a form control. +const excluded = 'script,style,noscript,code,pre,textarea,[contenteditable]:not([contenteditable="false"]),[translate="no"],[data-no-translate],.no-translate'; +const attributes = ['placeholder', 'title', 'aria-label', 'alt'] as const; +type Target = { node: Text | Element; attribute?: string; original: string; translated?: string }; + +function read(target: Target): string | null { + return target.attribute ? (target.node as Element).getAttribute(target.attribute) : target.node.nodeValue; +} + +function write(target: Target, value: string): void { + if (target.attribute) (target.node as Element).setAttribute(target.attribute, value); + else target.node.nodeValue = value; +} + +export function PageTranslator() { + const { language } = useTempoUi(); + + useEffect(() => { + if (language === 'pt') return; + let active = true; + const abort = new AbortController(); + const targets = new Map>(); + const cache = new Map>(); + const queue: Array<() => void> = []; + let running = 0; + let timer: ReturnType | undefined; + let unavailable = false; + + const run = () => { + if (!active || unavailable || timer || running >= 2 || !queue.length) return; + running++; + queue.shift()?.(); + // Stay below the API's per-minute limit on large pages. + timer = setTimeout(() => { timer = undefined; run(); }, 650); + }; + const translate = (value: string): Promise => { + const previous = cache.get(value); + if (previous) return previous; + const promise = new Promise((resolve, reject) => { + queue.push(() => { + const protectedText = protectTranslationTokens(value); + translateText({ text: protectedText.text, sourceLanguage: 'auto', targetLanguage: language }, abort.signal) + .then(({ translatedText }) => { + for (const token of protectedText.replacements.keys()) { + if (!translatedText.includes(token)) throw new Error('Translation lost a protected token'); + } + resolve(restoreTranslationTokens(translatedText, protectedText.replacements)); + }) + .catch((error) => { + if (!abort.signal.aborted && (error?.status === 503 || error?.status === null)) unavailable = true; + reject(error); + }) + .finally(() => { running--; run(); }); + }); + run(); + }); + cache.set(value, promise); + promise.catch(() => cache.delete(value)); + return promise; + }; + const consider = (node: Text | Element, attribute?: string) => { + const element = node instanceof Element ? node : node.parentElement; + if (!element || element.closest(excluded)) return; + // Without an explicit value, translating an option changes the submitted value. + if (element.closest('option:not([value])')) return; + const key = attribute ?? ''; + const value = attribute ? (node as Element).getAttribute(attribute) : node.nodeValue; + if (!value || value.length > 10000 || !/\p{L}/u.test(value)) return; + let entries = targets.get(node); + if (!entries) { entries = new Map(); targets.set(node, entries); } + const old = entries.get(key); + if (old && (value === old.original || value === old.translated)) return; + const target: Target = { node, attribute, original: value }; + entries.set(key, target); + translate(value).then((translated) => { + if (!active || !node.isConnected || entries?.get(key) !== target || read(target) !== value) return; + target.translated = translated; + write(target, translated); + }).catch(() => { /* Keep the original visible when translation fails. */ }); + }; + const scan = (root: Node) => { + if (root instanceof Text) { consider(root); return; } + if (!(root instanceof Element)) return; + if (root.closest(excluded)) return; + for (const name of attributes) if (root.hasAttribute(name)) consider(root, name); + const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT); + while (walker.nextNode()) { + const node = walker.currentNode; + if (node instanceof Text) consider(node); + else if (node instanceof Element) for (const name of attributes) if (node.hasAttribute(name)) consider(node, name); + } + }; + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.type === 'characterData') scan(mutation.target); + else if (mutation.type === 'attributes' && mutation.target instanceof Element && mutation.attributeName) consider(mutation.target, mutation.attributeName); + else mutation.addedNodes.forEach(scan); + } + }); + observer.observe(document.body, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: [...attributes] }); + scan(document.body); + return () => { + active = false; + abort.abort(); + if (timer) clearTimeout(timer); + observer.disconnect(); + for (const entries of targets.values()) for (const target of entries.values()) { + if (target.translated !== undefined && read(target) === target.translated) write(target, target.original); + } + }; + }, [language]); + + return null; +} diff --git a/resources/js/translation/service.ts b/resources/js/translation/service.ts new file mode 100644 index 00000000..cfede32a --- /dev/null +++ b/resources/js/translation/service.ts @@ -0,0 +1,162 @@ +import type { + TranslateRequest, + TranslateResponse, + TranslationLanguage, +} from "./types"; +import { readLanguageList } from "./utils"; + +const translationApiBaseUrl = "/api"; + +const REQUEST_TIMEOUT_MS = 65_000; +const MAX_ATTEMPTS = 3; + +export class TranslationRequestError extends Error { + status: number | null; + retryable: boolean; + + constructor(message: string, options?: { status?: number | null; retryable?: boolean }) { + super(message); + this.name = "TranslationRequestError"; + this.status = options?.status ?? null; + this.retryable = options?.retryable ?? false; + } +} + +function isRetryableStatus(status: number): boolean { + return [429, 500, 502, 503, 504].includes(status); +} + +async function wait(ms: number): Promise { + await new Promise((resolve) => window.setTimeout(resolve, ms)); +} + +async function fetchJson( + input: RequestInfo | URL, + init: RequestInit = {}, + attempt = 1, + maxAttempts = MAX_ATTEMPTS, +): Promise { + const parentSignal = init.signal; + const controller = new AbortController(); + const timeoutId = window.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS); + + const forwardAbort = () => controller.abort(); + parentSignal?.addEventListener("abort", forwardAbort, { once: true }); + + try { + const response = await fetch(input, { + ...init, + signal: controller.signal, + headers: { + Accept: "application/json", + ...(init.headers ?? {}), + }, + }); + + if (!response.ok) { + const retryable = isRetryableStatus(response.status); + if (retryable && attempt < maxAttempts) { + await wait(300 * attempt); + return fetchJson(input, init, attempt + 1, maxAttempts); + } + + let message = `Translation request failed with status ${response.status}`; + try { + const payload = (await response.json()) as { message?: string }; + if (payload?.message) { + message = payload.message; + } + } catch { + // Ignore JSON parse issues on error responses. + } + + throw new TranslationRequestError(message, { + status: response.status, + retryable, + }); + } + + return (await response.json()) as T; + } catch (error) { + const aborted = controller.signal.aborted; + const isDomAbort = error instanceof DOMException && error.name === "AbortError"; + const parentAborted = parentSignal?.aborted ?? false; + const timedOut = aborted && !parentAborted; + const retryable = timedOut || error instanceof TypeError; + + if (retryable && attempt < maxAttempts) { + await wait(300 * attempt); + return fetchJson(input, init, attempt + 1, maxAttempts); + } + + if (error instanceof TranslationRequestError) { + throw error; + } + + if (parentAborted || isDomAbort) { + throw error; + } + + if (timedOut) { + throw new TranslationRequestError("Translation request timed out", { + status: null, + retryable, + }); + } + + throw new TranslationRequestError("Translation request failed", { + status: null, + retryable, + }); + } finally { + window.clearTimeout(timeoutId); + parentSignal?.removeEventListener("abort", forwardAbort); + } +} + +export async function getLanguages(signal?: AbortSignal): Promise { + const payload = await fetchJson(`${translationApiBaseUrl}/translate/languages`, { + method: "GET", + signal, + }, 1, 1); + + return readLanguageList(payload); +} + +export async function translateText( + request: TranslateRequest, + signal?: AbortSignal, +): Promise { + const payload = await fetchJson<{ + original_text?: string; + translated_text?: string; + source_lang?: string; + target_lang?: string; + }>(`${translationApiBaseUrl}/translate`, { + method: "POST", + signal, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + text: request.text, + source_lang: request.sourceLanguage, + target_lang: request.targetLanguage, + is_html: request.isHtml ?? false, + }), + }, 1, 1); + + if (typeof payload.translated_text !== "string" || payload.translated_text.trim() === "") { + throw new TranslationRequestError("Translation response is missing translated_text", { + status: 200, + retryable: false, + }); + } + + return { + originalText: payload.original_text ?? request.text, + translatedText: payload.translated_text, + sourceLanguage: payload.source_lang ?? request.sourceLanguage, + targetLanguage: payload.target_lang ?? request.targetLanguage, + }; +} diff --git a/resources/js/translation/types.ts b/resources/js/translation/types.ts new file mode 100644 index 00000000..20bd534d --- /dev/null +++ b/resources/js/translation/types.ts @@ -0,0 +1,41 @@ +export interface TranslationLanguage { + code: string; + name: string; + targets?: string[]; +} + +export interface TranslateRequest { + text: string; + sourceLanguage: string; + targetLanguage: string; + isHtml?: boolean; +} + +export interface TranslateResponse { + originalText: string; + translatedText: string; + sourceLanguage: string; + targetLanguage: string; +} + +export interface TranslationCacheEntry { + value: string; + createdAt: number; + expiresAt: number; +} + +export interface ProtectedTranslationTokens { + text: string; + replacements: Map; +} + +export interface TranslationPayloadHealth { + shouldTranslate: boolean; + normalizedText: string; +} + +export interface TranslateOptions { + isHtml?: boolean; + signal?: AbortSignal; + protectedTerms?: string[]; +} diff --git a/resources/js/translation/utils.ts b/resources/js/translation/utils.ts new file mode 100644 index 00000000..02c6c951 --- /dev/null +++ b/resources/js/translation/utils.ts @@ -0,0 +1,615 @@ +import type { + ProtectedTranslationTokens, + TranslationPayloadHealth, + TranslationCacheEntry, + TranslationLanguage, +} from "./types"; + +const CACHE_PREFIX = "tempo_translation_v1"; +const CACHE_VERSION = "v1"; +const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; +const CACHE_MAX_ENTRIES = 200; +const CACHE_CLEANUP_INTERVAL = 12 * 60 * 60 * 1000; +const CLEANUP_MARKER_KEY = `${CACHE_PREFIX}:cleanup`; +const memoryCache = new Map(); + +const LANGUAGE_ALIASES: Record = { + ar: "ar", + "ar-sa": "ar", + en: "en", + "en-gb": "en", + "en-us": "en", + es: "es", + "es-es": "es", + fr: "fr", + "fr-fr": "fr", + hi: "hi", + "hi-in": "hi", + pt: "pt", + "pt-mz": "pt", + "pt-pt": "pt", + zh: "zh-Hans", + "zh-cn": "zh-Hans", + "zh-hans": "zh-Hans", +}; + +const apiUnsafeNodes = "script, iframe, object, embed, link, meta"; +const excludedTranslationNodes = + "code, pre, script, style, textarea, noscript, .no-translate, [data-no-translate], [translate='no']"; +const INTERNAL_PLACEHOLDER_PREFIX = "¤TRX"; +const BATCH_MAX_ITEMS = 8; +const BATCH_MAX_CHARS = 2200; +const TRANSLATION_PLACEHOLDER_PATTERN = /¤TRX[A-Z]+\d+¤/g; +const HTML_BATCH_ROOT_ATTR = "data-trx-batch-root"; +const HTML_BATCH_NODE_ATTR = "data-trx-node"; + +export const fallbackTranslationLanguages: TranslationLanguage[] = [ + { code: "pt", name: "Português" }, + { code: "en", name: "English" }, + { code: "fr", name: "French" }, + { code: "es", name: "Spanish" }, + { code: "ar", name: "Arabic" }, + { code: "hi", name: "Hindi" }, + { code: "zh-Hans", name: "Chinese" }, +]; + +export const DEFAULT_PROTECTED_TERMS = [ + "Revista TEMPO", + "Grupo TEMPO", + "Tempo TV", + "Tempo Connect", + "Informação Pública", + "InvesteMoz", + "TEMPO", +] as const; + +function getStorage(): Storage | null { + if (typeof window === "undefined") return null; + return window.localStorage; +} + +function normalizeAlias(code: string): string { + return LANGUAGE_ALIASES[code.trim().toLowerCase()] ?? code.trim(); +} + +export function normalizeLanguageCode( + code: string, + availableLanguages: TranslationLanguage[], +): string | null { + if (!code) return null; + + const normalized = normalizeAlias(code); + const supportedCodes = new Set( + availableLanguages.map((language) => normalizeAlias(language.code)), + ); + + return supportedCodes.has(normalized) ? normalized : null; +} + +export function getBrowserLanguageCode(code: string): string { + switch (code) { + case "zh-Hans": + return "zh-CN"; + default: + return code; + } +} + +export function getLocaleForLanguage(code: string): string { + switch (normalizeAlias(code)) { + case "pt": + return "pt-MZ"; + case "zh-Hans": + return "zh-CN"; + default: + return normalizeAlias(code); + } +} + +export function isRtlLanguage(code: string): boolean { + return normalizeAlias(code) === "ar"; +} + +export function readLanguageList(payload: unknown): TranslationLanguage[] { + const source = Array.isArray(payload) + ? payload + : Array.isArray((payload as { value?: unknown[] })?.value) + ? (payload as { value: unknown[] }).value + : Array.isArray((payload as { data?: unknown[] })?.data) + ? (payload as { data: unknown[] }).data + : []; + + return source + .filter((item): item is TranslationLanguage => { + return ( + Boolean(item) && + typeof item === "object" && + typeof item.code === "string" && + typeof item.name === "string" + ); + }) + .map((language) => ({ + code: normalizeAlias(language.code), + name: language.name, + targets: Array.isArray(language.targets) + ? language.targets.map((target) => normalizeAlias(target)) + : undefined, + })); +} + +export function withPortugueseFirst( + languages: TranslationLanguage[], +): TranslationLanguage[] { + const unique = new Map(); + + for (const language of languages) { + const code = normalizeAlias(language.code); + if (!unique.has(code)) { + unique.set(code, { + ...language, + code, + name: code === "pt" ? "Português" : language.name, + }); + } + } + + const items = Array.from(unique.values()).sort((a, b) => + a.name.localeCompare(b.name), + ); + + const portuguese = + items.find((language) => language.code === "pt") ?? fallbackTranslationLanguages[0]; + + return [portuguese, ...items.filter((language) => language.code !== "pt")]; +} + +export function hashTranslationText(value: string): string { + let hash = 2166136261; + + for (let index = 0; index < value.length; index += 1) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + + return (hash >>> 0).toString(16); +} + +export function createTranslationCacheKey(params: { + sourceLanguage: string; + targetLanguage: string; + isHtml: boolean; + text: string; + protectedTerms?: string[]; +}): string { + return [ + CACHE_PREFIX, + CACHE_VERSION, + params.sourceLanguage, + params.targetLanguage, + params.isHtml ? "html" : "text", + hashTranslationText(params.text), + hashTranslationText( + JSON.stringify( + collectProtectedTerms(params.protectedTerms).map((term) => term.toLowerCase()), + ), + ), + ].join(":"); +} + +export function getMemoryCacheEntry(key: string): TranslationCacheEntry | null { + const entry = memoryCache.get(key); + if (!entry) return null; + + if (entry.expiresAt <= Date.now()) { + memoryCache.delete(key); + return null; + } + + return entry; +} + +export function setMemoryCacheEntry(key: string, value: string): TranslationCacheEntry { + const entry: TranslationCacheEntry = { + value, + createdAt: Date.now(), + expiresAt: Date.now() + CACHE_TTL, + }; + + memoryCache.set(key, entry); + return entry; +} + +export function getPersistentCacheEntry(key: string): TranslationCacheEntry | null { + const storage = getStorage(); + if (!storage) return null; + + const raw = storage.getItem(key); + if (!raw) return null; + + try { + const entry = JSON.parse(raw) as TranslationCacheEntry; + if (entry.expiresAt <= Date.now()) { + storage.removeItem(key); + return null; + } + + return entry; + } catch { + storage.removeItem(key); + return null; + } +} + +export function setPersistentCacheEntry(key: string, entry: TranslationCacheEntry): void { + const storage = getStorage(); + if (!storage) return; + + storage.setItem(key, JSON.stringify(entry)); +} + +export function cleanupTranslationCache(): void { + const storage = getStorage(); + if (!storage) return; + + const lastCleanup = Number(storage.getItem(CLEANUP_MARKER_KEY) ?? "0"); + if (lastCleanup && Date.now() - lastCleanup < CACHE_CLEANUP_INTERVAL) { + return; + } + + const translationKeys: string[] = []; + + for (let index = 0; index < storage.length; index += 1) { + const key = storage.key(index); + if (key && key.startsWith(`${CACHE_PREFIX}:${CACHE_VERSION}:`)) { + translationKeys.push(key); + } + } + + const validEntries: Array<{ key: string; entry: TranslationCacheEntry }> = []; + + for (const key of translationKeys) { + const entry = getPersistentCacheEntry(key); + if (entry) { + validEntries.push({ key, entry }); + } + } + + validEntries + .sort((a, b) => a.entry.createdAt - b.entry.createdAt) + .slice(0, Math.max(0, validEntries.length - CACHE_MAX_ENTRIES)) + .forEach(({ key }) => storage.removeItem(key)); + + storage.setItem(CLEANUP_MARKER_KEY, String(Date.now())); +} + +function createPlaceholder(prefix: string, index: number): string { + return `${INTERNAL_PLACEHOLDER_PREFIX}${prefix}${index}¤`; +} + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +export function collectProtectedTerms(terms?: Array): string[] { + const combined = [...DEFAULT_PROTECTED_TERMS, ...(terms ?? [])] + .map((term) => String(term ?? "").trim()) + .filter(Boolean); + + return Array.from(new Set(combined)).sort((a, b) => b.length - a.length); +} + +function protectMatches( + input: string, + pattern: RegExp, + replacements: Map, + prefix: string, +): string { + return input.replace(pattern, (match) => { + const placeholder = createPlaceholder(prefix, replacements.size); + replacements.set(placeholder, match); + return placeholder; + }); +} + +function protectExcludedHtmlBlocks( + input: string, + replacements: Map, +): string { + if (typeof window === "undefined") return input; + + const documentFragment = new DOMParser().parseFromString(input, "text/html"); + const nodes = Array.from(documentFragment.body.querySelectorAll(excludedTranslationNodes)); + + nodes.forEach((node) => { + const placeholder = createPlaceholder("HTML", replacements.size); + replacements.set(placeholder, node.outerHTML); + node.replaceWith(documentFragment.createTextNode(placeholder)); + }); + + return documentFragment.body.innerHTML; +} + +export function protectTranslationTokens( + input: string, + options?: { isHtml?: boolean; protectedTerms?: string[] }, +): ProtectedTranslationTokens { + const replacements = new Map(); + let output = String(input ?? ""); + + if (options?.isHtml) { + output = protectExcludedHtmlBlocks(output, replacements); + } + + output = protectMatches( + output, + /https?:\/\/[^\s"'<>]+/gi, + replacements, + "URL", + ); + output = protectMatches( + output, + /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, + replacements, + "EMAIL", + ); + output = protectMatches( + output, + /\{\{[^{}]+\}\}|\{[a-zA-Z0-9_.-]+\}|%(\d+\$)?[sd]|:[a-zA-Z_][a-zA-Z0-9_]*/g, + replacements, + "TOKEN", + ); + + for (const term of collectProtectedTerms(options?.protectedTerms)) { + const escapedTerm = escapeRegExp(term); + const pattern = new RegExp(`(^|[^\\p{L}\\p{N}])(${escapedTerm})(?=$|[^\\p{L}\\p{N}])`, "giu"); + + output = output.replace(pattern, (match, prefix, protectedValue) => { + const placeholder = createPlaceholder("TERM", replacements.size); + replacements.set(placeholder, protectedValue); + return `${prefix}${placeholder}`; + }); + } + + return { text: output, replacements }; +} + +export function restoreTranslationTokens( + input: string, + replacements: Map, +): string { + let output = String(input ?? ""); + + for (const [placeholder, original] of replacements.entries()) { + output = output.split(placeholder).join(original); + } + + return output; +} + +export function getTranslationPayloadHealth( + input: string, + options?: { isHtml?: boolean; protectedTerms?: string[] }, +): TranslationPayloadHealth { + const source = String(input ?? ""); + if (!source.trim()) { + return { + shouldTranslate: false, + normalizedText: source, + }; + } + + if (options?.isHtml && typeof window !== "undefined") { + const documentFragment = new DOMParser().parseFromString(source, "text/html"); + const walker = document.createTreeWalker( + documentFragment.body, + NodeFilter.SHOW_TEXT, + { + acceptNode(node) { + return isSkippableTextNode(node as Text) + ? NodeFilter.FILTER_REJECT + : NodeFilter.FILTER_ACCEPT; + }, + }, + ); + + if (!walker.nextNode()) { + return { + shouldTranslate: false, + normalizedText: source, + }; + } + } + + const protectedPayload = protectTranslationTokens(source, options); + const remainder = protectedPayload.text + .replace(TRANSLATION_PLACEHOLDER_PATTERN, "") + .trim(); + + if (!remainder) { + return { + shouldTranslate: false, + normalizedText: source, + }; + } + + const hasLetters = /[\p{L}]/u.test(remainder); + if (!hasLetters) { + return { + shouldTranslate: false, + normalizedText: source, + }; + } + + return { + shouldTranslate: true, + normalizedText: source, + }; +} + +export function sanitizeTranslatedHtml(html: string): string { + if (typeof window === "undefined" || !html) return ""; + + const documentFragment = new DOMParser().parseFromString(String(html), "text/html"); + documentFragment.querySelectorAll(apiUnsafeNodes).forEach((node) => node.remove()); + + documentFragment.querySelectorAll("*").forEach((node) => { + for (const attribute of Array.from(node.attributes)) { + const name = attribute.name.toLowerCase(); + const value = attribute.value.trim().toLowerCase(); + + if ( + name.startsWith("on") || + value.startsWith("javascript:") || + value.startsWith("data:text/html") || + value.startsWith("vbscript:") + ) { + node.removeAttribute(attribute.name); + } + } + }); + + return documentFragment.body.innerHTML; +} + +function isSkippableTextNode(node: Text): boolean { + const parent = node.parentElement; + const value = node.textContent ?? ""; + + if (!value.trim()) return true; + if (!parent) return true; + if (parent.closest(excludedTranslationNodes)) return true; + + return false; +} + +function createBatchPayload(values: string[]): { + payload: string; +} { + if (typeof window === "undefined") { + return { + payload: values.join(" "), + }; + } + + const documentFragment = document.implementation.createHTMLDocument(""); + const root = documentFragment.createElement("div"); + root.setAttribute(HTML_BATCH_ROOT_ATTR, "1"); + + values.forEach((value, index) => { + const node = documentFragment.createElement("span"); + node.setAttribute(HTML_BATCH_NODE_ATTR, String(index)); + node.textContent = value; + root.appendChild(node); + }); + + documentFragment.body.appendChild(root); + + return { payload: root.outerHTML }; +} + +function parseBatchResponse( + translated: string, + originalValues: string[], +): string[] { + if (typeof window === "undefined") { + return originalValues; + } + + const documentFragment = new DOMParser().parseFromString(translated, "text/html"); + const root = documentFragment.body.querySelector(`[${HTML_BATCH_ROOT_ATTR}]`); + if (!root) { + return originalValues; + } + + const nodes = Array.from(root.querySelectorAll(`[${HTML_BATCH_NODE_ATTR}]`)); + if (nodes.length !== originalValues.length) { + return originalValues; + } + + return originalValues.map((originalValue, index) => { + const node = nodes.find( + (candidate) => candidate.getAttribute(HTML_BATCH_NODE_ATTR) === String(index), + ); + + return node?.textContent?.trim() ? node.textContent : originalValue; + }); +} + +function buildTextBatches(nodes: Text[]): Text[][] { + const batches: Text[][] = []; + let currentBatch: Text[] = []; + let currentLength = 0; + + for (const node of nodes) { + const textLength = (node.textContent ?? "").length; + const shouldFlush = + currentBatch.length >= BATCH_MAX_ITEMS || + currentLength + textLength > BATCH_MAX_CHARS; + + if (shouldFlush && currentBatch.length > 0) { + batches.push(currentBatch); + currentBatch = []; + currentLength = 0; + } + + currentBatch.push(node); + currentLength += textLength; + } + + if (currentBatch.length > 0) { + batches.push(currentBatch); + } + + return batches; +} + +export async function translateHtmlByTextNodes(params: { + html: string; + protectedTerms?: string[]; + translateText: (text: string, options?: { protectedTerms?: string[]; isHtml?: boolean }) => Promise; +}): Promise { + if (typeof window === "undefined" || !params.html.trim()) { + return params.html; + } + + const documentFragment = new DOMParser().parseFromString(params.html, "text/html"); + const walker = document.createTreeWalker( + documentFragment.body, + NodeFilter.SHOW_TEXT, + { + acceptNode(node) { + return isSkippableTextNode(node as Text) + ? NodeFilter.FILTER_REJECT + : NodeFilter.FILTER_ACCEPT; + }, + }, + ); + + const textNodes: Text[] = []; + let currentNode = walker.nextNode(); + while (currentNode) { + textNodes.push(currentNode as Text); + currentNode = walker.nextNode(); + } + + if (textNodes.length === 0) { + return sanitizeTranslatedHtml(documentFragment.body.innerHTML); + } + + for (const batch of buildTextBatches(textNodes)) { + const originalValues = batch.map((node) => node.textContent ?? ""); + const { payload } = createBatchPayload(originalValues); + const translatedPayload = await params.translateText(payload, { + protectedTerms: params.protectedTerms, + isHtml: true, + }); + + const translatedValues = parseBatchResponse(translatedPayload, originalValues); + + batch.forEach((node, index) => { + node.textContent = translatedValues[index]; + }); + } + + return sanitizeTranslatedHtml(documentFragment.body.innerHTML); +} diff --git a/routes/api.php b/routes/api.php index 5278aca3..07b49d34 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,6 @@ middleware('throttle:60,1'); +Route::post('translate', [TranslationApiController::class, 'translate'])->middleware('throttle:120,1'); + Route::prefix('v1')->middleware(['throttle:api', CorrelationId::class])->group(function () { Route::get('/catalogs/{catalog}', [ReferenceCatalogController::class, 'index']) ->whereIn('catalog', ['authorities', 'jurisdictions', 'economic-activities', 'countries']); diff --git a/routes/web.php b/routes/web.php index 0ecbc5b0..c4ef53ec 100644 --- a/routes/web.php +++ b/routes/web.php @@ -114,7 +114,7 @@ Route::middleware(['auth', 'verified', EnsureDocumentManagement::class])->group( Route::get('/artigos/{id}', [EditorialArticleController::class, 'show'])->whereNumber('id')->name('editorial.show'); Route::get('/carteira', [InvestmentPortfolioController::class, 'index'])->name('portfolio.index'); Route::get('/carteira/{id}', [InvestmentPortfolioController::class, 'show'])->whereUuid('id')->name('portfolio.show'); -Route::get('/carteira/{id}/interesse', [InvestmentPortfolioController::class, 'resumeInterest'])->whereUuid('id')->middleware(['auth', VerifiedOrSimpleParticipation::class])->name('portfolio.interest'); +Route::get('/carteira/{id}/interesse', [InvestmentPortfolioController::class, 'resumeInterest'])->whereUuid('id')->middleware(['auth', \App\Http\Middleware\VerifiedOrSimpleParticipation::class])->name('portfolio.interest'); Route::get('/oportunidades', [InvestmentDiscoveryController::class, 'index'])->name('portal.opportunities'); Route::get('/oportunidades/{slug}', [InvestmentDiscoveryController::class, 'detail'])->name('portal.opportunity'); Route::get('/negocios', [PublicBusinessOpportunityController::class, 'index'])->name('business-marketplace.index'); diff --git a/tests/Feature/GlobalSearchTest.php b/tests/Feature/GlobalSearchTest.php new file mode 100644 index 00000000..10660758 --- /dev/null +++ b/tests/Feature/GlobalSearchTest.php @@ -0,0 +1,55 @@ +withoutVite(); + } + + public function test_empty_and_overlong_queries(): void + { + $this->get('/pesquisa')->assertOk()->assertInertia(fn (Assert $page) => $page->component('portal/search')->where('results.total', 0)); + $this->get('/pesquisa?q='.str_repeat('a', 121))->assertSessionHasErrors('q'); + } + + public function test_source_failure_recalculates_the_page_without_hiding_the_other_results(): void + { + $sources = [ + 'Documentos' => fn () => ['count' => 1, 'fetch' => fn () => throw new QueryException('testing', 'select 1', [], new \RuntimeException('Source unavailable'))], + 'Páginas' => fn () => ['count' => 1, 'fetch' => fn ($offset, $limit) => array_slice([['title' => 'Como investir', 'url' => '/como-investir']], $offset, $limit)], + ]; + $result = app(FederatedSearch::class)->page($sources, 1); + $this->assertSame(1, $result['total']); + $this->assertSame(['Documentos'], $result['unavailable']); + $this->assertSame('Como investir', $result['data'][0]['title']); + } + + public function test_public_search_uses_the_existing_portfolio_visibility_scope(): void + { + if (getenv('GLOBAL_SEARCH_QA') !== '1') { + $this->markTestSkipped('A prova com dados exige a base QA explicitamente seleccionada.'); + } + $identity = DB::selectOne('select current_database() as name, inet_server_port() as port'); + $this->assertSame('simulator_fiscal_delta_20261021_test', $identity->name); + $this->assertSame(55441, (int) $identity->port); + $record = InvestmentPortfolioController::visible()->first(); + if (! $record) { + $this->markTestSkipped('No published portfolio records in isolated QA.'); + } + $term = mb_substr($record->title, 0, 15); + $this->get('/pesquisa?q='.urlencode($term))->assertOk()->assertInertia(fn (Assert $page) => $page + ->component('portal/search')->where('query', $term) + ->where('results.total', fn ($total) => $total >= 1)); + } +} diff --git a/tests/Feature/TranslationApiTest.php b/tests/Feature/TranslationApiTest.php new file mode 100644 index 00000000..684a044d --- /dev/null +++ b/tests/Feature/TranslationApiTest.php @@ -0,0 +1,27 @@ + 'http://translator.test']); + Http::fake(['translator.test/languages' => Http::response([['code' => 'pt', 'name' => 'Portuguese', 'targets' => ['en']]])]); + + $this->getJson('/api/translate/languages')->assertOk()->assertJsonPath('0.targets.0', 'en'); + } + + public function test_it_translates_and_reports_engine_failures(): void + { + config(['services.translation.url' => 'http://translator.test']); + Http::fake(['translator.test/translate' => Http::sequence()->push(['translatedText' => 'Hello'])->push([], 500)]); + $input = ['text' => 'Olá', 'source_lang' => 'pt', 'target_lang' => 'en']; + + $this->postJson('/api/translate', $input)->assertOk()->assertJsonPath('translated_text', 'Hello'); + $this->postJson('/api/translate', $input)->assertStatus(503); + } +} diff --git a/tests/Unit/FederatedSearchTest.php b/tests/Unit/FederatedSearchTest.php new file mode 100644 index 00000000..244bd13e --- /dev/null +++ b/tests/Unit/FederatedSearchTest.php @@ -0,0 +1,47 @@ + $count, 'fetch' => function ($offset, $limit) use (&$calls, $prefix, $count) { + $calls[] = [$prefix, $offset, $limit]; + + return array_map(fn ($i) => ['title' => $prefix.$i, 'url' => '/'.$prefix.$i], array_slice(range(1, $count), $offset, $limit)); + }]; + }; + }; + $sources = ['Páginas' => $factory('p', 3), 'Oportunidades' => $factory('o', 7), 'Documentos' => $factory('d', 2)]; + $service = new FederatedSearch; + $first = $service->page($sources, 1); + $this->assertSame(['p1', 'p2', 'p3', 'o1', 'o2'], array_column($first['data'], 'title')); + $this->assertSame(['Páginas', 'Páginas', 'Páginas', 'Oportunidades', 'Oportunidades'], array_column($first['data'], 'category')); + $this->assertSame(12, $first['total']); + $this->assertSame(3, $first['last_page']); + $calls = []; + $second = $service->page($sources, 2); + $this->assertSame(['o3', 'o4', 'o5', 'o6', 'o7'], array_column($second['data'], 'title')); + $this->assertSame([['p', 0, 5], ['o', 0, 5], ['d', 0, 5], ['o', 5, 5]], $calls); + $third = $service->page($sources, 99); + $this->assertSame(3, $third['current_page']); + $this->assertSame(['d1', 'd2'], array_column($third['data'], 'title')); + } + + public function test_more_relevant_titles_appear_first_across_sources(): void + { + $factories = [ + 'Serviços' => fn () => ['count' => 1, 'fetch' => fn ($offset, $limit) => array_slice([['title' => 'Informação', 'url' => '/info', 'score' => 10]], $offset, $limit)], + 'Sectores' => fn () => ['count' => 1, 'fetch' => fn ($offset, $limit) => array_slice([['title' => 'Sectores', 'url' => '/sectores', 'score' => 100]], $offset, $limit)], + ]; + $result = (new FederatedSearch)->page($factories, 1, 5, fn ($item) => $item['score']); + $this->assertSame(['Sectores', 'Informação'], array_column($result['data'], 'title')); + } +} diff --git a/tests/Unit/SearchTermsTest.php b/tests/Unit/SearchTermsTest.php new file mode 100644 index 00000000..fe9a1f57 --- /dev/null +++ b/tests/Unit/SearchTermsTest.php @@ -0,0 +1,59 @@ +tokens(' NAMPULA agronegócio Agronegócio '); + + $this->assertSame(['nampula', 'agronegocio'], $tokens); + $this->assertTrue($search->matches('Agronegócio em Nampula', $tokens)); + $this->assertFalse($search->matches('Agronegócio em Gaza', $tokens)); + $this->assertSame([], $search->tokens(' ')); + } + + public function test_sql_matches_each_word_across_fields_with_bound_literal_patterns(): void + { + $connection = new PostgresConnection(fn () => throw new \LogicException('A database must not be opened.')); + $query = $connection->table('records'); + $search = new SearchTerms; + $search->constrain($query, ['title', 'description'], $search->tokens('100% a_b')); + + $sql = $query->toSql(); + $this->assertStringContainsString('translate(lower(coalesce(title::text', $sql); + $this->assertStringContainsString(' or ', $sql); + $this->assertStringContainsString(' and ', $sql); + $this->assertSame(['%100!%%', '%100!%%', '%a!_b%', '%a!_b%'], $query->getBindings()); + $this->assertStringNotContainsString('100%', $sql); + } + + public function test_static_services_can_be_found_without_a_database(): void + { + $pages = (new \ReflectionMethod(GlobalSearchController::class, 'pages'))->invoke(new GlobalSearchController); + $search = new SearchTerms; + $matches = array_values(array_filter($pages, fn ($page) => $search->matches(implode(' ', $page), $search->tokens('FISCAL simulador')))); + + $this->assertCount(1, $matches); + $this->assertSame('/simulador-fiscal', $matches[0]['url']); + } + + public function test_spelling_variants_common_words_and_title_relevance(): void + { + $search = new SearchTerms; + $tokens = $search->tokens('setores de investimento'); + $this->assertTrue($search->matches('Sectores de investimento', $tokens)); + $this->assertFalse($search->matches('Sector de saúde', $tokens)); + $this->assertTrue($search->matches('Projectos âncora', $search->tokens('projeto'))); + $this->assertTrue($search->matches('Oportunidades de investimento em energia', $search->tokens('Como investir em energia?'))); + $this->assertGreaterThan($search->score('Como investir', 'investir', ['investir']), $search->score('Investir', 'investir', ['investir'])); + $this->assertSame(['de'], $search->tokens('de')); + } +} diff --git a/tests/frontend/fiscal-form-entry.test.mjs b/tests/frontend/fiscal-form-entry.test.mjs index 201561b8..8b074077 100644 --- a/tests/frontend/fiscal-form-entry.test.mjs +++ b/tests/frontend/fiscal-form-entry.test.mjs @@ -7,53 +7,14 @@ import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import ts from 'typescript'; import * as forms from '../../resources/js/lib/fiscal-form-preparation.ts'; -const require = createRequire(import.meta.url); -const source = fs.readFileSync( - new URL( - '../../resources/js/pages/portal/fiscal-forms.tsx', - import.meta.url, - ), - 'utf8', -); -const compiled = ts.transpileModule(source, { - compilerOptions: { - module: ts.ModuleKind.CommonJS, - target: ts.ScriptTarget.ES2022, - jsx: ts.JsxEmit.ReactJSX, - }, -}).outputText; -const module = { exports: {} }; -compileFunction(compiled, ['require', 'module', 'exports'])( - (name) => - name === '@inertiajs/react' - ? { - Head: () => null, - Link: ({ href, children, ...props }) => - React.createElement('a', { href, ...props }, children), - router: { on: () => () => {} }, - } - : name === '@/layouts/portal-navigation' - ? { PortalMenu: () => null } - : name === '@/lib/fiscal-form-preparation' - ? forms - : require(name), - module, - module.exports, -); -void test('fiscal entry renders labelled editable fields and a guided preparation rather than legislation', () => { - const html = renderToStaticMarkup( - React.createElement(module.exports.default), - ); - for (const label of [ - 'Identificação e período', - 'Nome ou designação social', - 'NUIT', - 'Período — ano e mês', - 'Conferir e guardar', - 'Guardar ficheiro para continuar', - 'Recuperar ficheiro guardado', - 'Confirmar recuperação', - ]) { +const require=createRequire(import.meta.url); +const source=fs.readFileSync(new URL('../../resources/js/pages/portal/fiscal-forms.tsx',import.meta.url),'utf8'); +const compiled=ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022,jsx:ts.JsxEmit.ReactJSX}}).outputText; +const module={exports:{}}; +new Function('require','module','exports',compiled)(name=>name==='@inertiajs/react'?{Head:()=>null,Link:({href,children,...props})=>React.createElement('a',{href,...props},children),router:{on:()=>()=>{}}}:name==='@/layouts/portal-navigation'?{PortalMenu:()=>null}:name==='@/lib/fiscal-form-preparation'?forms:require(name),module,module.exports); +test('fiscal entry renders labelled editable fields and a guided preparation rather than legislation',()=>{ + const html=renderToStaticMarkup(React.createElement(module.exports.default)); + for(const label of ['Identificação e período','Nome ou designação social','NUIT','Período — ano e mês','Conferir e guardar','Guardar ficheiro para continuar','Recuperar ficheiro guardado','Confirmar recuperação']) { // Confirmation appears only after a compatible file is selected. if (label !== 'Confirmar recuperação') assert.ok(html.includes(label), label); diff --git a/tests/frontend/global-search.test.mjs b/tests/frontend/global-search.test.mjs new file mode 100644 index 00000000..1820cd39 --- /dev/null +++ b/tests/frontend/global-search.test.mjs @@ -0,0 +1,36 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import { createRequire } from 'node:module'; +import React from 'react'; +import { renderToStaticMarkup } from 'react-dom/server'; +import ts from 'typescript'; + +const require = createRequire(import.meta.url); +const source = fs.readFileSync(new URL('../../resources/js/pages/portal/search.tsx', import.meta.url), 'utf8'); +const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX } }).outputText; +const module = { exports: {} }; +new Function('require', 'module', 'exports', compiled)(name => name === '@inertiajs/react' ? { + Head: () => null, + Link: ({ href, children, ...props }) => React.createElement('a', { href, ...props }, children), +} : name === 'lucide-react' ? { Search: () => null } : require(name), module, module.exports); +const Search = module.exports.default; + +test('shows five results in one sequence with numbered pagination and the query preserved', () => { + const results = { data: [{ title: 'Energia em Nampula', description: 'Projecto público', url: '/oportunidades/energia', category: 'Oportunidades' }], total: 12, current_page: 1, last_page: 3, per_page: 5, unavailable: [] }; + const html = renderToStaticMarkup(React.createElement(Search, { query: 'energia', results })); + assert.match(html, /Oportunidades/); + assert.match(html, /Resultados 1–1 de 12/); + assert.match(html, /href="\/oportunidades\/energia"/); + assert.match(html, /q=energia&page=2/); + assert.match(html, /aria-current="page"/); + assert.doesNotMatch(html, /emerald/); +}); + +test('makes source failures explicit without hiding other results', () => { + const results = { data: [], total: 0, current_page: 1, last_page: 1, per_page: 5, unavailable: ['Documentos e legislação'] }; + const html = renderToStaticMarkup(React.createElement(Search, { query: 'terra', results })); + assert.match(html, /role="alert"/); + assert.match(html, /Não foi possível consultar: Documentos e legislação/); + assert.match(html, /Nenhum resultado nas fontes consultadas/); +});