Compare commits

..
Author SHA1 Message Date
nala 25cae1d98b docs(delivery): record G4C installed delta and preserved baseline 2026-10-24 17:59:25 +02:00
nala 679203d4b1 chore(delivery): prepare G4C after authenticated backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 17:56:23 +02:00
nala 2fccbc8ee8 docs(iva): close G4C QA with Tempo manual visual confirmation 2026-10-24 17:55:23 +02:00
nala 19b31d51c5 docs(iva): record G4C code/API coverage and pending directed visual proof 2026-10-24 17:54:36 +02:00
nala b1c8e0e343 feat(iva): add G4C linked export services with explicit operation reference 2026-10-24 17:53:35 +02:00
nala 117f2a70a8 docs(iva): record G4B homologation delivery and preserved balance 2026-10-24 17:42:50 +02:00
nala a153d0782f docs(iva): prepare G4B delivery with fresh authenticated backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 17:40:34 +02:00
nala 0b0e002d15 docs(iva): record Tempo G4B visual completion and current saved result 2026-10-24 17:31:20 +02:00
nala b641887274 docs(iva): record G4B code QA and explicit browser access gate 2026-10-24 17:29:11 +02:00
nala f946364baa feat(iva): implement G4B eligible vessel aircraft and direct services 2026-10-24 17:27:32 +02:00
nala 3846be8fc6 docs(iva): record G4A homologation delivery and preserved balance 2026-10-24 17:21:31 +02:00
nala b898955603 docs(iva): prepare G4A delivery with fresh backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 17:19:15 +02:00
nala 7b54efb0fc docs(iva): record Tempo G4A visual completion and preserved historical result 2026-10-24 17:16:23 +02:00
nala 7a58fa2435 docs(iva): record G4A code QA coverage and explicit visual remainder 2026-10-24 17:08:36 +02:00
nala 0f0d2e566f feat(iva): implement G4A direct international operations with scoped evidence 2026-10-24 17:07:26 +02:00
nala 82e010c44f docs(iva): record G3 homologation delivery and preserved balance 2026-10-24 17:03:13 +02:00
nala 6eefe4b332 docs(iva): prepare G3 delivery with fresh backup restore and compatible rollback
tests / ci (push) Canceled after 0s
2026-10-24 17:01:08 +02:00
nala 0dc2d64b20 docs(iva): record Tempo visual completion of G3 QA 2026-10-24 16:58:34 +02:00
nala bda6d1e3a0 docs(iva): record G3 cessation code QA and explicit visual verification remainder 2026-10-24 16:54:23 +02:00
nala ac948bd8b7 feat(iva): implement G3 temporary benefit cessation and explicit treatment continuity 2026-10-24 16:51:52 +02:00
nala 908c8afc54 docs(iva): make G2L manual visual evidence and technical corroboration explicit 2026-10-24 16:44:26 +02:00
nala 643ba6ed72 docs(iva): record G2K G2L homologation delivery and preserved balance 2026-10-24 16:41:57 +02:00
nala ccdecbd8d7 docs(iva): verify G2K G2L joint delivery backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 16:39:06 +02:00
nala da798dd1d8 docs(iva): complete G2L QA with Tempo review and actual saved payload evidence 2026-10-24 16:36:58 +02:00
nala 0304612093 docs(iva): record partial Tempo review and clarify QA save recovery controls 2026-10-24 16:33:05 +02:00
nala d76078a81f docs(iva): accept Tempo manual verification route without claiming G2L closure 2026-10-24 16:24:02 +02:00
nala c4cc7d83e7 docs(iva): record G2L code QA and explicit pending visual access gate 2026-10-24 16:20:31 +02:00
nala 744682835a feat(iva): implement G2L Annex I and explicit continuity pending visual QA 2026-10-24 16:19:52 +02:00
nala 1fe742561f docs(iva): record G2K P008 QA candidate and preserved balance 2026-10-24 16:06:48 +02:00
nala 8882dc54d0 feat(iva): implement G2K pharmaceutical manufacturing inputs in QA 2026-10-24 16:05:55 +02:00
nala eb9e0dbc60 docs(iva): record G2I G2J homologation delivery and calendar resolution 2026-10-24 15:52:45 +02:00
nala e45a1394fa docs(iva): verify G2I G2J joint delivery backup and calendar evidence
tests / ci (push) Canceled after 0s
2026-10-24 15:49:08 +02:00
nala 72f4187d3b feat(iva): add fundraising group and correct production option calendar in QA 2026-10-24 15:47:02 +02:00
nala a5ac8ca1c9 docs(iva): record G2I QA candidate and explicit calendar limit 2026-10-24 15:31:29 +02:00
nala fe69a16eea feat(iva): add own-production exemptions and dated tax options in QA 2026-10-24 15:31:27 +02:00
nala 7696af6814 docs(iva): record G2G G2H homologation delivery and preserved balance 2026-10-24 15:15:49 +02:00
nala d4eae917ee docs(iva): verify G2G G2H joint delivery backup and compatibility
tests / ci (push) Canceled after 0s
2026-10-24 15:13:32 +02:00
nala b297058d11 docs(iva): record G2H QA candidate and one-branch coverage 2026-10-24 15:12:30 +02:00
nala 48146089cd feat(iva): add eighteen enumerated products within P026 in QA 2026-10-24 15:12:14 +02:00
nala 2440cb448a docs(iva): record G2G QA candidate and four-branch balance 2026-10-24 15:06:45 +02:00
nala 9dbfdd67ad feat(iva): add conditional public official and asset-sale operations in QA 2026-10-24 15:06:43 +02:00
nala b1928b61e5 docs(iva): clarify delivered G2F IDs and evidence paths 2026-10-24 15:03:42 +02:00
nala 541ea70484 docs(iva): record G2E G2F homologation delivery and preservation 2026-10-24 15:01:45 +02:00
nala 9a56d98242 docs(iva): verify G2E G2F destination backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 14:59:24 +02:00
nala 38b49bd5fa docs(iva): prepare G2E G2F joint delivery and authenticated preflight 2026-10-24 14:57:53 +02:00
nala 9b0f437073 docs(iva): record G2F candidate and seven QA branches 2026-10-24 14:57:23 +02:00
nala 8171c7992e feat(iva): add games stamped values and passenger transport in QA 2026-10-24 14:57:22 +02:00
nala 30760cab9b docs(iva): record G2E QA candidate and preserved balance 2026-10-24 14:53:24 +02:00
nala 33d18b9efc feat(iva): add conditional agropecuary operations in QA 2026-10-24 14:53:23 +02:00
nala 0aac0d1555 docs(iva): record G2C G2D homologation delivery and preservation 2026-10-24 14:49:27 +02:00
nala 3b788ec009 docs(iva): record G2C G2D backup and activation scope
tests / ci (push) Canceled after 0s
2026-10-24 14:46:36 +02:00
nala db4ff64e87 docs(iva): prepare verified G2C G2D joint Git delivery 2026-10-24 14:46:24 +02:00
nala c28e290b42 docs(iva): record G2D candidate and joint QA balance 2026-10-24 14:42:43 +02:00
nala 8d127799cd feat(iva): add author rights and eligible publications in QA 2026-10-24 14:42:38 +02:00
nala d32ad1e0a6 docs(iva): record G2C QA candidate and preserved delivery balance 2026-10-24 14:39:04 +02:00
nala 122f4f04b9 feat(iva): add conditional cultural and membership operations in QA 2026-10-24 14:38:55 +02:00
nala dacda11c07 Record joint L1 homologation delivery 490527b9 and verified preservation 2026-10-24 14:32:35 +02:00
nala 490527b92c Record joint L1 QA candidate, verified Git bundle and integration preview
tests / ci (push) Canceled after 0s
2026-10-24 14:22:15 +02:00
nala 4a35d63cd3 Complete G2B social QA and prepare joint L1 delivery with compatible rollback 2026-10-24 14:21:21 +02:00
nala 0e644b5524 Record G2A QA candidate and reconciled L1 closure counts 2026-10-24 14:04:45 +02:00
nala 675cf38f67 Implement G2A health exemptions in QA and reconcile L1 branch inventory 2026-10-24 14:04:18 +02:00
nala 89ab288334 Record L1 grouped QA candidate and verified final export evidence 2026-10-24 13:54:42 +02:00
nala 5030116ee5 Group L1 coverage and implement documented service exemptions in QA 2026-10-24 13:54:32 +02:00
nala 8719e916ea docs: record rational VAT QA candidate and open form dependency 2026-10-24 13:20:52 +02:00
nala 689e7cbe8b feat: preserve exact included VAT fractions and enumerate L1 remainder 2026-10-24 13:20:32 +02:00
nala d89912e579 docs: record IVA L1 QA candidate and explicit remaining scope 2026-10-24 13:00:26 +02:00
nala 544068e8cc feat: demonstrate scoped IVA operations L1 in QA 2026-10-24 12:59:37 +02:00
nala e8c39a1b54 docs: receipt for installed Modelo A acquisitions and totals 2026-10-24 12:19:34 +02:00
nala 1655f57e69 docs: register Modelo A acquisitions QA candidate and evidence
tests / ci (push) Canceled after 0s
2026-10-24 12:14:21 +02:00
nala d18ff0f049 feat: implement opportunity-scoped Modelo A acquisitions in QA 2026-10-24 12:13:57 +02:00
nala 355656b5c8 docs: receipt for installed simulator S1-S3 closure in homologation 2026-10-24 11:41:57 +02:00
nala cd10cccbf4 docs: close S3 monthly PDF review and mark simulator candidate ready for integration
tests / ci (push) Canceled after 0s
2026-10-24 11:37:09 +02:00
nala d044ef1efc docs: record S1 and S2 QA results and directed S3 file checks 2026-10-24 11:30:59 +02:00
nala 65b87819a0 fix: preserve cashflow currency and recover admitted monthly IVA executions in QA 2026-10-24 11:29:15 +02:00
nala be62783b98 docs: delimit simulator closure to two code gaps and monthly export proof 2026-10-24 11:16:42 +02:00
nala 98fc16a3fb docs: record installed stabilization reference and finite remaining scope 2026-10-24 11:10:51 +02:00
nala 276d833a4b test: consolidate stabilization reference and preserve accepted contour scope
tests / ci (push) Canceled after 0s
2026-10-24 11:08:35 +02:00
nala 5d45541a11 docs: receipt for installed shared map stabilization and accepted public contours 2026-10-24 10:51:31 +02:00
nala 066707ece6 fix: restore shared map access and publish accepted administrative boundary projection
tests / ci (push) Canceled after 0s
2026-10-24 10:47:13 +02:00
nala c1f4a71963 docs: record installed anchor integration and exact territorial recovery 2026-10-23 19:26:07 +02:00
nala cf2ddf21a1 fix: verify territorial recovery manifest with canonical Git line endings
tests / ci (push) Canceled after 0s
2026-10-23 19:20:25 +02:00
nala 3fd5128c62 fix: connect documentary anchors to investment preparation and recover accepted territories
tests / ci (push) Canceled after 0s
2026-10-23 19:17:15 +02:00
nala cdf8fcfba4 docs: record installed treatment scope and verified native PDF 2026-10-23 18:50:13 +02:00
nala 8036b9b071 docs: verify saved native PDF and release delivery condition
tests / ci (push) Canceled after 0s
2026-10-23 18:44:09 +02:00
nala 6985f82e9c docs: delimit anchor findings and pending native PDF delivery gate 2026-10-23 18:36:08 +02:00
nala 2856240cf4 fix: print selected requirements and translated opportunity stage states 2026-10-23 18:34:39 +02:00
nala 32144aa2f3 docs: record treatment scope QA and anchor search analysis boundary 2026-10-23 18:26:00 +02:00
nala 1afdfee8c0 fix: share selected opportunity across simulator stages and land shortcuts 2026-10-23 18:25:09 +02:00
nala bc84fbdb3e docs: delimit remaining transversal investment scope 2026-10-23 18:06:42 +02:00
nala b6a626c92d Record installed opportunity-consumer delta in homologation 2026-10-23 17:58:15 +02:00
nala 55136b446d Record directed QA proof for all four opportunity consumers
tests / ci (push) Canceled after 0s
2026-10-23 17:51:45 +02:00
nala 4a01e9e2b7 Scope parks and downstream investment requests to the treated opportunity 2026-10-23 17:49:22 +02:00
nala ad4160f040 Record second-opportunity context assessment and bounded consumer gaps 2026-10-23 17:18:55 +02:00
nala af9261809c Record installed complements delta and preserved acceptance 2026-10-23 17:14:04 +02:00
nala d8224ba84b Align public simulator entry check with integrated home layout
tests / ci (push) Canceled after 0s
2026-10-23 17:11:15 +02:00
nala 088f2c2cf4 Merge remote-tracking branch 'origin/main' into codex/investment-complements-20261023
tests / ci (push) Canceled after 0s
2026-10-23 16:35:03 +02:00
nala 603a88e1d3 Link documented investment complements to existing fiches and dossier context 2026-10-23 16:34:57 +02:00
paulomassigue 43cd0be7cb correcao de conflitos
tests / ci (push) Canceled after 0s
2026-10-23 16:03:34 +02:00
paulomassigue 89a9c3d994 mudanca o botao Tempo no hear fica Mais 2026-10-23 15:58:59 +02:00
paulomassigue d242482042 home ajustado 2026-10-23 15:46:53 +02:00
paulomassigue ec4b2f2af2 organizacao da tela inicial 2026-10-23 14:51:34 +02:00
paulomassigue e2b0fb4b2d melhorias de home 1 2026-10-23 10:36:34 +02:00
249 changed files with 28490 additions and 863 deletions
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers;
use App\Services\InvestmentComplements;
use Illuminate\Http\Request;
final class InvestmentComplementController extends Controller
{
public function index(Request $request, InvestmentComplements $service)
{
$data = $request->validate(['origin' => [\Illuminate\Validation\Rule::requiredIf(!$request->has('contexts')), 'nullable', 'string', 'max:100'], 'territory_id' => 'nullable|uuid',
'contexts' => 'sometimes|array|max:100', 'contexts.*' => 'array:origin,territory_id', 'contexts.*.origin' => 'required|string|max:100', 'contexts.*.territory_id' => 'nullable|uuid']);
$items = [];
$issues = [];
foreach ($data['contexts'] ?? [['origin' => $data['origin'], 'territory_id' => $data['territory_id'] ?? null]] as $context) {
try {
$items = [...$items, ...$service->options($context['origin'], $context['territory_id'] ?? null)];
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException|\Symfony\Component\HttpKernel\Exception\HttpException $e) {
$status = $e instanceof \Symfony\Component\HttpKernel\Exception\HttpException ? $e->getStatusCode() : 404;
if (!isset($data['contexts']) || $status !== 404) throw $e;
$issues[] = ['origin' => $context['origin'], 'message' => 'Uma referência escolhida deixou de estar disponível para consulta pública. A relação guardada conserva-se no dossier; os outros complementos continuam disponíveis.'];
}
}
return response()->json(isset($data['contexts']) ? ['items' => $items, 'issues' => $issues] : $items)->header('Cache-Control', 'private, no-store');
}
}
@@ -107,7 +107,7 @@ class InvestmentDiscoveryController extends Controller
$returnFilters = $request->query();
unset($returnFilters['zone_id'], $returnFilters['from_dossier']);
return Inertia::render('investment/detail', ['record' => $record, 'context' => $catalogue->context($record->id), 'zone_origin' => $origin,
return Inertia::render('investment/detail', ['complements' => app(\App\Services\InvestmentComplements::class)->options('opportunity:'.$record->id), 'record' => $record, 'context' => $catalogue->context($record->id), 'zone_origin' => $origin,
'guides' => app(\App\Services\SectorInvestment::class)->guides($record->sector),
'dossierOrigin' => $dossierOrigin ? ['id' => $dossierOrigin->id, 'title' => $dossierOrigin->title] : null,
'returnUrl' => $returnFilters === [] ? '/oportunidades' : '/oportunidades?'.http_build_query($returnFilters)]);
@@ -61,8 +61,15 @@ class InvestmentPortfolioController extends Controller
{
$management = $request->routeIs('management.portfolio*');
$filters = $request->validate(['q' => ['nullable', 'string', 'max:120'], 'kind' => ['nullable', 'in:corridor,cluster,project'],
'sector' => ['nullable', 'string', 'max:500'],
'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid']]);
$query = $management ? InvestmentDossier::query() : self::visible();
$sectorOptions = ($management ? InvestmentDossier::query() : self::visible())
->whereNotNull('content->sector')->get()->pluck('content.sector')
->filter(fn ($sector) => is_string($sector) && trim($sector) !== '')->unique()->sort()->values();
if (! empty($filters['sector'])) {
$query->where('content->sector', $filters['sector']);
}
if (! empty($filters['kind'])) {
$query->whereNotNull($filters['kind'].'_id');
}
@@ -76,7 +83,7 @@ class InvestmentPortfolioController extends Controller
}
return Inertia::render('portfolio/index', ['records' => $query->orderBy('title')->paginate(30)->withQueryString(),
'management' => $management, 'filters' => $filters, 'territorySelection' => $territorySelection]);
'management' => $management, 'filters' => $filters, 'sectors' => $sectorOptions, 'territorySelection' => $territorySelection]);
}
public function show(Request $request, string $id): Response
@@ -131,12 +138,19 @@ class InvestmentPortfolioController extends Controller
->orderByDesc('updated_at')->limit(10)->get(['id', 'version', 'updated_at'])
: collect();
return Inertia::render('portfolio/show', ['record' => $record, 'related' => $related, 'management' => $management, 'zones' => $zones,
return Inertia::render('portfolio/show', ['complements' => $management ? [] : app(\App\Services\InvestmentComplements::class)->options('portfolio:'.$record->id), 'record' => $record, 'related' => $related, 'management' => $management, 'zones' => $zones,
'anchorProject' => $anchorProject, 'existingSubmissions' => $existingSubmissions,
'geography' => app(InvestmentRelations::class)->dossier($record, $management),
'origin' => $origin ? ['id' => $origin->id, 'title' => $origin->title] : null, 'opportunities' => $opportunities, 'chains' => $chains]);
}
public function resumeInterest(Request $request, string $id): RedirectResponse
{
self::visible()->findOrFail($id);
$data = $request->validate(['catalogue_query' => ['nullable', 'string', 'max:4000']]);
return redirect('/carteira/'.$id.'?'.http_build_query([...$data, 'prepare_interest' => '1']));
}
public function save(Request $request, InvestmentDossier $dossier): RedirectResponse
{
$data = $request->validate(['version_no' => ['required', 'integer', 'min:1'], 'title' => ['required', 'string', 'max:255'], 'source' => ['required', 'string', 'max:2000'],
@@ -192,11 +192,13 @@ class InvestmentSubmissionController extends Controller
{
$required = $submitting ? 'required' : 'nullable';
$data = $request->validate(['version' => ['required', 'integer', 'min:1'],
'payload' => ['required', 'array:context_reuse,full_name,email,phone,country,residence_country_code,incorporation_country_code,organization_country_snapshot,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload' => ['required', 'array:context_opportunity,context_opportunity_snapshot,context_reuse,full_name,email,phone,country,residence_country_code,incorporation_country_code,organization_country_snapshot,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload.organization_country_snapshot' => ['sometimes', 'array', 'max:10'],
'payload.residence_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.incorporation_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.declared_origin_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.other_details' => ['nullable', 'string', 'max:5000'],
'payload.full_name' => [$required, 'string', ...($submitting ? ['min:3'] : []), 'max:150'], 'payload.email' => [$required, $submitting ? 'email:rfc' : 'string', 'max:150'],
@@ -247,6 +249,9 @@ class InvestmentSubmissionController extends Controller
}
}
$bound = DB::table('desk_cases')->where('submission_id', $request->route('id'))->where('user_id', $request->user()->id)->whereNotNull('journey_id')->first();
if ($bound) $data['payload'] = app(\App\Services\InvestmentConsumerScope::class)->bind($request->user(), $bound->id, $data['payload'], $submitting);
else unset($data['payload']['context_opportunity'], $data['payload']['context_opportunity_snapshot']);
return $data;
}
@@ -266,7 +271,7 @@ class InvestmentSubmissionController extends Controller
$version = DB::transaction(function () use ($request, $id, $data) {
$row = $this->owned($request, $id, true, true);
abort_unless($row->status === 'draft' && $row->version === (int) $data['version'], 409, 'Rascunho alterado. Recarregue antes de guardar.');
$row->update(['payload' => $this->preserveCountrySource($row, $data['payload']), 'version' => $row->version + 1]);
$row->update([...(isset($data['payload']['context_opportunity']) ? ['opportunity_id'=>(int)substr($data['payload']['context_opportunity'],12)] : []), 'payload' => $this->preserveCountrySource($row, $data['payload']), 'version' => $row->version + 1]);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
foreach ($data['needs'] ?? [] as $need) {
InvestmentSpecificNeed::create([...$need, 'submission_id' => $id]);
@@ -310,7 +315,8 @@ class InvestmentSubmissionController extends Controller
return InterestRequest::findOrFail($row->interest_request_id)->reference;
}
abort_unless($row->version === (int) $data['version'], 409, 'Rascunho alterado. Recarregue.');
$opportunity = $row->opportunity_id ? Opportunity::published()->findOrFail($row->opportunity_id) : null;
$scopeKey = $data['payload']['context_opportunity'] ?? null;
$opportunity = $scopeKey ? Opportunity::published()->findOrFail(substr($scopeKey,12)) : ($row->opportunity_id ? Opportunity::published()->findOrFail($row->opportunity_id) : null);
if ($row->dossier_id) {
InvestmentPortfolioController::visible()->findOrFail($row->dossier_id);
}
@@ -331,12 +337,14 @@ class InvestmentSubmissionController extends Controller
'sector_interest' => $p['sector'], 'message' => $p['objective'], 'privacy_consent' => true, 'consented_at' => now(),
'status' => 'received', 'source_page' => '/investidor/manifestacoes/'.$id,
'metadata' => ['submission_id' => $id, 'portal_user_id' => $request->user()->id, 'dossier_id' => $row->dossier_id,
'context_opportunity' => $p['context_opportunity'] ?? null,
'context_opportunity_snapshot' => $p['context_opportunity_snapshot'] ?? null,
'declared_origin_country_code' => $p['declared_origin_country_code'] ?? null,
'residence_country_code' => $p['residence_country_code'] ?? null,
'incorporation_country_code' => $p['incorporation_country_code'] ?? null,
...(isset($p['organization_country_snapshot']) ? ['organization_country_snapshot' => $p['organization_country_snapshot']] : []),
...($zoneOrigin ? ['zone_origin' => (array) $zoneOrigin] : [])]]));
$row->update(['payload' => $p, 'version' => $row->version + 1, 'interest_request_id' => $interest->id, 'status' => 'submitted']);
$row->update(['opportunity_id'=>$opportunity?->id, 'payload' => $p, 'version' => $row->version + 1, 'interest_request_id' => $interest->id, 'status' => 'submitted']);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
foreach ($data['needs'] ?? [] as $need) {
InvestmentSpecificNeed::create([...$need, 'submission_id' => $id]);
@@ -19,12 +19,21 @@ class InvestmentTerritoryController extends Controller
$data = $request->validate(['territory_id' => ['required', 'uuid']]);
$profile = $request->is('minhas-oportunidades/*');
$management = $request->is('management/*') || $profile;
$actor = $request->user();
$access = app(PortalProfileAccess::class);
// The general consumers use this same endpoint while authenticated.
// Reuse the read access already granted by the private cadastral routes.
$profileAccess = $actor && $actor->hasVerifiedEmail()
&& ($access->grants($actor) !== [] || $access->superuser($actor));
$internal = $profileAccess || ($actor?->hasVerifiedEmail() && $actor->can('manage-portal'));
if ($management) {
$access = app(PortalProfileAccess::class);
abort_unless($profile ? ($access->grants($request->user()) !== [] || $access->superuser($request->user())) : $request->user()?->can('manage-portal'), 403);
abort_unless($profile ? $profileAccess : $internal, 403);
}
return response()->json(app(TerritoryGeometry::class)->context($data['territory_id'], $management));
return response()->json([
...app(TerritoryGeometry::class)->context($data['territory_id'], $internal),
'geometry_scope' => $internal ? 'authorized_internal' : 'public',
])->header('Cache-Control', 'private, no-store');
}
private const TABLES = ['opportunities' => 'opportunities', 'projects' => 'projects', 'clusters' => 'economic_clusters', 'corridors' => 'development_corridors', 'zones' => 'investment_zones'];
@@ -11,6 +11,15 @@ use Inertia\Inertia;
final class InvestorContextController extends Controller
{
private function entryComplements(Request $request): array
{
$data = $request->validate(['complement_origin' => 'nullable|string|max:100', 'complement_code' => 'required_with:complement_origin|string|max:40',
'complement_target' => 'nullable|string|max:100', 'complement_territory' => 'nullable|uuid']);
if (empty($data['complement_origin'])) return [];
return app(\App\Services\InvestmentComplements::class)->resolve([['origin' => $data['complement_origin'], 'code' => $data['complement_code'],
'target' => $data['complement_target'] ?? null, 'territory_id' => $data['complement_territory'] ?? null]]);
}
private function entryChoices(Request $r, InvestorContext $context): array
{
$data = $r->validate(['source' => 'nullable|string|max:100', 'from_dossier' => 'nullable|uuid', 'opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1',
@@ -21,6 +30,14 @@ final class InvestorContextController extends Controller
$path = app(InvestmentGeography::class)->selection($data);
$input = array_map(fn($id) => ['source' => 'opportunity:'.$id, ...($path ? ['territory' => 'territory:'.$path[array_key_last($path)]->id] : [])], $ids);
if (!empty($data['from_dossier'])) $input[0]['portfolio_origins'] = [$data['from_dossier']];
foreach ($this->entryComplements($r) as $complement) {
$keys = array_filter([$complement['origin']['key'], $complement['target']['key'] ?? null], fn($key) => str_starts_with($key, 'opportunity:'));
foreach ($keys as $key) {
if (in_array($key, array_column($input, 'source'), true)) continue;
$input[] = ['source' => $key, ...($complement['territory_id'] ? ['territory' => 'territory:'.$complement['territory_id']] : []),
...(str_starts_with($complement['origin']['key'], 'portfolio:') ? ['portfolio_origins' => [substr($complement['origin']['key'], 10)]] : [])];
}
}
return app(\App\Services\InvestmentOpportunityChoices::class)->resolve($input, [], true);
}
@@ -36,7 +53,8 @@ final class InvestorContextController extends Controller
public function show(Request $r, string $id, InvestorContext $context)
{
return response()->json($context->view($r->user(), $id));
$data = $r->validate(['opportunity' => 'nullable|string|max:100']);
return response()->json($context->view($r->user(), $id, $data['opportunity'] ?? null));
}
public function options(Request $r, InvestorContext $context)
@@ -84,7 +102,18 @@ final class InvestorContextController extends Controller
$kept = collect($choices ?? [])->firstWhere('opportunity.key', $entry['opportunity']['key']);
if ($kept && ($kept['territory']['key'] ?? null) !== ($entry['territory']['key'] ?? null)) $differences[] = ['title'=>$entry['opportunity']['title'],'saved'=>$kept['territory']['title']??'Por definir','requested'=>$entry['territory']['title']??'Por definir'];
}
return Inertia::render('investor-path/context', ['entryLocationDifferences'=>$differences,'entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
$complements = isset($draft['complements']) ? app(\App\Services\InvestmentComplements::class)->resolve($draft['complements'], $data['context']['complements'] ?? []) : ($data['context']['complements'] ?? []);
$entryTerritory = null;
if (($source['kind'] ?? null) === 'portfolio') {
$path = app(InvestmentGeography::class)->selection($r->validate(['province_id' => 'nullable|uuid', 'district_id' => 'nullable|uuid', 'admin_post_id' => 'nullable|uuid', 'locality_id' => 'nullable|uuid']));
if ($path) $entryTerritory = $context->reference('territory:'.$path[array_key_last($path)]->id);
}
foreach ($this->entryComplements($r) as $entry) {
$tag = 'complement:'.hash('sha256', $entry['key'].'@'.($selectionKey ?? ''));
$entrySources[] = $tag;
if (!in_array($tag, $draft['entry_sources'] ?? [], true)) $complements = collect([...$complements, $entry])->unique('key')->values()->all();
}
return Inertia::render('investor-path/context', ['entryTerritory' => $entryTerritory, 'entryComplements' => $complements, 'entryLocationDifferences'=>$differences,'entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : ($entryTerritory ? app(InvestmentGeography::class)->path($entryTerritory['id']) : [])]);
}
public function preview(Request $r, string $id, InvestorContext $context)
@@ -101,9 +130,16 @@ final class InvestorContextController extends Controller
{
$d = $r->validate(['source' => 'nullable|string|max:100', 'step' => ['nullable', 'regex:/^S(0[1-9]|1[0-9])$/']]);
$ref = isset($d['source']) ? $context->reference($d['source']) : null;
$submissionId = $r->validate(['submission' => 'nullable|uuid'])['submission'] ?? null;
$entrySubmission = null;
if ($submissionId) {
$submission = \App\Models\InvestmentSubmission::where('id', $submissionId)->where('user_id', $r->user()->id)->where('status', 'draft')->firstOrFail();
abort_unless(($ref['kind'] ?? null) === 'portfolio' && $submission->dossier_id === $ref['id'], 422, 'Conserve a ficha de origem da manifestação.');
$entrySubmission = ['id' => $submission->id, 'version' => $submission->version];
}
$choices = $this->entryChoices($r, $context);
return Inertia::render('investor-path/context-start', ['entryQuery' => $r->only(['from_dossier', 'province_id', 'district_id', 'admin_post_id', 'locality_id']), 'opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
return Inertia::render('investor-path/context-start', ['entrySubmission' => $entrySubmission, 'entryComplements' => $this->entryComplements($r), 'entryQuery' => $r->only(['complement_origin', 'complement_code', 'complement_target', 'complement_territory', 'from_dossier', 'province_id', 'district_id', 'admin_post_id', 'locality_id']), 'opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
}
public function installation(Request $r, InvestorContextInstallation $install)
@@ -88,7 +88,8 @@ class InvestorPathController extends Controller
public function show(Request $request, string $id, InvestorPath $path): JsonResponse|Response
{
$data = $path->view($request->user(), $id);
$choice = $request->validate(['opportunity' => 'nullable|string|max:100'])['opportunity'] ?? null;
$data = $path->view($request->user(), $id, $choice);
return $request->expectsJson() ? response()->json($data) : Inertia::render('investor-path/show', $data);
}
@@ -119,8 +119,8 @@ class VirtualDeskController extends Controller
public function createRequest(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
$data = $request->validate(['service_version_id' => 'required|uuid', 'client_key' => 'required|uuid']);
$row = $desk->createRequest($request->user(), $id, $data['service_version_id'], $data['client_key']);
$data = $request->validate(['service_version_id' => 'required|uuid', 'client_key' => 'required|uuid', 'opportunity' => 'nullable|string|max:100']);
$row = $desk->createRequest($request->user(), $id, $data['service_version_id'], $data['client_key'], $data['opportunity'] ?? null);
return $request->expectsJson() ? response()->json(['id' => $row->id, 'version' => $row->version], 201) : redirect('/balcao-virtual/pedidos/'.$row->id);
}
@@ -14,12 +14,13 @@ final class EnsureScopedPortalAdministration
public function handle(Request $request, Closure $next): Response
{
$actor = $request->user();
abort_unless($actor, 403);
abort_unless($actor !== null, 403);
$scope = app(ScopedPortalAdministration::class);
$path = $request->path();
$interests = $request->is('management/interests', 'management/interests/*', 'api/v1/investment/admin/interests/*');
// Fiscal maintenance reuses authorised administration; unrelated gates remain unchanged.
$catalogue = $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
$geometryRead = $request->isMethod('GET') && $path === 'management/territory-geometries';
$catalogue = $geometryRead || $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
'management/economic-references/lot-01', 'management/economic-references/lot-01/*',
'management/education', 'management/education/*', 'management/investment/references', 'management/investment/references/*', 'api/v1/investment/admin/references', 'api/v1/investment/admin/references/*',
'management/investment/zones', 'management/investment/zones/*', 'api/v2/investment/admin/zones', 'api/v2/investment/admin/zones/*',
@@ -19,7 +19,9 @@ class StoreLandAssistanceCaseRequest extends FormRequest
{
$payload = $this->validated('payload');
return is_array($payload) ? $payload : [];
if (!is_array($payload)) return [];
if (!empty($payload['investor_path_case_id'])) return app(\App\Services\InvestmentConsumerScope::class)->bind($this->user(), $payload['investor_path_case_id'], $payload, $this->routeIs('land-assistance.support'));
return \Illuminate\Support\Arr::except($payload, ['context_opportunity', 'context_opportunity_snapshot']);
}
public function authorize(): bool
@@ -33,7 +35,9 @@ class StoreLandAssistanceCaseRequest extends FormRequest
return [
'version' => [$this->isMethod('post') && ! $this->routeIs('land-assistance.support') ? 'nullable' : 'required', 'integer', 'min:1'],
'context_revision' => ['nullable', 'integer', 'min:0'], 'context_reviewed' => ['nullable', 'boolean'],
'payload' => ['required', 'array:context_reuse,support_kind,request_description,project_reference,investor_path_case_id,applicant_category,full_name,contact_person,email,phone,preferred_contact,country,declared_origin_country_code,nationality,representative_name,representative_role,representation_basis,nuit,constitution_or_residency_note,area_status,parcels,purpose,activity,known_occupants,occupant_description,known_improvements,improvements_description,prior_right_status,prior_right_description,conflict_status,conflict_description,official_process,attachments_to_follow,exploration_plan,consultation,additional_information,truth_declaration,contact_consent'],
'payload' => ['required', 'array:context_opportunity,context_opportunity_snapshot,context_reuse,support_kind,request_description,project_reference,investor_path_case_id,applicant_category,full_name,contact_person,email,phone,preferred_contact,country,declared_origin_country_code,nationality,representative_name,representative_role,representation_basis,nuit,constitution_or_residency_note,area_status,parcels,purpose,activity,known_occupants,occupant_description,known_improvements,improvements_description,prior_right_status,prior_right_description,conflict_status,conflict_description,official_process,attachments_to_follow,exploration_plan,consultation,additional_information,truth_declaration,contact_consent'],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.support_kind' => ['nullable', 'in:investment,home,family_exploitation,recognition,regularization,delimitation,change_of_use,transfer,existing_process,conflict_guidance,other'],
'payload.request_description' => ['nullable', 'string', 'max:4000'],
@@ -37,7 +37,7 @@ class StoreSimulationFormDraftRequest extends FormRequest
'contact_province', 'contact_district', 'preferred_channel',
];
$economic = [
'context_applicability_snapshot', 'investment_regime', 'context_reuse', 'compatible_fields_snapshot', 'published_iva_base', 'published_iva_currency', 'published_iva_date', 'published_iva_scope', 'monthly_iva_settings', 'monthly_iva_snapshot', 'journey_type', 'detail_level', 'business_plan_snapshot', 'financial_tools_snapshot', 'cashflow_snapshot', 'project_team_snapshot', 'project_execution_snapshot', 'purpose', 'manifestation_type', 'preferred_language', 'project_title', 'project_summary', 'project_problem', 'target_customers', 'value_proposition', 'market_assumption', 'market_source', 'project_milestones', 'selection_labels', 'project_type',
'context_opportunity', 'context_applicability_snapshot', 'investment_regime', 'context_reuse', 'compatible_fields_snapshot', 'published_iva_base', 'published_iva_currency', 'published_iva_date', 'published_iva_scope', 'monthly_iva_settings', 'monthly_iva_snapshot', 'modelo_a_snapshot', 'journey_type', 'detail_level', 'business_plan_snapshot', 'financial_tools_snapshot', 'cashflow_snapshot', 'project_team_snapshot', 'project_execution_snapshot', 'purpose', 'manifestation_type', 'preferred_language', 'project_title', 'project_summary', 'project_problem', 'target_customers', 'value_proposition', 'market_assumption', 'market_source', 'project_milestones', 'selection_labels', 'project_type',
'competitor_assumption', 'sales_channel_assumption', 'marketing_approach', 'location_rationale', 'project_risk_responses_snapshot', 'project_questionnaire_version',
'customer_validation_status', 'cost_estimate_status', 'location_assessment_status', 'funding_status', 'receivables_timing_status',
'project_type_other', 'sector_id', 'activity_id', 'products_services', 'maturity_stage', 'expected_start_date',
@@ -73,6 +73,7 @@ class StoreSimulationFormDraftRequest extends FormRequest
'economic_snapshot.financial_tools_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.cashflow_snapshot' => ['nullable', 'string', 'max:20000'],
'economic_snapshot.context_applicability_snapshot' => ['nullable', 'string', 'max:1000000'],
'economic_snapshot.context_opportunity' => ['nullable', 'string', 'max:100'],
'economic_snapshot.investment_regime' => ['nullable', 'in:general,industrial_park,zee,zfi'],
'economic_snapshot.context_reuse' => ['nullable', 'string', 'max:10000'],
'economic_snapshot.compatible_fields_snapshot' => ['nullable', 'string', 'max:10000'],
@@ -82,6 +83,7 @@ class StoreSimulationFormDraftRequest extends FormRequest
'economic_snapshot.published_iva_scope' => ['nullable', 'string', 'in:yes,no'],
'economic_snapshot.monthly_iva_settings' => ['nullable', 'string', 'max:2000'],
'economic_snapshot.monthly_iva_snapshot' => ['nullable', 'string', 'max:60000'],
'economic_snapshot.modelo_a_snapshot' => ['nullable', 'string', 'json', 'max:1000000'],
'economic_snapshot.project_team_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.project_execution_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.project_risk_responses_snapshot' => ['nullable', 'string', 'max:30000'],
@@ -0,0 +1,42 @@
<?php
namespace App\Services;
use RuntimeException;
/** Public read projection authorized by Tempo; source rows and originals stay private. */
class ApprovedAdministrativeBoundaries
{
public const HASH = '06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc';
/** @var array<string,array<string,string>>|null */
private ?array $items = null;
/** @return array<string,array<string,string>> */
public function snapshots(): array
{
if ($this->items !== null) {
return $this->items;
}
$contents = file_get_contents(base_path('docs/investmoz/unification/approved-administrative-boundaries-20261024.json'));
if ($contents === false || ! hash_equals(self::HASH, hash('sha256', str_replace("\r\n", "\n", $contents)))) {
throw new RuntimeException('Approved administrative boundary manifest changed.');
}
$manifest = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (count($manifest['items']) !== 408) {
throw new RuntimeException('Exact 408-boundary scope required.');
}
$this->items = array_column($manifest['items'], null, 'id');
return $this->items;
}
public function allows(string $id, string $territoryId, string $geometryHash, string $propertiesHash): bool
{
$item = $this->snapshots()[$id] ?? null;
return $item !== null && $item['territory_id'] === $territoryId
&& hash_equals($item['geometry_sha256'], $geometryHash)
&& hash_equals($item['properties_sha256'], $propertiesHash);
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use RuntimeException;
/** Exact replay of the 28 accepted links into the transported project identities. */
final class ApprovedAnchorTerritories
{
public const HASH = 'd2893d0a638d630435aca1890f79a8094dc58eb65bbdd65a470bb685fa075190';
/** @return array{manifest_sha256:string,projects:list<array<string,mixed>>,links:list<array<string,mixed>>} */
public function plan(): array
{
$file = base_path('docs/investmoz/unification/approved-anchor-territories-20261023.json');
$contents = is_file($file) ? file_get_contents($file) : false;
if ($contents !== false) {
$contents = str_replace("\r\n", "\n", $contents);
}
if ($contents === false || ! hash_equals(self::HASH, hash('sha256', $contents))) {
throw new RuntimeException('Reviewed territorial manifest changed.');
}
$manifest = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (count($manifest['items']) !== 28) {
throw new RuntimeException('Exact 28-link scope required.');
}
$projects = [];
$links = [];
foreach ($manifest['items'] as $item) {
$project = DB::table('projects')->where('id', $item['project_id'])->whereNull('deleted_at')->first();
$dossier = DB::table('investment_dossiers')->where('id', $item['dossier_id'])->whereNull('deleted_at')->first();
if (! $project || $project->code !== $item['code'] || ! $dossier || $dossier->project_id !== $project->id
|| ! hash_equals($item['content_sha256'], hash('sha256', $dossier->content))
|| ! hash_equals($item['source_sha256'], hash('sha256', $dossier->source))) {
throw new RuntimeException('Project identity or documentary source changed: '.$item['code']);
}
$original = $item['original_relation'];
$geo = DB::table('geo_locations')->where('id', $original['geo_location_id'])->whereNull('deleted_at')->first();
foreach (['location_type', 'source_code', 'parent_id', 'data_classification'] as $field) {
if (! $geo || $item['territory'][$field] !== $geo->$field) {
throw new RuntimeException('Territory identity changed: '.$original['geo_location_id']);
}
}
$metadata = $projects[$project->id]['after_metadata'] ?? json_decode($project->metadata, true, 512, JSON_THROW_ON_ERROR);
$key = $geo->id.':'.$original['role'];
$evidence = $item['evidence'];
// Preserve the original dossier id in evidence and explicitly map the destination.
$evidence['transported_dossier_id'] = $dossier->id;
if (isset($metadata['documented_location_sources'][$key]) && $metadata['documented_location_sources'][$key] != $evidence) {
throw new RuntimeException('Existing territorial evidence differs; no overwrite: '.$item['code']);
}
$projects[$project->id] ??= ['id' => $project->id, 'code' => $project->code, 'before_version' => (int) $project->version_no, 'before_metadata' => json_decode($project->metadata, true, 512, JSON_THROW_ON_ERROR)];
$metadata['documented_location_sources'][$key] = $evidence;
$projects[$project->id]['after_metadata'] = $metadata;
$existing = DB::table('project_locations')->where('project_id', $project->id)->where('geo_location_id', $geo->id)->where('role', $original['role'])->first();
if ($existing && ($existing->deleted_at || $existing->data_classification !== 'public')) {
throw new RuntimeException('Archived or restricted territorial relation must not be revived.');
}
$identity = DB::table('project_locations')->where('id', $original['id'])->first();
if ($identity && (! $existing || $identity->id !== $existing->id)) {
throw new RuntimeException('Historical relation identity is already occupied.');
}
$links[] = ['code' => $item['code'], 'already_present' => (bool) $existing, 'row' => [...$original, 'project_id' => $project->id]];
}
return ['manifest_sha256' => self::HASH, 'projects' => array_values($projects), 'links' => $links];
}
/** Caller supplies an authenticated, backed-up transaction; no source publication changes.
* @param array{manifest_sha256:string,projects:list<array<string,mixed>>,links:list<array<string,mixed>>} $plan
* @return array<string,int>
*/
public function apply(array $plan): array
{
if (DB::transactionLevel() < 1 || $this->plan() !== $plan) {
throw new RuntimeException('Reviewed transaction and unchanged preview required.');
}
$inserted = 0;
$updated = 0;
foreach ($plan['projects'] as $project) {
if ($project['before_metadata'] == $project['after_metadata']) {
continue;
}
$count = DB::table('projects')->where('id', $project['id'])->where('version_no', $project['before_version'])->update([
'metadata' => json_encode($project['after_metadata'], JSON_THROW_ON_ERROR), 'version_no' => $project['before_version'] + 1, 'updated_at' => now(),
]);
if ($count !== 1) {
throw new RuntimeException('Concurrent project change.');
}
DB::table('audit_events')->insert(['source_system' => 'approved-anchor-territories-recovery-v1', 'external_id' => self::HASH.':'.$project['id'], 'entity_type' => 'projects', 'entity_id' => $project['id'], 'action' => 'accepted_territories_restored',
'data_classification' => 'public', 'before_data' => json_encode(['version_no' => $project['before_version'], 'metadata' => $project['before_metadata']], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['version_no' => $project['before_version'] + 1, 'manifest_sha256' => self::HASH, 'metadata' => $project['after_metadata'], 'new_approval' => false], JSON_THROW_ON_ERROR)]);
$updated++;
}
foreach ($plan['links'] as $link) {
if ($link['already_present']) {
continue;
}
DB::table('project_locations')->insert($link['row']);
$inserted++;
}
return ['relations_restored' => $inserted, 'projects_updated' => $updated, 'new_dossiers' => 0, 'publication_changes' => 0];
}
}
+157
View File
@@ -0,0 +1,157 @@
<?php
namespace App\Services;
use App\Http\Controllers\InvestmentPortfolioController;
use App\Models\Opportunity;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
/** Resolve documented complements without creating opportunities or master relations. */
final class InvestmentComplements
{
private const TERMS = [
'irrigation' => ['Regadio', 'regadio|irrigação|irrigacao'],
'storage' => ['Silos e armazenagem', 'silos?|armazenagem|armazenamento'],
'cold' => ['Cadeia de frio', 'frio|refrigeração'],
'processing' => ['Processamento', 'processamento|transformação|moagem'],
'spinning' => ['Fiação', 'fiação|fiacao'],
'logistics' => ['Logística', 'logística|logistica|transporte'],
'certification' => ['Certificação', 'certificação|certificacao'],
'training' => ['Formação', 'formação|formacao'],
'finance' => ['Financiamento', 'financiamento|serviços financeiros'],
];
public function options(string $origin, ?string $territory = null): array
{
[$originKind, $originId] = array_pad(explode(':', $origin, 2), 2, '');
abort_unless(($originKind === 'portfolio' && Str::isUuid($originId)) || ($originKind === 'opportunity' && ctype_digit($originId)), 422, 'Origem complementar inválida.');
$principal = null;
$relationEvidence = [];
if (str_starts_with($origin, 'portfolio:')) {
$record = InvestmentPortfolioController::visible()->addSelect('version_no')->findOrFail(substr($origin, 10));
$text = trim(($record->content['focus'] ?? '')."\n".($record->content['gaps'] ?? '')."\n".($record->content['description'] ?? ''));
$reference = ['key' => $origin, 'title' => $record->title, 'href' => '/carteira/'.$record->id, 'version' => $record->version_no];
$ids = app(CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($record);
foreach (['projects' => 'project_id', 'clusters' => 'cluster_id', 'corridors' => 'corridor_id'] as $relation => $foreign) {
if ($record->$foreign) $ids = [...$ids, ...DB::table('opportunity_'.$relation)->where($foreign, $record->$foreign)->pluck('opportunity_id')->all()];
}
$basis = $record->source;
foreach (array_unique($ids) as $id) $relationEvidence[$id] = ['type' => 'portfolio', 'origin' => $origin, 'source' => $basis];
$serviceOrigins = [['dossier', $record->id]];
foreach (['project_id' => 'project', 'cluster_id' => 'cluster'] as $foreign => $type) {
if ($record->$foreign) $serviceOrigins[] = [$type, $record->$foreign];
}
} else {
$reference = app(InvestorContext::class)->reference($origin);
abort_unless($reference['kind'] === 'opportunity', 422);
$principal = Opportunity::published()->findOrFail($reference['id']);
$text = $principal->summary;
$basis = 'Resumo cadastrado da oportunidade '.$principal->reference;
$projects = DB::table('opportunity_projects')->where('opportunity_id', $principal->id)->pluck('project_id');
$links = DB::table('complementary_project_links')->whereIn('anchor_project_id', $projects)
->whereNull('deleted_at')->where('data_classification', 'public')->get(['id', 'anchor_project_id', 'complementary_project_id', 'relation_type', 'version_no']);
$targetProjects = DB::table('opportunity_projects')->whereIn('project_id', $links->pluck('complementary_project_id'))->get();
$ids = [$principal->id, ...$targetProjects->pluck('opportunity_id')->all()];
$relationEvidence[$principal->id] = ['type' => 'same_fiche', 'source' => $basis];
foreach ($targetProjects as $targetProject) $relationEvidence[$targetProject->opportunity_id] = ['type' => 'complementary_project',
'links' => $links->where('complementary_project_id', $targetProject->project_id)->values()->map(fn($link) => (array)$link)->all()];
foreach (Opportunity::published()->whereIn('id', $ids)->where('id', '!=', $principal->id)->get() as $linked) $text .= "\n".$linked->summary;
if (count($ids) > 1) $basis .= '; relações complementares públicas entre projectos';
$serviceOrigins = [['investment', (string) $principal->id]];
$classification = app(OpportunityClassification::class);
$principalChains = collect($classification->publicRows($principal))->where('target_type', 'chain')->filter(fn($r) => !empty($r['source_reference']));
$chains = $principalChains->pluck('target_id')->all();
if ($chains) {
Opportunity::published()->whereNot('id', $principal->id)->chunkById(100, function ($records) use (&$ids, &$relationEvidence, $chains, $principalChains, $classification) {
foreach ($records as $candidate) {
$related = collect($classification->publicRows($candidate))->where('target_type', 'chain')->filter(fn($r) => !empty($r['source_reference']));
$shared = array_intersect($chains, $related->pluck('target_id')->all());
if ($shared) {
$ids[] = $candidate->id;
$relationEvidence[$candidate->id] ??= ['type' => 'value_chain', 'principal' => $principalChains->whereIn('target_id', $shared)->values()->all(), 'target' => $related->whereIn('target_id', $shared)->values()->all()];
}
}
});
}
}
$territoryReference = $territory ? app(InvestorContext::class)->reference('territory:'.$territory) : null;
$candidates = Opportunity::published()->whereIn('id', array_unique($ids))->get();
$items = [];
foreach (self::TERMS as $code => [$label, $pattern]) {
if (!preg_match('/\b(?:'.$pattern.')\b/iu', $text, $match)) continue;
$offers = [];
foreach ($candidates as $candidate) {
// A common corridor alone does not prove the component. Keep the supporting excerpt.
if (!preg_match('/\b(?:'.$pattern.')\b/iu', $candidate->title."\n".$candidate->summary, $evidence)) continue;
// Mentioning a need for funding/training in a project's summary is not an offer.
if (in_array($code, ['certification', 'training', 'finance'], true) && !preg_match('/\b(?:'.$pattern.')\b/iu', $candidate->title)) continue;
if (in_array($code, ['certification', 'training', 'finance'], true) && preg_match('/\b(?:necessidade|pedido|procura)\b/iu', $candidate->title)) continue;
if ($territory && $candidate->primary_territory_id && !$this->compatible($territory, $candidate->primary_territory_id)) continue;
$offers[] = ['key' => 'opportunity:'.$candidate->id, 'title' => $candidate->title, 'href' => '/oportunidades/'.$candidate->slug,
'relationship' => $relationEvidence[$candidate->id] ?? null,
'version' => $candidate->management_version, 'evidence' => $evidence[0], 'location' => ($principal && $principal->id === $candidate->id ? 'Componente referido na própria ficha. ' : '').($candidate->primary_territory_id ? app(InvestorContext::class)->reference('territory:'.$candidate->primary_territory_id)['title'] : 'Implantação por definir')];
}
// Services are concrete published offerings explicitly associated with this source.
$services = [];
if (in_array($code, ['certification', 'training', 'finance'], true) && Schema::hasTable('partnership_origins') && Schema::hasTable('partnership_interests')) {
if ($serviceOrigins) {
$services = DB::table('portal_partnerships as p')->join('partnership_origins as o', 'o.partnership_id', '=', 'p.id')
->where(function ($q) use ($serviceOrigins) {
foreach ($serviceOrigins as [$type, $id]) $q->orWhere(fn($q) => $q->where('o.type', $type)->where('o.target_id', $id));
})->where('p.status', 'published')->where('p.kind', 'offering')
->where('p.partnership_type', $code === 'finance' ? 'finance' : 'training')
->when($code !== 'finance', fn($q) => $q->where(fn($q) => $q->where('p.title', 'ilike', '%'.$match[0].'%')->orWhereRaw("p.payload->>'summary' ILIKE ?", ['%'.$match[0].'%'])))->distinct()->get(['p.id', 'p.title'])
->filter(function ($p) use ($territory) {
if (!$territory) return true;
$locations = DB::table('partnership_locations')->where('partnership_id', $p->id)->pluck('geo_location_id');
return $locations->isEmpty() || $locations->contains(fn($id) => $this->compatible($territory, $id));
})->map(fn ($p) => ['key' => 'partnership:'.$p->id, 'title' => $p->title, 'href' => '/parcerias/'.$p->id, 'location' => 'Consultar âmbito na oferta'])->values()->all();
}
}
$excerpt = collect(explode("\n", $text))->first(fn($line) => preg_match('/\b(?:'.$pattern.')\b/iu', $line));
$items[] = ['code' => $code, 'title' => $label, 'origin' => $reference, 'territory_id' => $territory, 'territory' => $territoryReference,
'source' => $basis, 'excerpt' => $excerpt, 'source_sha256' => hash('sha256', $text), 'opportunities' => $offers, 'services' => $services];
}
return $items;
}
private function compatible(string $a, string $b): bool
{
if ($a === $b) return true;
$geo = app(InvestmentGeography::class);
return in_array($b, $geo->descendants($a), true) || in_array($a, $geo->descendants($b), true);
}
public function resolve(array $input, array $previous = []): array
{
$resolved = [];
foreach ($input as $choice) {
$target = $choice['target'] ?? null;
$old = collect($previous)->first(fn($r) => $r['origin']['key'] === $choice['origin'] && $r['code'] === $choice['code'] && ($r['target']['key'] ?? null) === $target && ($r['territory_id'] ?? null) === ($choice['territory_id'] ?? null));
try {
$item = collect($this->options($choice['origin'], $choice['territory_id'] ?? null))->firstWhere('code', $choice['code']);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
if (!$old) throw $e;
$item = null;
} catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
if (!$old || $e->getStatusCode() !== 404) throw $e;
$item = null;
}
$offer = $target && $item ? collect([...$item['opportunities'], ...$item['services']])->firstWhere('key', $target) : null;
if ($old && (!$item || ($target && !$offer) || (!$target && ($item['opportunities'] || $item['services'])))) {
$resolved[$old['key']] = [...$old, 'availability' => 'review_required'];
continue;
}
abort_unless($item, 422, 'Complemento sem referência documentada neste investimento.');
abort_if($target && !$offer, 422, 'A oferta complementar deixou de estar disponível neste contexto.');
abort_if(!$target && ($item['opportunities'] || $item['services']), 422, 'Já existe uma oferta relacionada; seleccione a ficha correspondente.');
$key = hash('sha256', $choice['origin'].'|'.$choice['code'].'|'.($target ?? 'idea').'|'.($choice['territory_id'] ?? ''));
$resolved[$key] = ['key' => $key, 'origin' => $item['origin'], 'code' => $item['code'], 'title' => $item['title'],
'kind' => $target ? (str_starts_with($target, 'opportunity:') ? 'opportunity' : 'service') : 'need',
'target' => $offer, 'territory_id' => $item['territory_id'], 'territory' => $item['territory'], 'source' => $item['source'], 'excerpt' => $item['excerpt'], 'source_sha256' => $item['source_sha256']];
}
return array_values($resolved);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Arr;
/** An identified opportunity within the authorised dossier, never the account's last choice. */
final class InvestmentConsumerScope
{
public function key(array $context, ?string $key, bool $required = false): ?string
{
$choices = $context['opportunity_choices'] ?? [];
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
abort_if($key && !collect($choices)->contains('opportunity.key', $key), 422, 'Escolha uma oportunidade deste dossier.');
abort_if($required && count($choices) > 1 && !$key, 422, 'Escolha a oportunidade em tratamento.');
return $key;
}
public function facts(array $payload, array $context, ?string $key): array
{
$key = $this->key($context, $key);
$path = $payload['investor_path'] ?? [];
$defaults = ['land_needed' => 'unknown', 'external_funding' => 'unknown', 'viability' => 'unknown'];
// A dossier-wide dispensation cannot decide a distinct opportunity's needs.
if ($key && count($context['opportunity_choices'] ?? []) > 1) return [...$defaults, ...($path['opportunity_facts'][$key] ?? [])];
if ($key && isset($path['opportunity_facts'][$key])) return [...$defaults, ...$path['opportunity_facts'][$key]];
if (count($context['opportunity_choices'] ?? []) > 1) return $defaults;
return [...$defaults, ...($path['facts'] ?? [])];
}
public function context(array $context, ?string $key): array
{
$choices = $context['opportunity_choices'] ?? [];
if (!$choices) return $context;
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
$choice = $key ? collect($choices)->firstWhere('opportunity.key', $key) : null;
abort_if($key && !$choice, 422, 'Escolha uma oportunidade deste dossier.');
$specific = ['project_summary', 'sector_id', 'sector', 'province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location', 'special_zone_id', 'investment_regime'];
$context['fields'] = Arr::except($context['fields'], $specific);
$context['provenance'] = Arr::except($context['provenance'] ?? [], $specific);
$context['selection'] = Arr::except($context['selection'], ['opportunity', 'territory', 'park']);
if (!$choice) {
$context['opportunity_choices'] = [];
$context['requirements_assessment']['requirements'] = [];
return $context;
}
$context['selection']['opportunity'] = $choice['opportunity'];
$context['fields'] = [...$context['fields'], ...Arr::only($choice['opportunity']['fields'], $specific)];
foreach (Arr::only($choice['opportunity']['fields'], $specific) as $field => $value) $context['provenance'][$field] = Arr::only($choice['opportunity'], ['key','kind','id','title','version','sha256']);
unset($context['selection']['sector']);
if (!empty($context['fields']['sector_id'])) $context['selection']['sector'] = app(InvestorContext::class)->reference('sector:'.$context['fields']['sector_id']);
if ($choice['territory']) {
$context['selection']['territory'] = $choice['territory'];
$context['fields'] = [...Arr::except($context['fields'], array_keys(InvestmentGeography::FIELDS)), ...$choice['territory']['fields']];
foreach ($choice['territory']['fields'] as $field => $value) $context['provenance'][$field] = Arr::only($choice['territory'], ['key','kind','id','title','version','sha256']);
} else {
$context['fields'] = Arr::except($context['fields'], ['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location']);
}
$park = $choice['park'] ?? null;
if ($park) $context['selection']['park'] = $park;
$context['fields']['special_zone_id'] = $park['id'] ?? '';
$context['fields']['investment_regime'] = $park['fields']['investment_regime'] ?? 'general';
$context['opportunity_choices'] = [$choice];
$context['requirements_assessment']['requirements'] = array_values(array_filter($context['requirements_assessment']['requirements'] ?? [], fn($r) => $r['opportunity_key'] === $key));
$context['consumer_opportunity'] = $choice;
$context['complements'] = array_values(array_filter($context['complements'] ?? [], fn($c) => ($c['origin']['key'] ?? null) === $key || ($c['target']['key'] ?? null) === $key || in_array(substr($c['origin']['key'] ?? '',10),array_column($choice['portfolio_origins'] ?? [],'id'),true)));
$context['dependency_hash'] = app(InvestorContext::class)->dependencyHash(['opportunity_choices'=>[$choice], 'fields'=>Arr::except($context['fields'],['project_title','project_summary']), 'complements'=>$context['complements']]);
return $context;
}
public function bind(User $actor, string $id, array $payload, bool $required = false): array
{
$case = app(VirtualDesk::class)->case($actor, $id, true);
$context = app(InvestorContext::class)->state($case);
$scoped = $this->context($context, $payload['context_opportunity'] ?? null);
$choice = $scoped['consumer_opportunity'] ?? null;
abort_if($required && count($context['opportunity_choices'] ?? []) > 1 && !$choice, 422, 'Escolha a oportunidade em tratamento antes de submeter.');
if (!$choice) return Arr::except($payload, ['context_opportunity', 'context_opportunity_snapshot']);
// Canonical server snapshot; client text cannot establish a different origin or territory.
$payload['context_opportunity'] = $choice['opportunity']['key'];
$payload['context_opportunity_snapshot'] = json_encode(['context_id' => $id, 'revision' => $context['revision'], 'choice' => $choice, 'requirements' => $scoped['requirements_assessment'] ?? null], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
return $payload;
}
}
+12 -1
View File
@@ -51,7 +51,7 @@ final class InvestmentOpportunityChoices
$corridor = $choice['corridor_key'] ?? $old['corridor_key'] ?? $corridors->key($record);
$provinces = $corridor ? $corridors->provinces($corridor) : [];
$documented = $record->primary_territory_id;
$territory = $choice['territory'] ?? ($documented ? 'territory:'.$documented : null);
$territory = array_key_exists('territory', $choice) ? $choice['territory'] : ($documented ? 'territory:'.$documented : null);
if (!$territory && count($provinces) === 1) $territory = 'territory:'.$provinces[0]->id;
if ($corridor && $territory) abort_unless($corridors->compatible($corridor, substr($territory, 10)), 422, 'A localização não pertence ao corredor escolhido.');
$previousTerritory = $old['territory']['key'] ?? null;
@@ -65,7 +65,18 @@ final class InvestmentOpportunityChoices
}
$location = $territory ? app(InvestorContext::class)->reference($territory) : null;
abort_unless($location === null || $location['kind'] === 'territory', 422);
$parkKey = array_key_exists('park', $choice) ? $choice['park'] : ($old['park']['key'] ?? null);
$park = $parkKey ? app(InvestorContext::class)->reference($parkKey) : null;
if ($park) {
$eligible = $corridor ? array_column($corridors->parks($corridor, $location['id'] ?? null), 'id') : [];
if (!in_array($park['id'], $eligible, true)) {
abort_if(!empty($choice['park']), 422, 'A zona ou parque não é compatível com a localização desta oportunidade.');
$park = null;
}
abort_unless(!$park || $park['kind'] === 'park', 422);
}
$result[] = ['opportunity' => $ref, 'territory' => $location, ...($origins ? ['portfolio_origins' => $origins] : []),
'park' => $park,
'corridor_key' => $corridor, 'corridor_name' => $corridor ? config('investment_corridors.'.$corridor.'.name') : null,
'allowed_provinces' => array_map(fn($p)=>(array)$p, $provinces),
'territory_path' => $location ? array_map(fn ($node) => \Illuminate\Support\Arr::only((array) $node, ['id', 'name', 'parent_id', 'location_type']), app(InvestmentGeography::class)->path($location['id'], true)) : [],
+67 -19
View File
@@ -39,10 +39,11 @@ final class InvestorContext
$case=$this->desk->case($actor,$id,true);
abort_if($case->closed_at,409);
$sequence = (int)($input['draft_sequence'] ?? 0);
$entrySources=Validator::make($input,['entry_sources'=>'sometimes|array|max:100','entry_sources.*'=>'string|max:100'])->validate()['entry_sources']??[];
$entrySources=Validator::make($input,['entry_sources'=>'sometimes|array|max:200','entry_sources.*'=>'string|max:100'])->validate()['entry_sources']??[];
unset($input['draft_sequence'],$input['entry_sources']);
abort_unless($sequence > 0, 422);
$data = $this->input($input);
if (isset($data['complements'])) app(InvestmentComplements::class)->resolve($data['complements'], $this->state($case)['complements'] ?? []);
foreach ($data['selection'] as $slot=>$key) {
if (!$key) continue;
$ref=$this->reference($key);
@@ -60,6 +61,7 @@ final class InvestorContext
if ($key) abort_unless(app(InvestmentCorridorContext::class)->compatible($key, $location['id']), 422, 'A localização não pertence ao corredor escolhido.');
}
}
if (isset($data['opportunity_choices'])) app(InvestmentOpportunityChoices::class)->resolve($data['opportunity_choices'], $this->state($case)['opportunity_choices'] ?? [], true);
if (!empty($data['selection']['park'])) {
$first=$data['opportunity_choices'][0] ?? null;
$source=$first['source'] ?? $data['selection']['opportunity'] ?? null;
@@ -110,6 +112,7 @@ final class InvestorContext
}
}
}
if (!empty($context['opportunity_choices']) && !array_key_exists('park', $context['opportunity_choices'][0])) $context['opportunity_choices'][0]['park'] = $context['selection']['park'] ?? null;
$zone = $context['selection']['park'] ?? null;
$context['fields']['investment_regime'] = $zone['fields']['investment_regime'] ?? 'general';
$context['fields']['special_zone_id'] = $zone['id'] ?? '';
@@ -119,6 +122,7 @@ final class InvestorContext
public function dependencyHash(array $selection): string
{
unset($selection['portfolio'], $selection['selection']['portfolio']);
if (isset($selection['opportunity_choices'])) $selection['opportunity_choices'] = array_map(fn($choice)=>Arr::except($choice,['portfolio_origins']),$selection['opportunity_choices']);
return hash('sha256', json_encode(Arr::sortRecursive($selection), JSON_THROW_ON_ERROR));
}
@@ -165,6 +169,18 @@ final class InvestorContext
if ($o->primary_territory_id) {
$fields = [...$fields, ...$this->territoryFields($o->primary_territory_id)];
}
} elseif ($kind === 'portfolio') {
abort_unless(Str::isUuid($id), 422);
$dossier = \App\Http\Controllers\InvestmentPortfolioController::visible()->findOrFail($id);
$title = $dossier->title;
$href = '/carteira/'.$id;
// Documentary coverage is not the investor's chosen implantation.
$version = DB::table('investment_dossiers')->where('id', $id)->value('version_no');
$fields = ['project_title' => $title, 'project_summary' => $dossier->content['description'] ?? $dossier->content['focus'] ?? ''];
$state = 'documented_origin';
$zoneAnalysis = ['source' => $dossier->source, 'documented_sector' => $dossier->content['sector'] ?? null,
'documented_location' => $dossier->content['location'] ?? $dossier->content['region'] ?? null,
'geography' => app(InvestmentRelations::class)->dossier($dossier), 'available_opportunity' => false];
} elseif ($kind === 'business') {
abort_unless(config('existing-business.enabled') && Str::isUuid($id), 404);
$o = ExistingBusiness::published()->with('sector')->findOrFail($id);
@@ -328,7 +344,7 @@ final class InvestorContext
private function input(array $input): array
{
abort_if(array_diff(array_keys($input), ['opportunity_choices', 'version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(array_diff(array_keys($input), ['complements', 'opportunity_choices', 'version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(! app(PrivateInvestmentPreparation::class)->available() && (! empty($input['document_links']) || array_intersect(array_keys(is_array($input['declarations'] ?? null) ? $input['declarations'] : []), PrivateInvestmentPreparation::FIELDS)), 409, 'Esta preparação ainda não está disponível neste ambiente. As respostas foram preservadas.');
@@ -341,13 +357,17 @@ final class InvestorContext
}
return Validator::make($input, [...$inputRules,
'opportunity_choices' => 'sometimes|array|max:100', 'opportunity_choices.*' => 'array:source,territory,location_reason,confirm_location_change,activities,corridor_key,portfolio_origins',
'complements' => 'sometimes|array|max:100', 'complements.*' => 'array:origin,code,target,territory_id',
'complements.*.origin' => 'required|string|max:100', 'complements.*.code' => 'required|string|max:40',
'complements.*.target' => 'nullable|string|max:100', 'complements.*.territory_id' => 'nullable|uuid',
'opportunity_choices' => 'sometimes|array|max:100', 'opportunity_choices.*' => 'array:source,territory,location_reason,confirm_location_change,activities,corridor_key,portfolio_origins,park',
'opportunity_choices.*.portfolio_origins' => 'sometimes|array|max:100', 'opportunity_choices.*.portfolio_origins.*' => 'uuid',
'opportunity_choices.*.corridor_key' => ['sometimes', 'nullable', Rule::in(array_keys(config('investment_corridors')))],
'opportunity_choices.*.activities' => 'sometimes|array', 'opportunity_choices.*.activities.*' => 'string|distinct|in:production,processing,trade,transport,water,forestry,animal',
'opportunity_choices.*.park' => 'sometimes|nullable|string|max:100',
'opportunity_choices.*.source' => 'required|string|distinct|max:100', 'opportunity_choices.*.territory' => 'nullable|string|max:100',
'opportunity_choices.*.location_reason' => 'nullable|string|max:2000', 'opportunity_choices.*.confirm_location_change' => 'sometimes|boolean',
'version' => 'required|integer|min:1', 'selection' => 'present|array:opportunity,sector,territory,park',
'version' => 'required|integer|min:1', 'selection' => 'present|array:portfolio,opportunity,sector,territory,park',
'selection.*' => 'nullable|string|max:100', 'declarations' => 'nullable|array:project_title,project_summary,currency,expected_start_date,investor_origin,person_type,entity_stage,tax_residency_country,fiscal_residency_country,project_type,maturity_stage,'.implode(',', PrivateInvestmentPreparation::FIELDS), 'declarations.project_title' => 'nullable|string|max:200', 'declarations.project_summary' => 'nullable|string|max:5000',
'declarations.currency' => 'nullable|regex:/^[A-Z]{3}$/', 'declarations.expected_start_date' => 'nullable|date_format:Y-m-d', 'declarations.investor_origin' => 'nullable|in:national,foreign,mixed', 'declarations.person_type' => 'nullable|in:singular,collective,sole_trader,consortium', 'declarations.entity_stage' => 'nullable|in:existing,being_formed', 'declarations.tax_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.fiscal_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.project_type' => 'nullable|string|max:100', 'declarations.maturity_stage' => 'nullable|string|max:100',
'replace_fields' => 'nullable|array', 'replace_fields.*' => 'string|in:'.implode(',', self::FIELDS)])->validate();
@@ -361,6 +381,7 @@ final class InvestorContext
abort_unless((int) $case->version === $data['version'], 409, 'O dossier mudou; recupere a versão atual.');
app(InvestorPath::class)->view($actor, $id);
$old = $this->state($case);
$complements = array_key_exists('complements', $data) ? app(InvestmentComplements::class)->resolve($data['complements'], $old['complements'] ?? []) : ($old['complements'] ?? []);
$links = $old['preparation_documents'] ?? [];
foreach ($data['document_links'] ?? [] as $key => $document) {
if ($document) {
@@ -384,10 +405,17 @@ final class InvestorContext
$data['selection']['opportunity'] = $choices[0]['opportunity']['key'] ?? null;
// Shared fields concern the first identified opportunity; other sites remain separate.
$data['selection']['territory'] = $choices[0]['territory']['key'] ?? null;
if (array_key_exists('park', $data['opportunity_choices'][0] ?? [])) $data['selection']['park'] = $choices[0]['park']['key'] ?? null;
} elseif (array_key_exists('opportunity', $data['selection']) && $choices !== []) {
abort(422, 'Actualize a selecção identificada de oportunidades; não substitua silenciosamente o conjunto por uma ficha.');
}
$selection = $old['selection'];
foreach ($complements as $complement) {
if (($complement['availability'] ?? '') === 'review_required') continue;
foreach ([$complement['origin']['key'], $complement['target']['key'] ?? ''] as $key) {
if (str_starts_with($key, 'opportunity:')) abort_unless(in_array($key, array_column(array_column($choices, 'opportunity'), 'key'), true), 422, 'Conserve a oportunidade escolhida ou retire explicitamente a sua relação complementar.');
}
}
foreach ($data['selection'] as $slot => $key) {
if ($key === null || $key === '') {
unset($selection[$slot]);
@@ -417,7 +445,7 @@ final class InvestorContext
}
$proposed = [];
$origins = [];
foreach (['opportunity', 'sector', 'park', 'territory'] as $slot) {
foreach (['portfolio', 'opportunity', 'sector', 'park', 'territory'] as $slot) {
if (in_array($slot, ['park', 'territory'], true) && array_intersect(array_keys($selection[$slot]['fields'] ?? []), array_keys(InvestmentGeography::FIELDS))) {
foreach (['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location'] as $key) {
unset($proposed[$key],$origins[$key]);
@@ -469,18 +497,19 @@ final class InvestorContext
$replaced[] = ['field' => $key, 'before' => $old['fields'][$key] ?? null, 'after' => $fields[$key] ?? null];
}
}
foreach (['opportunity', 'sector', 'territory', 'park'] as $slot) {
foreach (['portfolio', 'opportunity', 'sector', 'territory', 'park'] as $slot) {
if (($old['selection'][$slot] ?? null) !== ($selection[$slot] ?? null)) {
$changed[] = $slot;
}
}
$changedFields = array_column($replaced, 'field');
if ($complements !== ($old['complements'] ?? [])) $changed[] = 'complements';
$choicesChanged = $choices !== ($old['opportunity_choices'] ?? []);
$choiceInputsChanged = array_map(fn($c)=>Arr::except($c,['portfolio_origins']),$choices) !== array_map(fn($c)=>Arr::except($c,['portfolio_origins']),$old['opportunity_choices']??[]);
if ($choiceInputsChanged) $changed = array_values(array_unique([...$changed, 'opportunity', 'territory']));
elseif ($choicesChanged) $changed[] = 'portfolio_origins';
$conditionsChanged = (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary']));
$dependencyChanged = $choiceInputsChanged || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$dependencyChanged = $choiceInputsChanged || in_array('complements', $changed, true) || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$privateConditionsChanged = (bool) array_intersect($changedFields, PrivateInvestmentPreparation::FIELDS);
$calculationInputsChanged = $choiceInputsChanged || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]));
$payload = $this->desk->decode($case->payload);
@@ -493,6 +522,7 @@ final class InvestorContext
if ($privateConditionsChanged) {
$steps = array_values(array_unique([...$steps, 'S02', 'S05', 'S06', 'S07']));
}
if (in_array('complements', $changed, true)) $steps = array_values(array_unique([...$steps, 'S02', 'S08']));
$privatePreparation = null;
if (app(PrivateInvestmentPreparation::class)->available()) {
$docs = $this->preparationDocuments($id);
@@ -500,7 +530,7 @@ final class InvestorContext
$afterPreparation = app(PrivateInvestmentPreparation::class)->assess(['fields' => $fields, 'selection' => $selection, 'preparation_documents' => $links], $docs);
$privatePreparation = ['before' => $beforePreparation, 'after' => $afterPreparation];
}
$plan = ['opportunity_choices' => $choices, 'case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
$plan = ['complements' => $complements, 'opportunity_choices' => $choices, 'case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
'preparation_documents' => $links, 'private_investment' => $privatePreparation,
'updated' => $replaced, 'maintained' => $kept, 'changed_dimensions' => $changed, 'dependent_results' => (int) $case->user_id === $actor->id && $calculationInputsChanged ? array_map(fn ($r) => ['id' => $r['id'], 'engine' => $r['engine']], $results) : [],
'requests' => $requests, 'review_steps' => $steps, 'dependency_changed' => $dependencyChanged, 'calculation_inputs_changed' => $calculationInputsChanged, 'documents_preserved' => DB::table('desk_documents')->where('case_id', $id)->count(),
@@ -545,8 +575,9 @@ final class InvestorContext
$review[$step] = ['revision' => $revision, 'reason' => 'O contexto mudou; reveja os pressupostos e a evidência aplicável.'];
}
$context = ['opportunity_choices' => $plan['opportunity_choices'], 'preparation_documents' => $plan['preparation_documents'], 'preparation_snapshot' => $plan['private_investment']['after'] ?? $before['preparation_snapshot'] ?? null, 'revision' => $revision, 'selection' => $plan['selection'], 'fields' => $plan['fields'], 'provenance' => $plan['provenance'], 'review_steps' => $review,
'dependency_hash' => $this->dependencyHash([...($plan['opportunity_choices'] !== [] ? ['opportunity_choices' => $plan['opportunity_choices']] : []), 'selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
'dependency_hash' => $this->dependencyHash([...($plan['opportunity_choices'] !== [] ? ['opportunity_choices' => $plan['opportunity_choices']] : []), ...($plan['complements'] ? ['complements' => $plan['complements']] : []), 'selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
$context['requirements_assessment'] = $plan['requirements_assessment'];
$context['complements'] = $plan['complements'];
if ($plan['calculation_inputs_changed']) {
foreach ($payload['investor_path']['results'] ?? [] as $i => $r) {
$payload['investor_path']['results'][$i] = [...$r, 'context_state' => 'review_required', 'context_invalidated_revision' => $revision, 'context_invalidated_at' => now()->toIso8601String()];
@@ -563,13 +594,13 @@ final class InvestorContext
}, 3);
}
public function view(User $actor, string $id): array
public function view(User $actor, string $id, ?string $opportunity = null): array
{
$case = $this->desk->case($actor, $id);
abort_unless($this->desk->owns($actor, $case, false) || $actor->can('manage-portal'), 403);
$ctx = $this->state($case);
$ctx['land_preparation'] = $this->landPreparation($case);
$path = app(InvestorPath::class)->view($actor, $id);
$ctx['land_preparation'] = $this->landPreparation($case, $opportunity);
$path = app(InvestorPath::class)->view($actor, $id, $opportunity);
$ctx['path_applicability'] = ['definition_id' => $path['definition_id'], 'definition_version' => $path['definition_version'], 'source_sha256' => $path['source_sha256'],
'steps' => array_values(array_map(fn ($step) => Arr::only($step, ['code', 'title', 'applicability', 'reason', 'state', 'context_review_required']), array_filter($path['steps'], fn ($step) => ! empty($step['branch']))))];
@@ -584,12 +615,19 @@ final class InvestorContext
}
}
$preparation = app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess($ctx, $this->preparationDocuments($id)) : null;
$preparation = app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess(app(InvestmentConsumerScope::class)->context($ctx, $opportunity), $this->preparationDocuments($id)) : null;
$ctx['preparation_assessment'] = $preparation;
$prefill = $this->prefill($ctx, $opportunity);
$saved = $this->desk->decode($case->payload);
if (!empty($saved['reuse_consent'])) {
$contacts = array_filter(['email' => $saved['email'] ?? null, 'phone' => $saved['profile']['phone'] ?? null], fn($v) => is_string($v) && $v !== '');
$prefill['simulator'] = [...$contacts, ...$prefill['simulator']];
$prefill['land'] = [...$contacts, ...(!empty($saved['name']) ? ['full_name' => $saved['name']] : []), ...$prefill['land']];
}
return ['private_investment' => $preparation, 'preparation_documents' => $this->preparationDocuments($id), 'simulator_context_revision' => $simulatorRevision, 'case' => $path['case'], 'context' => $ctx, 'steps' => array_map(fn ($s) => Arr::only($s, ['code', 'title', 'state', 'context_review_required']), $path['steps']),
'can_write' => $path['canWrite'], 'next' => $path['next'], 'results' => $path['results'], 'requests' => $path['requests'],
'prefill' => $this->prefill($ctx), 'notice' => 'A seleção apoia a preparação e não confirma benefícios, licenças, direitos ou disponibilidade.'];
'prefill' => $prefill, 'notice' => 'A seleção apoia a preparação e não confirma benefícios, licenças, direitos ou disponibilidade.'];
}
public function preparationDocuments(string $id): array
@@ -597,16 +635,21 @@ final class InvestorContext
return DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->whereNull('d.deleted_at')->get(['l.id', 'l.document_id', 'd.file_name', 'd.status', 'd.malware_scan_status', 'd.version_no', 'd.sha256'])->map(fn ($row) => (array) $row)->all();
}
public function landPreparation(\stdClass $case): array
public function landPreparation(\stdClass $case, ?string $opportunity = null): array
{
$path = $this->desk->decode($case->payload)['investor_path'] ?? [];
$need = $path['facts']['land_needed'] ?? 'unknown';
$payload = $this->desk->decode($case->payload);
$ctx = $this->state($case);
$key = app(InvestmentConsumerScope::class)->key($ctx, $opportunity);
$path = $payload['investor_path'] ?? [];
$need = app(InvestmentConsumerScope::class)->facts($payload, $ctx, $key)['land_needed'];
return ['need' => in_array($need, ['yes', 'no'], true) ? $need : 'unknown', 'reason' => $path['fact_reasons']['land_needed'] ?? ''];
return ['need' => in_array($need, ['yes', 'no'], true) ? $need : 'unknown', 'reason' => $key ? ($path['opportunity_fact_reasons'][$key]['land_needed'] ?? '') : ($path['fact_reasons']['land_needed'] ?? '')];
}
public function prefill(array $ctx): array
public function prefill(array $ctx, ?string $opportunity = null): array
{
$original = $ctx;
$ctx = app(InvestmentConsumerScope::class)->context($ctx, $opportunity);
$f = $ctx['fields'];
$sim = Arr::except(Arr::only($f, self::FIELDS), ['sector', 'province', 'district', 'location', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]);
// Entering this tool from an investment dossier selects the existing investment-analysis route.
@@ -626,9 +669,12 @@ final class InvestorContext
$zone = $ctx['selection']['park'] ?? null;
$sim['context_applicability_snapshot'] = json_encode([
'version' => 1, 'context_revision' => $ctx['revision'],
'consumer_opportunity' => $ctx['consumer_opportunity']['opportunity']['key'] ?? null,
'portfolio_origin' => $ctx['selection']['portfolio'] ?? null,
'zone' => $zone ? Arr::only($zone, ['id', 'title', 'href', 'version', 'sha256', 'fields', 'analysis']) : null,
'provenance' => $ctx['provenance'],
'opportunity_choices' => $ctx['opportunity_choices'] ?? [],
'complements' => $ctx['complements'] ?? [],
'requirements_assessment' => $ctx['requirements_assessment'] ?? null,
'path' => $ctx['path_applicability'] ?? null,
'land_preparation' => $ctx['land_preparation'] ?? null,
@@ -638,6 +684,8 @@ final class InvestorContext
'notice' => 'Referências e declarações para preparação; sem reconhecimento automático de elegibilidade ou benefício.',
], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
$scoped = app(InvestmentConsumerScope::class)->context($original, $opportunity);
$f = $scoped['fields'];
return ['simulator' => $sim, 'land' => array_filter(['project_reference' => $f['project_title'] ?? null, 'activity' => $f['sector'] ?? null, 'purpose' => $f['project_summary'] ?? null, 'parcels' => [Arr::only($f, array_keys(InvestmentGeography::FIELDS))]], fn ($v) => $v !== null),
'desk' => array_filter(['title' => $f['project_title'] ?? null, 'territory_id' => $f['locality_id'] ?? $f['admin_post_id'] ?? $f['district_id'] ?? $f['province_id'] ?? null, 'location_source' => isset($f['province_id']) ? 'Referência consultada no contexto v'.($ctx['revision'] ?? 0).': '.($f['location'] ?? 'território identificado').'. Não confirma disponibilidade.' : null, 'description' => $f['project_summary'] ?? null, 'sector' => $f['sector'] ?? null, ...Arr::only($f, array_keys(InvestmentGeography::FIELDS))], fn ($v) => $v !== null),
'submission' => array_filter(['currency' => $f['currency'] ?? null, 'sector' => $f['sector'] ?? null, 'objective' => $f['project_summary'] ?? null, 'location' => $f['location'] ?? null], fn ($v) => $v !== null)];
+38 -16
View File
@@ -68,7 +68,7 @@ final class InvestorPath
}
/** @return array<string,mixed> */
public function view(User $actor, string $id): array
public function view(User $actor, string $id, ?string $opportunity = null): array
{
abort_unless($this->available(), 404);
$case = $this->desk->case($actor, $id);
@@ -79,18 +79,26 @@ final class InvestorPath
$payload = $this->desk->decode($case->payload);
$path = $payload['investor_path'] ?? [];
$context = app(InvestorContext::class)->state($case);
$facts = $path['facts'] ?? ['land_needed' => 'unknown', 'external_funding' => 'unknown', 'viability' => 'unknown'];
$scope = app(InvestmentConsumerScope::class);
$opportunity = $scope->key($context, $opportunity);
$allChoices = $context['opportunity_choices'] ?? [];
$facts = $scope->facts($payload, $context, $opportunity);
$factReasons = $opportunity ? ($path['opportunity_fact_reasons'][$opportunity] ?? []) : ($path['fact_reasons'] ?? []);
$context = $scope->context($context, $opportunity);
$records = DB::table('journey_steps')->where('journey_id', $journey->id)->whereNull('deleted_at')->get()->keyBy('step_code');
$steps = [];
foreach ($definition['steps'] as $step) {
$row = $records->get($step['code']);
abort_unless($row !== null, 409, 'Etapa em falta; reparar a instalação sem reconstruir o histórico.');
$detail = $this->desk->decode($row->path_detail);
if ($opportunity && (count($allChoices) > 1 || isset($detail['opportunities'][$opportunity]))) {
$detail = $detail['opportunities'][$opportunity] ?? ['state' => 'not_started'];
}
$value = $step['branch'] ? ($facts[$step['branch']] ?? 'unknown') : 'yes';
$applicable = $value === 'unknown' ? 'undetermined' : ($value === 'no' ? 'not_needed_for_preparation' : 'applicable');
$state = $value === 'no' ? 'dispensed' : $detail['state'];
$steps[] = [...$step, 'id' => $row->id, 'version' => $row->version_no, 'state' => $state, 'saved_state' => $detail['state'],
'applicability' => $applicable, 'reason' => $value === 'no' ? ($path['fact_reasons'][$step['branch']] ?? '') : ($detail['reason'] ?? ''),
'applicability' => $applicable, 'reason' => $value === 'no' ? ($factReasons[$step['branch']] ?? '') : ($detail['reason'] ?? ''),
'detail' => $detail, 'preparation_allowed' => $value !== 'no',
'action_gaps' => []];
}
@@ -143,7 +151,8 @@ final class InvestorPath
$landCase = (int) $case->user_id === $actor->id
? LandAssistanceCase::where('user_id', $actor->id)->latest('updated_at')->get()
->first(fn ($land) => ($land->payload['investor_path_case_id'] ?? null) === $id) : null;
->first(fn ($land) => ($land->payload['investor_path_case_id'] ?? null) === $id
&& (!$allChoices || ($opportunity && ($land->payload['context_opportunity'] ?? null) === $opportunity))) : null;
$preparation = ($owner || $manager) && app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess($context, $documents->map(fn ($d) => (array) $d)->all()) : null;
if ($preparation && $preparation['enabled']) {
@@ -152,11 +161,12 @@ final class InvestorPath
return ['private_investment' => $preparation, 'case' => ['id' => $id, 'title' => $case->title, 'version' => $case->version, 'closed' => $case->closed_at !== null],
'journey_id' => $journey->id, 'definition_id' => $version->id, 'definition_version' => $version->version_no, 'source_sha256' => $definition['source_sha256'],
'phases' => $definition['phases'], 'steps' => $steps, 'facts' => $facts, 'fact_reasons' => $path['fact_reasons'] ?? [],
'phases' => $definition['phases'], 'steps' => $steps, 'facts' => $facts, 'fact_reasons' => $factReasons,
'context_opportunity' => $opportunity, 'opportunity_options' => $allChoices,
'fintech' => ($owner || $manager) && (isset($path['fintech']) || collect($path['sector_contexts'] ?? [])->contains(fn ($s) => in_array($s['slug'], ['fintech', 'tecnologias-de-informacao', 'mercado-financeiro'], true)) || collect($path['content_sources'] ?? [])->contains('return_href', '/tech-fintech')) ? app(FintechInvestment::class)->view($payload, $steps) : null,
'canWrite' => $owner && ! $case->closed_at, 'canReview' => $manager && (int) $case->user_id !== $actor->id && ! $case->closed_at,
'next' => $next ? ['code' => $next['code'], 'title' => $next['title'], 'action' => 'Preparar', 'href' => $next['href'] ?? '#'.$next['code']] : null,
'investment_context' => ($owner || $manager) ? $context : null,
'investment_context' => ($owner || $manager) ? [...$context, 'opportunity_choices' => $opportunity ? $context['opportunity_choices'] : $allChoices] : null,
'results' => $results, 'requests' => $requests, 'documents' => $documents,
'zone_contexts' => ($owner || $manager) ? ($path['zone_contexts'] ?? []) : [],
'sector_contexts' => ($owner || $manager) ? ($path['sector_contexts'] ?? []) : [],
@@ -167,25 +177,31 @@ final class InvestorPath
->get(['id', 'title', 'status', 'version_no', 'due_at', 'assignee_user_id']),
'services' => DB::table('desk_service_versions')->where('status', 'published')->orderByDesc('version')->get(['id', 'code', 'definition'])
->unique('code')->values()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title']]),
'tools' => ['simulator' => (int) $case->user_id === $actor->id ? '/simulador-fiscal?context='.$id.($case->simulation_id ? '&draft='.$case->simulation_id : '') : null,
'desk' => '/balcao-virtual/dossiers/'.$id, 'guidance' => '/balcao-virtual/dossiers/'.$id.'/orientacao',
'tools' => ['simulator' => (int) $case->user_id === $actor->id ? '/simulador-fiscal?context='.$id.($case->simulation_id ? '&draft='.$case->simulation_id : '').($opportunity ? '&opportunity='.urlencode($opportunity) : '') : null,
'desk' => '/balcao-virtual/dossiers/'.$id.($opportunity ? '?opportunity='.urlencode($opportunity) : ''), 'guidance' => '/balcao-virtual/dossiers/'.$id.'/orientacao',
'library' => '/documentos?context='.$id, 'opportunities' => '/oportunidades?context='.$id, 'territory' => '/zonas?context='.$id, 'partners' => '/parcerias/painel?context='.$id,
'land' => ($facts['land_needed'] ?? 'unknown') !== 'no' && (int) $case->user_id === $actor->id ? ($landCase ? '/investidor/terra-duat/'.$landCase->id : '/investidor/terra-duat/novo?context='.$id) : null]];
'land' => ($facts['land_needed'] ?? 'unknown') !== 'no' && (int) $case->user_id === $actor->id ? ($landCase ? '/investidor/terra-duat/'.$landCase->id : '/investidor/terra-duat/novo?context='.$id.($opportunity ? '&opportunity='.urlencode($opportunity) : '')) : null]];
}
/** @param array<string,mixed> $input */
public function facts(User $actor, string $id, array $input): void
{
$data = Validator::make($input, ['version' => 'required|integer|min:1',
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'context_opportunity' => 'nullable|string|max:100',
'land_needed' => ['required', Rule::in(['yes', 'no', 'unknown'])], 'external_funding' => ['required', Rule::in(['yes', 'no', 'unknown'])],
'viability' => ['required', Rule::in(['unknown', 'proceed', 'reformulate', 'archive'])],
'reason' => 'required|string|min:3|max:3000'])->validate();
DB::transaction(function () use ($actor, $id, $data): void {
$case = $this->writable($actor, $id, $data['version']);
$payload = $this->desk->decode($case->payload);
$choice = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), $data['context_opportunity'] ?? null, true);
foreach (['land_needed', 'external_funding', 'viability'] as $key) {
$payload['investor_path']['facts'][$key] = $data[$key];
$payload['investor_path']['fact_reasons'][$key] = $data['reason'];
if ($choice) {
$payload['investor_path']['opportunity_facts'][$choice][$key] = $data[$key];
$payload['investor_path']['opportunity_fact_reasons'][$choice][$key] = $data['reason'];
} else {
$payload['investor_path']['facts'][$key] = $data[$key];
$payload['investor_path']['fact_reasons'][$key] = $data['reason'];
}
}
$this->savePayload($case, $payload);
$this->desk->event($this->desk->case($actor, $id), $actor, 'path_applicability_declared', $data);
@@ -195,7 +211,7 @@ final class InvestorPath
/** @param array<string,mixed> $input */
public function stage(User $actor, string $id, string $code, array $input): void
{
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'state' => ['required', Rule::in(array_diff(InvestorPathDefinition::STATES, ['dispensed']))],
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'context_opportunity' => 'nullable|string|max:100', 'state' => ['required', Rule::in(array_diff(InvestorPathDefinition::STATES, ['dispensed']))],
'reason' => 'required|string|min:3|max:3000', 'action' => ['required', Rule::in(['prepare', 'submit', 'execute', 'operate', 'review', 'record_external'])],
'document_id' => 'nullable|uuid', 'authority' => 'nullable|string|max:200', 'reference' => 'nullable|string|max:300',
'context_revision' => 'nullable|integer|min:0', 'context_reviewed' => 'nullable|boolean', 'decision_date' => 'nullable|date_format:Y-m-d|before_or_equal:today'])->validate();
@@ -203,7 +219,8 @@ final class InvestorPath
$case = $this->desk->case($actor, $id, false, true);
abort_if($case->closed_at, 409);
abort_unless((int) $case->version === $data['version'], 409, 'O dossier mudou; recupere a versão actual.');
$view = $this->view($actor, $id);
$key = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), $data['context_opportunity'] ?? null, true);
$view = $this->view($actor, $id, $key);
$step = $this->findStep($view, $code);
abort_unless($step !== null && $step['preparation_allowed'], 422, 'Etapa dispensada de preparação; altere os pressupostos com fundamento.');
$state = $data['state'];
@@ -238,7 +255,10 @@ final class InvestorPath
}
abort_if($state === 'completed' && ($step['context_review_required'] ?? false) && (! (bool) ($data['context_reviewed'] ?? false) || ($data['context_revision'] ?? -1) !== ($view['investment_context']['revision'] ?? 0)), 422, 'O contexto desta etapa exige nova conferência fundamentada; o registo anterior permanece no histórico.');
$detail = [...$data, 'context_dependency_hash' => $view['investment_context']['dependency_hash'] ?? null, 'fintech_fingerprint' => $view['fintech']['review_fingerprints'][$code] ?? null, 'scope' => $scope, 'actor_id' => $actor->id, 'recorded_at' => now()->toIso8601String()];
DB::table('journey_steps')->where('id', $step['id'])->update(['path_detail' => $this->desk->encode($detail),
$stored = $this->desk->decode(DB::table('journey_steps')->where('id', $step['id'])->value('path_detail'));
if ($key) $stored['opportunities'][$key] = $detail;
else $stored = [...$stored, ...$detail];
DB::table('journey_steps')->where('id', $step['id'])->update(['path_detail' => $this->desk->encode($stored),
'status' => in_array($state, ['completed', 'approved'], true) ? 'completed' : ($state === 'not_started' ? 'pending' : 'active'),
'version_no' => $step['version'] + 1, 'updated_at' => now()]);
DB::table('desk_cases')->where('id', $id)->update(['version' => $case->version + 1, 'updated_at' => now()]);
@@ -267,11 +287,12 @@ final class InvestorPath
abort_unless(is_array($parsed) && ($parsed['version'] ?? null) === 1 && is_array($parsed['data'] ?? null), 422, 'Snapshot financeiro incompatível.');
$payload = $this->desk->decode($case->payload);
$context = app(InvestorContext::class)->state($case);
$opportunity = app(InvestmentConsumerScope::class)->key($context, $economic['context_opportunity'] ?? null, true);
if ($context['revision'] > 0) {
abort_unless(($data['context_revision'] ?? -1) === $context['revision'], 409, 'O contexto mudou; recupere e confira os pressupostos antes de devolver o resultado.');
abort_unless($data['context_reviewed'] ?? false, 422, 'Confirme a revisão dos pressupostos financeiros para este contexto.');
}
$resultKey = hash('sha256', $draft->id.':'.$draft->version_no.':'.$snapshot.':context:'.$context['revision']);
$resultKey = hash('sha256', $draft->id.':'.$draft->version_no.':'.$snapshot.':context:'.$context['revision'].($opportunity ? ':'.$opportunity : ''));
foreach ($payload['investor_path']['results'] ?? [] as $result) {
if ($result['source_key'] === $resultKey) {
return $result;
@@ -280,6 +301,7 @@ final class InvestorPath
abort_unless((int) $case->version === $data['version'], 409, 'Recupere a versão actual do dossier.');
$result = ['id' => (string) Str::uuid(), 'source_key' => $resultKey, 'draft_id' => $draft->id, 'draft_version' => $draft->version_no,
'snapshot_sha256' => $draft->snapshot_sha256, 'financial_snapshot' => $snapshot,
'context_opportunity' => $opportunity,
'currency' => $economic['currency'] ?? null, 'engine' => 'financial-calculators:v1',
'kind' => 'local_calculation_inputs', 'context_state' => 'current', 'context_revision' => $context['revision'], 'context_dependency_hash' => $context['dependency_hash'] ?? app(InvestorContext::class)->dependencyHash([]), 'recorded_at' => now()->toIso8601String()];
$payload['investor_path']['results'][] = $result;
+6 -1
View File
@@ -470,7 +470,10 @@ final class SimulationFormDrafts
private function landContext(array $economic, \stdClass $case, ?array $previous = null): array
{
$decision = app(InvestorContext::class)->landPreparation($case);
$snapshot = json_decode($economic['context_applicability_snapshot'] ?? $previous['context_applicability_snapshot'] ?? '', true);
$key = $economic['context_opportunity'] ?? $snapshot['consumer_opportunity'] ?? null;
$key = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), is_string($key) ? $key : null);
$decision = app(InvestorContext::class)->landPreparation($case, $key);
if ($decision['need'] !== 'yes' && $previous !== null) {
if (array_key_exists('land_status', $previous)) $economic['land_status'] = $previous['land_status'];
else unset($economic['land_status']);
@@ -482,6 +485,8 @@ final class SimulationFormDrafts
$snapshot = ['version' => 1, 'context_revision' => app(InvestorContext::class)->state($case)['revision']];
}
$snapshot['land_preparation'] = $decision;
$snapshot['consumer_opportunity'] = $key;
if ($key) $economic['context_opportunity'] = $key;
$economic['context_applicability_snapshot'] = json_encode($snapshot, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
return $economic;
+19 -4
View File
@@ -14,16 +14,31 @@ final class TerritoryGeometry
abort_unless($geography->references($management)->where('id', $id)->exists(), 404);
$path = $geography->path($id, $management);
$ids = array_map(fn ($node) => $node->id, $path);
$approved = app(ApprovedAdministrativeBoundaries::class);
$rows = DB::table('geo_geometries as g')->join('geo_locations as l', 'l.id', '=', 'g.geo_location_id')
->whereIn('g.geo_location_id', $ids)->whereNull('g.deleted_at')->whereNull('l.deleted_at')
->whereIn('g.data_classification', $management ? ['internal', 'public'] : ['public'])
->where(function ($query) use ($management, $approved) {
$query->where('g.data_classification', 'public');
$query->orWhere(function ($internal) use ($management, $approved) {
$internal->where('g.data_classification', 'internal');
if (! $management) {
$internal->whereIn('g.id', array_keys($approved->snapshots()));
}
});
})
->whereRaw("g.properties->>'purpose' = 'administrative_boundary'")
->whereIn('g.geometry_type', ['polygon', 'multipolygon'])
->whereRaw('ST_IsValid(g.geom) AND NOT ST_IsEmpty(g.geom) AND ST_SRID(g.geom)=4326')
->orderBy('g.geo_location_id')->orderBy('g.id')->limit(101)
->get(['g.id', 'g.geo_location_id', 'l.name', 'l.location_type', 'g.properties', 'g.data_classification',
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry')]);
$areas = $rows->take(100)->map(function ($row) use ($id) {
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry'),
DB::raw("encode(sha256(ST_AsEWKB(g.geom)),'hex') as geometry_sha256"),
DB::raw("encode(sha256(convert_to(g.properties::text,'UTF8')),'hex') as properties_sha256")]);
if (! $management) {
$rows = $rows->filter(fn ($row) => $row->data_classification === 'public'
|| $approved->allows($row->id, $row->geo_location_id, $row->geometry_sha256, $row->properties_sha256))->values();
}
$areas = $rows->take(100)->map(function ($row) use ($id, $management) {
$source = json_decode($row->properties, true, 512, JSON_THROW_ON_ERROR);
return ['id' => $row->id, 'territory_id' => $row->geo_location_id, 'location_type' => $row->location_type,
@@ -31,7 +46,7 @@ final class TerritoryGeometry
'title' => 'Limite administrativo: '.$row->name, 'purpose' => 'administrative_boundary',
'source_reference' => $source['authority'] ?? null, 'source_date' => $source['source_version'] ?? null,
'source_url' => $source['source_url'] ?? null, 'source_sha256' => $source['source_sha256'] ?? null,
'data_classification' => $row->data_classification, 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
'data_classification' => $management ? $row->data_classification : 'public', 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
})->all();
return ['territory_id' => $id, 'territory_registered' => true,
+18 -4
View File
@@ -170,11 +170,11 @@ class VirtualDesk
});
}
public function createRequest(User $actor, string $caseId, string $serviceId, string $clientKey): \stdClass
public function createRequest(User $actor, string $caseId, string $serviceId, string $clientKey, ?string $opportunity = null): \stdClass
{
abort_unless(Str::isUuid($serviceId) && Str::isUuid($clientKey), 422);
return DB::transaction(function () use ($actor, $caseId, $serviceId, $clientKey) {
return DB::transaction(function () use ($actor, $caseId, $serviceId, $clientKey, $opportunity) {
$case = $this->case($actor, $caseId, true, true);
abort_if($case->closed_at, 409, 'Dossier encerrado.');
$service = DB::table('desk_service_versions')->where('id', $serviceId)->where('status', 'published')->first();
@@ -197,7 +197,10 @@ class VirtualDesk
$this->event($case, $actor, 'request_prefill_prepared', ['draft_id' => $draft->id, 'draft_version' => $draft->version_no, 'snapshot_sha256' => $draft->snapshot_sha256, 'fields' => ['title', 'description']]);
}
$context = app(InvestorContext::class)->state($case);
$mapped = app(InvestorContext::class)->prefill($context)['desk'];
if (count($context['opportunity_choices'] ?? []) > 1 && !$opportunity) $payload['description'] = '';
$mapped = app(InvestorContext::class)->prefill($context, $opportunity)['desk'];
if ($opportunity) $payload['context_opportunity'] = $opportunity;
$payload = app(InvestmentConsumerScope::class)->bind($actor, $caseId, $payload);
$serviceFields = json_decode($service->definition, true)['fields'];
foreach (['territory_id' => 'territory_id', 'location_source' => 'location_source', 'title' => 'title', 'description' => 'description', 'sector' => 'sector', 'province_id' => 'province_id', 'district_id' => 'district_id', 'admin_post_id' => 'admin_post_id', 'locality_id' => 'locality_id'] as $field => $source) {
if (isset($serviceFields[$field],$mapped[$source]) && (empty($payload[$field]) || in_array($field, ['title', 'description'], true) && $context['revision'] > 0)) {
@@ -230,6 +233,12 @@ class VirtualDesk
$draft = SimulationFormDraft::query()->whereKey($draft->id)->lockForUpdate()->firstOrFail();
}
$economic = SimulationFormDraft::decryptSnapshot($draft->economic_snapshot);
$contextChoices = app(InvestorContext::class)->state($case)['opportunity_choices'] ?? [];
if (count($contextChoices) > 1) {
$snapshot = json_decode($economic['context_applicability_snapshot'] ?? '{}', true);
$draftChoices = $snapshot['opportunity_choices'] ?? [];
if (count($draftChoices) !== 1 || ($draftChoices[0]['opportunity']['key'] ?? null) !== ($payload['context_opportunity'] ?? null)) return null;
}
$description = (string) ($economic['project_summary'] ?? '');
if (trim($description) === '') {
return null;
@@ -250,7 +259,9 @@ class VirtualDesk
* @return array<string,mixed> */
public function validateFields(array $payload, array $definition, bool $submitting): array
{
$rules = ['payload' => ['required', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse'])],
$rules = ['payload' => ['required', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'])],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.country' => ['nullable', 'string', 'max:100', app(CountryCatalogue::class)->legacyCountryRule()],
'payload.declared_origin_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()]];
@@ -334,6 +345,9 @@ class VirtualDesk
}
}
$payload = $this->validateFields($data['payload'], $this->definition($request), $submit);
if ($request->status !== 'returned' || in_array('context_opportunity', json_decode($request->editable_fields ?? '[]', true), true)) {
$payload = app(InvestmentConsumerScope::class)->bind($actor, $request->case_id, $payload, $submit);
}
if ($request->status === 'returned') {
$editable = json_decode($request->editable_fields ?? '[]', true);
$previous = $this->decode($request->payload);
@@ -0,0 +1,710 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: aplicar o anexo de identidade visual aos cinco cartões de Encontre o contexto do seu investimento.",
"instructionSource": {
"path": "C:\\Users\\jorge\\.codex\\attachments\\637b878f-1f58-490d-bd07-d5cd10ae2377\\Pasted text.txt",
"sha256": "fcc24dcce4b5df3f10e29add48052808d48ddcf674d052287854e11910e01d69"
},
"source": {
"type": "AI-generated photorealistic illustrative images",
"tool": "image_gen, built-in mode",
"skill": "C:/Users/jorge/.codex/skills/.system/imagegen/SKILL.md",
"externalPhotographsUsed": false,
"namedRealLocationsDepicted": false,
"note": "Cenas ilustrativas plausíveis, sem atribuição a instalações, pessoas, instituições ou projectos reais."
},
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#fotografias-nos-cartões-de-contexto-do-investimento--23102026",
"filesChanged": [
"resources/js/pages/PortalInvestidor.tsx",
"resources/js/components/investment-context-cards.tsx",
"tools/portal-context-cards-qa.mjs",
"docs/investmoz/public-portal-sections.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
"docs/investmoz/public-portal-context-images.json"
],
"images": [
{
"key": "clusters-agroindustria",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a modest, well maintained agro-processing packing facility linking commercial agriculture to local industry. Wide three-quarter view into an airy open-sided processing shed with pale walls and a few orderly wooden or reusable produce crates, stainless processing/sorting benches and an unobtrusive commercial agricultural field visible beyond. Two Black southern African workers in clean practical workwear sorting harvested vegetables naturally, faces not prominent. Show production and transformation together in ONE genuine-looking continuous scene, no montage. Clear simple geometry, warm-neutral sunlight, subtle vegetation.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f72e66b0-d788-4476-8b20-c39b22d5d6dc.png",
"original": "outputs/investment-context-20261023/originals/clusters-agroindustria.png",
"originalSha256": "75e04a694081ab757831fc9b37323949d09806e622c83d07588fc47c423c9033",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/clusters-agroindustria.webp",
"width": 960,
"height": 540,
"bytes": 116796,
"sha256": "12494b31ab551cffb79f81c7d1519c0c4a2d4236e7f129bec1ce32251b39d847"
},
{
"file": "public/images/investment-context/clusters-agroindustria-480.webp",
"width": 480,
"height": 270,
"bytes": 42060,
"sha256": "76e3152c99ed188f748542dcf0464787307dbdc1c6299e7264dfd1bd86ad75e3"
},
{
"file": "public/images/investment-context/clusters-agroindustria-fallback.webp",
"width": 240,
"height": 135,
"bytes": 9596,
"sha256": "9f668da50f7d64955b31940d239b420ac18dbb76a8120c8bedab3f2c04710288"
}
]
},
{
"key": "corredores-logisticos",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a commercial freight terminal serving a southern African logistics corridor. Elevated medium-wide viewpoint showing an orderly short line of unbranded freight containers, one realistic container-handling crane and a freight truck on a paved lane, with a calm strip of water and low coastal industrial vegetation in the distance. Infrastructure of credible modest contemporary scale, generic and unidentifiable; do not reproduce or name Maputo, Beira, Nacala or any real port. Spatially coherent containers, road and handling equipment; clean clear subject with no excessive machinery.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-0363da23-f9cb-413b-bb64-024539085c4b.png",
"original": "outputs/investment-context-20261023/originals/corredores-logisticos-v2.png",
"originalSha256": "2151d1a59265c6f7151d18af6ef6ad78f9fc6e0cd58ac9cc5c64b50a25c5058e",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/corredores-logisticos-v2.webp",
"width": 960,
"height": 540,
"bytes": 85184,
"sha256": "1939c26df297588b6c3e5ea08b700d4cda5d1183cf3e5faed06a1ca060d2475e"
},
{
"file": "public/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 480,
"height": 270,
"bytes": 26222,
"sha256": "06dc0e7126cb2c13eb3f9a98f6ee58f5d64f9d07c28620975f744f263744fe15"
},
{
"file": "public/images/investment-context/corredores-logisticos-v2-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5334,
"sha256": "f9fd6e6c3a2d4654df1a8fdb287e122f1889b5d318c104c4816ee393c793e242"
}
],
"selectedSource": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-c2cff7da-d602-4191-9aca-380918a09619.png",
"editPrompt": "Edit the provided photograph: REMOVE THE ENTIRE FOREGROUND TRUCK, including cab, wheels, long trailer and the red freight container on that trailer. The big truck at lower left/centre must be completely gone. Replace the removed truck's area with a continuous empty realistic paved road surface matching the surrounding pavement and road markings. Leave the stacked stationary freight containers along the quay, the water, the large port crane, the lifted container and workers. All remaining equipment and containers should have plain surfaces without readable lettering, logos, numbers or brands. No new truck, vehicle, symbol, text or overlay. Keep a single clean editorial photograph, natural lighting and horizontal 16:9 framing. Generic commercial port scene, not a named real facility."
},
{
"key": "projectos-ancora",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a small team of two Black southern African engineering professionals, one woman and one man, in realistic hard hats and restrained protective workwear, seen candidly from a three-quarter rear angle reviewing an unmarked folded technical plan at a utility-scale solar installation. Low rows of realistic blue solar panels and a simple low service building recede into a dry green southern African landscape. No readable drawing or numbers on the plan. Focus on credible engineering and investment project scale; clean composition, quiet professional atmosphere, no landmark or company identifiers.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-19fcd882-542b-43c9-81e7-593fd75083f6.png",
"original": "outputs/investment-context-20261023/originals/projectos-ancora.png",
"originalSha256": "f23cf6e64307a280f3aa58741454a23480ac28fcae01a0810adf134b783a3a74",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/projectos-ancora.webp",
"width": 960,
"height": 540,
"bytes": 77114,
"sha256": "de0b59774246fee982761de59618b3e7707c3fe30f2b1bcbb6017d4dce53c4dc"
},
{
"file": "public/images/investment-context/projectos-ancora-480.webp",
"width": 480,
"height": 270,
"bytes": 29484,
"sha256": "268e405112ed341fce3c9792c3caa47053984100cd4a204453e31bbe5db6e890"
},
{
"file": "public/images/investment-context/projectos-ancora-fallback.webp",
"width": 240,
"height": 135,
"bytes": 6750,
"sha256": "db7e4b4382e09eb6b4f9f2a4603ccac4b4eacc53ba0f6776429e33dbf5131954"
}
]
},
{
"key": "educacao-formacao",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a candid technical training classroom with three Black southern African young adult students of different genders and one instructor working together at a practical electronics and computing workbench. Bright modest well maintained vocational classroom, natural window light, simple laboratory equipment and unbranded closed or angled laptops whose screens have no visible interface or text. Focus on two students engaged in a realistic small hands-on electronics exercise with normal anatomy and correct equipment proportions. Dignified contemporary clothing, natural concentration, professional skills and human capital investment, no posed smiles or stereotypes.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-d21314d7-c726-41ad-862c-3c8b64df6b53.png",
"original": "outputs/investment-context-20261023/originals/educacao-formacao.png",
"originalSha256": "e59ec599e8c64ab84195d0cb37871d3102df178a13275806ca3b7f98e6bfa895",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/educacao-formacao.webp",
"width": 960,
"height": 540,
"bytes": 68224,
"sha256": "e3e5dbd292cac555a45bcbd94a0fa6b60e6b710debc0c827c68603f40bfb8a28"
},
{
"file": "public/images/investment-context/educacao-formacao-480.webp",
"width": 480,
"height": 270,
"bytes": 27384,
"sha256": "d3b743fbba7a8cb40e45999ee8c345cbfc0332cf85f5c5c2d6a5cf1240a395e4"
},
{
"file": "public/images/investment-context/educacao-formacao-fallback.webp",
"width": 240,
"height": 135,
"bytes": 7156,
"sha256": "0b2a12898043c57cf4354b54ebcba8adec8d41b3886bc574584ccc12af7b1e4c"
}
]
},
{
"key": "documentos-formularios",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a close-medium editorial photograph of a tidy modern administrative office desk where a Black southern African professional in a plain light blue shirt is naturally reviewing organised business documentation. Frame hands, desk and partial torso, no prominent portrait. Neat neutral folders, a few sheets with only faint out-of-focus non-readable printing, a pen and an unbranded laptop angled away with no visible UI. Soft window light, white and pale neutral surfaces with subtle blue accents. Absolutely no readable personal data, invented official seals or highlighted fake text; realistic fingers and documents, calm minimal composition.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f1c8e22e-6885-4578-ac7d-02692c5cc071.png",
"original": "outputs/investment-context-20261023/originals/documentos-formularios.png",
"originalSha256": "cfbd38a9cc9b9acf35f38220f5bd9c1ab1feafe411bc1d4bbdb3658de557e052",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/documentos-formularios.webp",
"width": 960,
"height": 540,
"bytes": 43002,
"sha256": "70ddea3256e6a8d981b1fae5ee7b4de6c910d757137b79a59306c268c278402f"
},
{
"file": "public/images/investment-context/documentos-formularios-480.webp",
"width": 480,
"height": 270,
"bytes": 17996,
"sha256": "436865c948acbb7b6e9e482bef8f5bd626c6960f2f155608e40dfcd0e76b84cb"
},
{
"file": "public/images/investment-context/documentos-formularios-fallback.webp",
"width": 240,
"height": 135,
"bytes": 4958,
"sha256": "fad6a6ab825a82ec2541d2e0c6de9d85486e4bbca159b912f87bec9cc0aeeba5"
}
]
}
],
"primaryImagesBytesTotal": 390320,
"responsive480ImagesBytesTotal": 143146,
"implementation": {
"gridColumns": [
1,
2,
4
],
"aspectRatio": "16:9",
"responsiveImages": true,
"lazyLoading": true,
"altLanguage": "pt",
"fallback": "Derivado pequeno da própria imagem; se também falhar, estado acessível Imagem indisponível, com dimensão reservada e link mantido.",
"globalCSSChanged": false,
"businessLogicChanged": false,
"databaseChanged": false,
"heroChanged": false
},
"visualReview": "Cinco composições individuais distintas, cores naturais e luz editorial; sem títulos/colagens ou mapas. A composição de Corredores foi revista para remover o camião com marca. Capturas em computador e telemóvel inspeccionadas.",
"verification": {
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 320,
"height": 180
}
],
"status": "passed"
},
{
"width": 390,
"dpr": 2,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 389,
"height": 219
}
],
"status": "passed"
},
{
"width": 768,
"dpr": 1,
"columns": 2,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 384,
"height": 216
}
],
"status": "passed"
},
{
"width": 1024,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 256,
"height": 144
}
],
"status": "passed"
},
{
"width": 1440,
"dpr": 2,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"width": 1920,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
}
],
"errors": [],
"navigation": [
"/clusters",
"/corredores",
"/projectos-ancora",
"/educacao",
"/documentos"
],
"databaseAccess": false
},
"script": "tools/portal-context-cards-qa.mjs",
"screenshots": [
"outputs/investment-context-20261023/cards-1024-dpr1.png",
"outputs/investment-context-20261023/cards-1440-dpr2.png",
"outputs/investment-context-20261023/cards-1920-dpr1.png",
"outputs/investment-context-20261023/cards-320-dpr1.png",
"outputs/investment-context-20261023/cards-390-dpr2.png",
"outputs/investment-context-20261023/cards-768-dpr1.png",
"outputs/investment-context-20261023/fallback-all.png",
"outputs/investment-context-20261023/fallback-primary.png"
],
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"files": [
"resources/js/components/investment-context-cards.tsx",
"resources/js/pages/PortalInvestidor.tsx",
"tools/portal-context-cards-qa.mjs"
],
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-fh5VZanx.js",
"log": "outputs/investment-context-20261023/build-local.log"
}
},
"scope": "Aplicado no código e pacote locais. API e navegação simuladas na verificação visual; sem dados activos ou publicação externa.",
"matrixReferences": [
"MASTER-efd550fd-0104",
"MASTER-55050f60-0001"
],
"acceptanceLimit": "Prova restrita à apresentação e navegação dos cinco cartões; não encerra critérios funcionais mais amplos da matriz.",
"layoutRevision": {
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: título a vermelho e menos espaço em branco dentro dos cartões.",
"changes": "Título no vermelho #ed1c24; removidas alturas mínimas de título e descrição; preenchimento 20→16 px, intervalo 8→6 px e entrelinhas 28/24→24/20 px. Mantidos imagens, conteúdos, links e alinhamento por linha da grelha.",
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 320,
"height": 180
}
],
"status": "passed"
},
{
"width": 390,
"dpr": 2,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 389,
"height": 219
}
],
"status": "passed"
},
{
"width": 768,
"dpr": 1,
"columns": 2,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 384,
"height": 216
}
],
"status": "passed"
},
{
"width": 1024,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 256,
"height": 144
}
],
"status": "passed"
},
{
"width": 1440,
"dpr": 2,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"width": 1920,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
}
],
"errors": [],
"navigation": [
"/clusters",
"/corredores",
"/projectos-ancora",
"/educacao",
"/documentos"
],
"databaseAccess": false
},
"lintExitCode": 0,
"buildExitCode": 0,
"pageAsset": "assets/PortalInvestidor-CYCMhSzW.js",
"screenshots": [
"outputs/investment-context-compact-20261023/cards-1024-dpr1.png",
"outputs/investment-context-compact-20261023/cards-1440-dpr2.png",
"outputs/investment-context-compact-20261023/cards-1920-dpr1.png",
"outputs/investment-context-compact-20261023/cards-320-dpr1.png",
"outputs/investment-context-compact-20261023/cards-390-dpr2.png",
"outputs/investment-context-compact-20261023/cards-768-dpr1.png"
],
"databaseChanged": false
}
}
@@ -0,0 +1,355 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: adaptar hero, imagens e pesquisa da referência, preservando a informação e os comportamentos equivalentes do V2.",
"sourceProject": "D:/Projects/Tempo_Investidor/investidor",
"targetProject": "D:/Projects/Tempo_Investidor/Investidor-V2",
"planAndAnalysis": "docs/investmoz/public-portal-sections.md#adequação-do-hero--23102026",
"implementation": [
"resources/js/components/portal-hero.tsx",
"resources/js/pages/PortalInvestidor.tsx"
],
"assets": [
{
"source": "D:\\Projects\\Tempo_Investidor\\investidor\\public\\images\\hero\\hero-1.png",
"original": "public\\images\\hero\\hero-1.png",
"sha256": "3c9246169025b9b1b4d1d10fb51c1f644123984bde56c6c2d9bf869d851024fc",
"bytes": 2315768,
"webpBytes": 94012,
"mobileBytes": 38804
},
{
"source": "D:\\Projects\\Tempo_Investidor\\investidor\\public\\images\\hero\\hero-3.jpg",
"original": "public\\images\\hero\\hero-3.jpg",
"sha256": "91377213b6286aca7ee4af90860a7dc7a75fa08a165ef7b3192081db43f92dff",
"bytes": 9875137,
"webpBytes": 140342,
"mobileBytes": 32998
}
],
"desktopBytesTotal": 234354,
"mobileBytesTotal": 71802,
"originalBytesTotal": 12190905,
"verification": {
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"browserScript": "tools/portal-hero-qa.mjs",
"screenshots": [
"outputs/portal-hero-20261023/after-1440-no-preference.png",
"outputs/portal-hero-20261023/after-1440-reduce.png",
"outputs/portal-hero-20261023/after-1440-second-image.png",
"outputs/portal-hero-20261023/after-1920-reduce.png",
"outputs/portal-hero-20261023/after-320-reduce.png",
"outputs/portal-hero-20261023/after-390-reduce.png",
"outputs/portal-hero-20261023/after-768-reduce.png",
"outputs/portal-hero-20261023/before-1440-reduce.png",
"outputs/portal-hero-20261023/before-390-reduce.png"
],
"additionalCases": [
"pesquisa por Enter e botão",
"ordem do teclado: campo → botão",
"query acentuada e pontuação preservadas",
"remoção de espaços exteriores",
"pesquisa vazia abre catálogo",
"CTA abre oportunidades",
"API indisponível mantém indicadores indeterminados",
"contagens zero preservadas",
"duas imagens carregadas",
"selecção manual",
"pausa e retoma explícitas",
"foco pausa rotação",
"rotação automática após perda de foco",
"movimento reduzido",
"entrada documental e cabeçalho preservados"
],
"existingFrontendTests": {
"command": "node --test tests/frontend/portal-api.test.mjs tests/frontend/portal-navigation.test.mjs",
"passed": 20
},
"typecheck": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"files": [
"resources/js/components/portal-hero.tsx",
"resources/js/pages/PortalInvestidor.tsx",
"tools/portal-hero-qa.mjs"
],
"exitCode": 0
},
"qaBuild": {
"command": "INVESTMOZ_QA_BUILD=1 npm run build",
"exitCode": 0
},
"localBuild": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-MsUeKoJQ.js"
}
},
"matrix": {
"file": "docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
"referencesAdded": [
"MASTER-9dee08d0-0016",
"MASTER-efd550fd-0104",
"MASTER-55050f60-0001"
],
"rowCount": 3422,
"criteriaAndStatesPreserved": true
},
"scope": {
"appliedToLocalCodeAndBuild": true,
"activeDatabaseChanged": false,
"migrationsRun": false,
"externalDeploymentPerformed": false,
"backendSearchReimplemented": false
},
"limits": "Verificação visual com dados sintéticos; pesquisa continua limitada ao catálogo de oportunidades. Os critérios mais amplos da matriz permanecem no estado anterior.",
"latestRevision": {
"id": "hero-no-controls-20261023",
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: remover do hero as duas bolinhas e o botão de pausa das imagens.",
"implementation": "Removidos grupo de controlos, ícones Pause/Play e estado de pausa manual. Preservadas troca automática, escrita dinâmica, pesquisa e preferência de movimento reduzido.",
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "no-preference",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"screenshots": [
"outputs/portal-hero-no-controls-20261023/after-1440-no-preference.png",
"outputs/portal-hero-no-controls-20261023/after-1440-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-1920-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-320-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-390-no-preference.png",
"outputs/portal-hero-no-controls-20261023/after-390-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-768-reduce.png",
"outputs/portal-hero-no-controls-20261023/second-image-1440.png",
"outputs/portal-hero-no-controls-20261023/second-image-390.png",
"outputs/portal-hero-no-controls-20261023/typed-1440.png",
"outputs/portal-hero-no-controls-20261023/typed-390.png"
],
"checks": {
"lintExitCode": 0,
"buildExitCode": 0,
"pageAsset": "assets/PortalInvestidor-T0B6aoV_.js"
},
"scope": {
"appliedLocally": true,
"databaseAccess": false,
"externalDeployment": false
}
},
"revisionHistory": [
{
"id": "hero-typing-20261023",
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: título e frase dinâmicos como na referência; remover Termos de uso do hero.",
"plan": [
"Analisar a sequência de escrita da referência.",
"Animar o título e depois a frase, mantendo os textos do V2 e reservando a dimensão final.",
"Reiniciar a escrita na troca de imagem e integrar pausa/retoma e preferência de movimento reduzido.",
"Remover o link e o ícone jurídico do hero.",
"Demonstrar comportamento em computador e telemóvel e compilar o pacote local."
],
"files": [
"resources/js/components/portal-hero.tsx",
"resources/css/app.css",
"tools/portal-hero-qa.mjs"
],
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "no-preference",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"screenshots": [
"outputs/portal-hero-typing-20261023/after-1440-no-preference.png",
"outputs/portal-hero-typing-20261023/after-1440-reduce.png",
"outputs/portal-hero-typing-20261023/after-1440-second-image.png",
"outputs/portal-hero-typing-20261023/after-1920-reduce.png",
"outputs/portal-hero-typing-20261023/after-320-reduce.png",
"outputs/portal-hero-typing-20261023/after-390-no-preference.png",
"outputs/portal-hero-typing-20261023/after-390-reduce.png",
"outputs/portal-hero-typing-20261023/after-768-reduce.png",
"outputs/portal-hero-typing-20261023/typed-1440.png",
"outputs/portal-hero-typing-20261023/typed-390.png",
"outputs/portal-hero-typing-20261023/typing-1440.png",
"outputs/portal-hero-typing-20261023/typing-390.png"
],
"demonstrated": [
"escrita progressiva",
"título antes da frase",
"texto completo no modo de movimento reduzido",
"nome acessível completo durante a escrita",
"pesquisa sem deslocamento durante a escrita",
"reinício na selecção manual e automática de imagem",
"pausa e retoma da escrita",
"cursor com pausa",
"Termos de uso ausente do hero",
"pesquisa, teclado, CTA, API indisponível e contagens zero preservados"
],
"checks": {
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"command": "vp lint resources/js/components/portal-hero.tsx tools/portal-hero-qa.mjs",
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-BbVHeTeI.js",
"log": "outputs/portal-hero-typing-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"databaseAccess": false,
"externalDeployment": false
}
}
]
}
+88
View File
@@ -48,3 +48,91 @@ Edge headless: 11 páginas públicas/autenticação verificadas a 390×844, com
Página inicial também verificada a 1440×1000. Cenário fiscal exercitado no navegador: base 1.000 × taxa 10% × (1 − redução 50%) = 50. Resultados em `public-portal-browser-validation.json`.
Antes da migration local foi criado e restaurado o backup de 74 tabelas em `storage/app/private/portal-services-backup-20260927-090641/`. O backup completo anterior permanece em `C:/laragon/backups/portal-investidor-20260927-101224/` e representa o estado anterior a esta entrega.
## Adequação do hero — 23/10/2026
Origem: pedido expresso da Tempo nesta sessão para aproveitar o hero, as imagens e a barra de pesquisa de `D:/Projects/Tempo_Investidor/investidor`, usando a informação existente no V2. Aplicam-se as orientações permanentes do `AGENTS.md`, incluindo a distinção entre decisão da Tempo e escolha técnica, a preservação de dados e a separação de QA e activo.
Análise prévia: a página de entrada real do V2 é `PortalInvestidor.tsx`, servida por `PortalServicesController::home`. A referência é `domains/investor-portal/components/homepage/homepage-hero.tsx`, montada em `InstitutionalHomepage`. A referência usa Inertia 2, Framer Motion, tradução e navegação diferentes; o V2 usa Inertia 3 e pesquisa de oportunidades. Copiar essas dependências e `/pesquisa` ou `/aviso-legal` directamente criaria incompatibilidades e destinos inexistentes.
Plano executado:
1. Registar a apresentação anterior em computador e telemóvel, com os componentes reais e dados sintéticos.
2. Copiar os dois originais efectivamente usados pela referência (`hero-1.png` e `hero-3.jpg`), conferir SHA-256 e gerar derivados WebP para computador e telemóvel. `hero-2.png` não faz parte da rotação da referência.
3. Extrair `components/portal-hero.tsx` e aplicar fotografias em rotação, texto centrado e pesquisa branca com botão vermelho. Preservar os textos do V2, contagens da API, sectores, documentos, apoio, cabeçalho e rodapé.
4. Manter a pesquisa de oportunidades em `/oportunidades?q=`, incluindo pesquisa vazia e caracteres acentuados. Conservar “Consultar oportunidades” e “Planear finanças”. A primeira iteração acrescentou o acesso jurídico `/termos-de-uso` ao hero; foi removido na revisão expressamente pedida pela Tempo abaixo.
5. Verificar apresentação, teclado, imagens, rotação, pausa, movimento reduzido, falha da API, contagens zero, TypeScript, lint e compilação. Compilar primeiro o pacote QA e depois os assets locais em `public/build`.
Escolhas técnicas desta adaptação: React e transições CSS existentes, sem novas dependências; rotação de oito segundos, pausa por controlo explícito, foco, ponteiro ou separador oculto; apresentação estática quando o utilizador pede movimento reduzido. A primeira iteração apresentou o texto estático; a revisão abaixo introduz a escrita dinâmica pedida pela Tempo. O campo indica pesquisa de oportunidades e conserva exemplos que o catálogo suporta; esta alteração não implementa uma pesquisa global de legislação/licenciamento.
Evidência reproduzível: `tools/portal-hero-qa.mjs`, com Vite local e Playwright configurável por `HERO_QA_PLAYWRIGHT`/`HERO_QA_CHROMIUM`. Fixtures e capturas em `outputs/portal-hero-20261023/`; síntese persistente em `public-portal-hero-validation.json`. Os testes de interface interceptam a API e a navegação Inertia, sem acesso a Laravel, base de dados ou serviços externos. A compilação local aplica os assets desta pasta; não representa publicação noutro servidor.
Referências na matriz existente: `MASTER-efd550fd-0104` (composição da página), `MASTER-9dee08d0-0016` (contexto da pesquisa) e `MASTER-55050f60-0001` (entrada documental preservada). Esta prova cobre a adaptação visual e os percursos exercitados; não encerra os critérios funcionais mais amplos dessas linhas.
### Revisão: escrita dinâmica e remoção do acesso jurídico no hero
Decisão expressa da Tempo na continuação da sessão de 23/10/2026: animar “INVISTA EM MOÇAMBIQUE” e “Transforme informação em decisões e ideias em negócios reais.” como na página de referência, e remover “Termos de uso” do hero. A anterior apresentação estática e a inclusão desse link eram escolhas de implementação, agora substituídas pelo pedido do proprietário.
Análise e plano executado: reproduzir a sequência da referência (espera inicial de 250 ms, título a 50 ms por carácter, intervalo de 150 ms e frase a 28 ms por carácter); reiniciar ao trocar de imagem; acrescentar o cursor intermitente; reservar a dimensão final de ambas as linhas para manter a pesquisa imóvel; remover o link e o ícone jurídico do hero; verificar em computador e telemóvel e compilar o pacote local.
Implementação em `portal-hero.tsx`, com React existente e CSS do cursor em `app.css`, sem dependências novas. A pausa explícita suspende também a escrita, retomando do mesmo ponto. Quando o separador fica oculto a escrita pára; a preferência de movimento reduzido apresenta os dois textos completos. Leitores de ecrã recebem o texto completo uma única vez, independentemente do número de caracteres visíveis. Os temporizadores são limpos ao mudar de imagem ou desmontar o componente.
O script `tools/portal-hero-qa.mjs` demonstra a escrita progressiva, a ordem título→frase, o reinício manual/automático, a pausa/retoma, a posição estável da pesquisa, o modo sem movimento e a ausência de “Termos de uso” no hero. As capturas e resultados desta revisão ficam em `outputs/portal-hero-typing-20261023/`, preservando a evidência anterior. Síntese e compilação final registadas na revisão de `public-portal-hero-validation.json`; referência acrescentada à linha existente `MASTER-efd550fd-0104`, sem encerrar o seu critério mais amplo.
### Revisão: remoção dos controlos visíveis das imagens
Pedido expresso da Tempo na continuação de 23/10/2026: remover do hero o grupo com o botão de pausa e as duas bolinhas de selecção de imagem. Removidos o grupo, os ícones e o estado de pausa manual. A troca automática de imagens e a escrita dinâmica permanecem; conservam-se a pausa da rotação por foco/ponteiro, a suspensão em separador oculto e a preferência de movimento reduzido. Esta decisão substitui os controlos visíveis introduzidos como escolha de implementação nas revisões anteriores.
O script existente de interface foi adaptado para demonstrar a ausência dos controlos e a continuação da rotação automática, escrita e pesquisa, com capturas em `outputs/portal-hero-no-controls-20261023/`. Evidência e pacote local registados em `public-portal-hero-validation.json`, mantendo o histórico das revisões e os estados dos requisitos da matriz.
## Fotografias nas etapas de Como Investir — 23/10/2026
Origem: pedido expresso da Tempo para analisar e ilustrar exclusivamente os cartões “1. Explorar”, “2. Preparar” e “3. Acompanhar”. Aplicam-se as orientações permanentes de `AGENTS.md` de 12/10 e 22/10/2026; componentes e optimização de recursos são escolhas técnicas, sem novas regras operacionais.
Análise e plano: os cartões existentes são âncoras estáticas na home React/Inertia, numa grelha de três colunas a partir de 768 px. Explorar liga a `/oportunidades` e representa a identificação de sector, território e oportunidade; Preparar liga a `/como-investir` e representa percurso/documentação; Acompanhar liga a `/balcao-virtual` e representa envio/consulta de pedido e protocolo. Os recursos locais existentes ilustram outras secções; preparar três fotografias distintas para evitar repetição. Gerar cenas editoriais plausíveis com `imagegen`, rever composição, guardar originais e versões WebP locais, integrar imagens 16:9 com dimensões reservadas e carregamento diferido, manter textos/destinos/título vermelho, verificar comportamento responsivo, navegação e falhas de imagem, compilar. Âmbito exclusivamente visual, sem alterações em dados, autenticação, apoio ou rodapé. Referência documental na linha existente `MASTER-efd550fd-0104`, sem criar outra matriz nem encerrar o critério mais amplo.
Implementação: `components/investment-steps.tsx` reúne os três cartões, preservando títulos, descrições e âncoras. Fotografias individuais geradas com a ferramenta integrada `image_gen`, sem local ou projecto real atribuído: avaliação de oportunidade num parque empresarial genérico, preparação documental numa reunião e consulta de pedido no computador. Originais em `outputs/investment-steps-20261023/originals/`; recursos locais em `public/images/investment-steps/` com WebP 960×540, 480×270 e alternativa própria 240×135. Os cartões usam `srcset`, `sizes`, `loading="lazy"`, dimensões reservadas, corte 16:9, alt em português, foco visível e texto compacto com 16 px de preenchimento. Se também falhar a alternativa pequena, o cartão mantém a área reservada, descrição acessível e destino utilizável.
Verificação desta secção: componentes reais com API sintética e sem base de dados, seis larguras de 320 a 1920 px, duas densidades de ecrã, três imagens distintas, texto/destinos conservados, navegação por teclado, ausência de transbordo e deslocamento no carregamento, falhas dos recursos principais e de todos os recursos. Oito cenários sem erros JavaScript. Fotografias, prompts, hashes, capturas, relatório de browser e compilação documentados em `public-portal-steps-images.json` e `outputs/investment-steps-20261023/`. Ajuste restrito a esta secção; apoio, acesso à gestão e rodapé mantidos.
## Fotografias nos cartões de contexto do investimento — 23/10/2026
Origem: pedido expresso da Tempo para aplicar o anexo “Melhorar as imagens e a identidade visual do Portal do Investidor de Moçambique” exclusivamente à secção “Encontre o contexto do seu investimento”. O anexo define estética fotográfica editorial, imagens individuais contextualizadas, recursos locais, acessibilidade, desempenho e preservação dos cinco destinos e conteúdos. Aplicam-se as orientações permanentes de `AGENTS.md` de 12/10 e 22/10/2026; os pormenores de implementação abaixo são escolhas técnicas.
Análise prévia: Laravel/Inertia 3 e React, com Tailwind existente; os cinco cartões estavam embutidos em `pages/PortalInvestidor.tsx`. `EducationalArticleCard` destina-se a artigos com acções e metadados diferentes, pelo que não foi alterado. A secção foi extraída para `components/investment-context-cards.tsx`, mantendo o título, descrições, âncoras e grelha de uma/duas/quatro colunas. Não foram alteradas as páginas de destino, dados, APIs ou estilos globais.
Foram geradas cinco imagens distintas com a ferramenta integrada `image_gen`, segundo a skill `imagegen`: agro-indústria, terminal logístico, acompanhamento de instalação solar, formação técnica e análise documental. São imagens fotográficas ilustrativas geradas, sem localização ou instituição real atribuída, e não fotografias documentais de projectos cadastrados. A imagem do terminal foi revista para remover o camião com marca visível. Não foram usadas fotografias externas nem URLs de serviços de imagens. Originais seleccionados, prompts e hashes estão registados no manifesto `public-portal-context-images.json`; os originais foram preservados dentro do workspace.
Recursos finais em `public/images/investment-context/`: `clusters-agroindustria`, `corredores-logisticos-v2`, `projectos-ancora`, `educacao-formacao` e `documentos-formularios`, em WebP 960×540, com variantes 480×270 e alternativas 240×135. As imagens mantêm 16:9, `object-cover`, textos alternativos em português, dimensões reservadas, `srcset`, `sizes`, `loading="lazy"` e descodificação assíncrona. Cada cartão conserva o seu título e descrição; o foco usa o azul e os tons neutros pedidos no anexo.
Se um recurso principal falhar, o cartão usa a sua própria variante pequena, evitando repetir a fotografia de outra secção. Se também essa falhar, apresenta “Imagem indisponível” no mesmo espaço reservado, com descrição acessível e link operacional. Este é apenas um estado de erro; os cinco cartões usam imagens fotográficas na apresentação normal.
Verificação reproduzível: `tools/portal-context-cards-qa.mjs`, com o portal e cabeçalho reais, API sintética e acesso exclusivo aos recursos locais. Exercita seis larguras de ecrã, ecrãs de alta densidade, os cinco destinos por teclado, imagens carregadas e distintas, alinhamento, dimensões, ausência de deslocamento no carregamento e dois cenários de falha. Capturas e resultados em `outputs/investment-context-20261023/`; síntese, fontes/prompts e compilação em `public-portal-context-images.json`. Referências acrescentadas às linhas existentes `MASTER-efd550fd-0104` e `MASTER-55050f60-0001`, sem encerrar os respectivos critérios mais amplos.
Revisão expressa da Tempo de 23/10/2026: título da secção no vermelho da identidade existente (`#ed1c24`) e cartões mais compactos. Removidas as alturas mínimas de 56 e 72 px do título/descrição; reduzidos o preenchimento de 20 para 16 px, o intervalo de 8 para 6 px e as entrelinhas. As alturas passam a acompanhar o conteúdo, com alinhamento por linha da grelha, conservando imagens, textos e destinos. A reserva das dimensões das imagens mantém-se. Evidência desta revisão em `outputs/investment-context-compact-20261023/` e no campo `layoutRevision` do manifesto existente.
## Sectores da home e catálogo completo — 23/10/2026
Origem: pedido expresso da Tempo para adaptar a estrutura de “Áreas de Investimento” do projecto `D:/Projects/Tempo_Investidor/tempo-dashboard`, incluindo cartões, botão para mais sectores e respectiva página, e uniformizar a vermelho os títulos das secções da home. Aplicadas as orientações permanentes `AGENTS.md` de 12/10 e 22/10/2026: as decisões de produto são da Tempo; as escolhas técnicas abaixo não criam requisitos organizacionais.
Análise prévia: a referência usa `components/investor-portal/homepage/homepage-sectors.tsx` e `pages/investor-portal/sectors/index.tsx`. Mostra cinco cartões com fotografia e título sobreposto, resumo, “Saiba mais” e ligação central arredondada para o catálogo. O V2 já dispunha de `/sectores`, fichas `/sectores/{slug}`, especialização Fintech e dados de `SectorOrganization`. Foram reutilizados esses contratos e percursos, sem importar Framer Motion, traduções ou rotas exclusivas da referência.
Implementação: `components/public-sector-cards.tsx` partilha os cartões entre a home e o catálogo. A home mostra os primeiros cinco sectores, na ordem recebida da API, com “Ler mais” para a ficha existente e “Ver mais sectores” para `/sectores`. A página existente apresenta todos os sectores publicados, na mesma estrutura visual, e “Voltar ao início”. Mantêm-se nomes, descrições, contagens, valores zero, especializações e URLs canónicos recebidos. Descrições ausentes não são preenchidas com dados da referência. Fintech permanece ligado à ficha própria, sem âncoras HTML aninhadas.
Foram inventariados os onze JPG disponíveis em `storage/app/public/investor-portal/sectors` na referência, copiados os originais para evidência e preparados derivados locais WebP 960×540/480×270 em `public/images/sectors/`. O mapeamento visual por slug é de apresentação e não altera a taxonomia. Para Imobiliário e sectores sem imagem específica usa-se a vista empresarial genérica disponível na referência; para Bens de Consumo e Franquias usa-se a imagem de actividade industrial. A variante genérica também serve como alternativa em caso de erro; se ambas falharem, o título e as ligações continuam visíveis num fundo neutro. Não se atribui aos ficheiros uma origem oficial, licença externa ou localização documental não comprovada.
Os seis títulos de secção da home — contexto do investimento, sectores, Como Investir, oportunidades em destaque, documentos essenciais e apoio — usam `HOME_SECTION_HEADING` em `lib/portal-presentation.ts`: vermelho `#ed1c24`, 24 px, entrelinha de 32 px e peso 700. O cartão de Apoio passou a superfície clara para manter contraste com o título vermelho. O título principal animado do hero mantém a sua hierarquia própria. `PORTAL_MORE_LINK` centraliza o botão arredondado, contorno vermelho e estado de foco, seguindo a referência.
Verificação: `tools/portal-home-sectors-qa.mjs` carrega os componentes reais com dez sectores sintéticos, descrições nulas e especialização Fintech, sem base de dados. Exercita seis larguras, prévia de cinco/cartálogo de dez, estilos dos seis títulos, percurso por teclado, dez fichas, Fintech, regresso à home, catálogo vazio e dois cenários de indisponibilidade de imagens. Capturas, inventário, hashes e resultados em `outputs/home-sectors-20261023/`; resumo persistente em `public-portal-sectors-validation.json`. Referências na matriz existente: `MASTER-efd550fd-0104` e `MASTER-9f5719c8-0077`. Esta adaptação não encerra critérios mais amplos nem altera dados, permissões, regras operacionais ou publicação noutro servidor.
Pedido expresso da Tempo, 23/10/2026 — botão “Contactar Apoio ao Investidor”: em `layouts/portal-navigation.tsx`, a faixa de largura total foi substituída por um botão centrado, com largura ajustada ao texto, altura mínima de 44 px, preenchimento reduzido, sombra discreta e vermelho `#ed1c24`, conservando `/apoio` e o foco visível. Verificado a 320, 390 e 1440 px: cerca de 223×44 px, sem transbordo ou erros JavaScript. Evidência em `outputs/support-button-20261023/qa-results.json` e capturas; compilação local no mesmo directório. Ajuste de apresentação por decisão do proprietário, sem nova regra operacional nem alteração de dados.
Revisão anterior de 23/10/2026, superada pela correcção de âmbito abaixo: o Codex interpretou o pedido de abreviação como aplicável à zona inferior inteira e alterou indevidamente o botão de apoio e o rodapé partilhado. Essa interpretação não foi uma decisão da Tempo. A revisão removeu o bloco interno, abreviou o botão para “Apoio” e recolheu contactos/ligações em “Informações” num rodapé claro; estas alterações fora do bloco indicado foram revertidas após a clarificação expressa do proprietário. O registo desta revisão é histórico e não descreve a apresentação actual.
Evidência histórica da revisão superada: `outputs/footer-compact-20261023/qa-results.json`, capturas e `check.mjs`. Não constitui aceitação do âmbito pelo proprietário.
Correcção expressa da Tempo, 23/10/2026: o pedido abrange exclusivamente o bloco “INVESTE Moçambique / Portal do Investidor — conheça as oportunidades… / Acesso à gestão”. Em `pages/PortalInvestidor.tsx`, esse bloco fica abreviado num ícone de acesso à gestão, com nome acessível e descrição “Acesso à gestão”, destino `/acesso-gestao`, área de interacção de 44 px e fundo branco, sem o título e parágrafo anteriores. O botão de apoio foi restaurado exactamente à apresentação anterior à abreviação: “Contactar Apoio ao Investidor”, compacto, vermelho e sem ícone. `components/tempo-footer.tsx` e os estilos `.tempo-footer` foram integralmente restaurados ao estado anterior, incluindo contactos e ligações visíveis e o fundo original do rodapé geral. Não se altera autenticação nem dados. Esta correcção substitui a interpretação indevida acima e mantém as restantes alterações previamente pedidas.
Evidência da correcção: `outputs/footer-scope-correction-20261023/check.mjs`, `qa-results.json`, capturas e `build-local.log`; componentes reais com API sintética a 320, 390 e 1440 px, ícone de gestão focável, bloco específico claro sem parágrafo, botão de apoio completo/vermelho, rodapé geral restaurado, contactos e ligações legais visíveis, sem transbordo ou erros JavaScript. Lint dos componentes alterados e compilação local. Referência na linha existente `MASTER-efd550fd-0104`, sem encerramento do critério amplo nem alteração dos seus estados.
Continuação expressa da Tempo, 23/10/2026: acrescentado o título visível “Acesso à gestão” ao lado do ícone nesse mesmo bloco, para tornar o destino compreensível. O acesso mantém-se compacto, vermelho e com fundo claro, conservando `/acesso-gestao`. Ajuste restrito a essa ligação; apoio e rodapé geral conservam a apresentação restaurada. Referência: `MASTER-efd550fd-0104` e a evidência da revisão anterior acima. Verificado a 320, 390 e 1440 px, sem transbordo ou erros JavaScript; lint e compilação aprovados. Evidência em `outputs/management-label-20261023/qa-results.json`, capturas e `build-local.log`. No pedido seguinte, a Tempo determinou o alinhamento desse acesso à esquerda; aplicado `justify-start` apenas no seu contentor.
@@ -0,0 +1,748 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: adaptar Áreas de Investimento do tempo-dashboard aos sectores da home e ao catálogo completo, copiar a estrutura dos botões e uniformizar a vermelho os títulos de secção da home.",
"reference": {
"project": "D:/Projects/Tempo_Investidor/tempo-dashboard",
"files": [
"resources/js/components/investor-portal/homepage/homepage-sectors.tsx",
"resources/js/pages/investor-portal/sectors/index.tsx"
],
"structure": "Cinco cartões com fotografia, título sobreposto, resumo e acção de leitura; botão central arredondado/contorno vermelho para o catálogo."
},
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#sectores-da-home-e-catálogo-completo--23102026",
"filesChanged": [
"resources/js/components/public-sector-cards.tsx",
"resources/js/lib/portal-presentation.ts",
"resources/js/components/investment-context-cards.tsx",
"resources/js/lib/portal-api.ts",
"resources/js/pages/PortalInvestidor.tsx",
"resources/js/pages/portal/services.tsx",
"tools/portal-home-sectors-qa.mjs",
"docs/investmoz/public-portal-sections.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv"
],
"behaviour": {
"homePreview": 5,
"previewOrder": "Ordem recebida da API, sem novos filtros de publicação.",
"readMore": "Ler mais, para a URL recebida ou ficha existente /sectores/{slug}.",
"moreSectors": "Ver mais sectores, botão arredondado para /sectores.",
"catalogue": "Todos os sectores publicados devolvidos pelo cadastro existente; Voltar ao início para /.",
"specializations": "Fintech conservado como ligação própria; sem âncoras aninhadas.",
"countsAndDescriptions": "Preservados dados recebidos, incluindo zero e descrições ausentes; não importados textos ou registos do outro projecto.",
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"supportCard": "Superfície clara para contraste com o título vermelho."
},
"assets": [
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\agronegocio.jpg",
"sourceBytes": 444057,
"original": "outputs/home-sectors-20261023/originals/agronegocio.jpg",
"sha256": "7337b689a6ad8b0b4c8d716ea356db14e22bd2982089825bb2382121ed3482f6",
"derivatives": [
{
"file": "public/images/sectors/agronegocio.webp",
"width": 960,
"height": 540,
"bytes": 110310,
"sha256": "3e9d3be22556300f880be39837f86e764e3d05433beff1da6694ef6cee1d5c34"
},
{
"file": "public/images/sectors/agronegocio-480.webp",
"width": 480,
"height": 270,
"bytes": 31592,
"sha256": "fd1f7624f7fd9224fc1c7bd11746806e419c645ba43c257b1edd9ba250cd47f1"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\economia-azul.jpg",
"sourceBytes": 456892,
"original": "outputs/home-sectors-20261023/originals/economia-azul.jpg",
"sha256": "1a2c04d0d9ed4a26129553daefd2ee18f6d820026ab1203acf3bcf91b0550f69",
"derivatives": [
{
"file": "public/images/sectors/economia-azul.webp",
"width": 960,
"height": 540,
"bytes": 107626,
"sha256": "bf3751e66839c1b3c585c91ffe65d32b9ee79ebd7d08e5e2c95c6cd581b04f8f"
},
{
"file": "public/images/sectors/economia-azul-480.webp",
"width": 480,
"height": 270,
"bytes": 29350,
"sha256": "aaf8ee66709d8e15c4304690dd03830b4368d14468a597d5617ccdb71d614331"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\energia.jpg",
"sourceBytes": 386678,
"original": "outputs/home-sectors-20261023/originals/energia.jpg",
"sha256": "a164e2c8ef155a6a198ae400feca132e79ba75e022473893ec48ebfa0557f679",
"derivatives": [
{
"file": "public/images/sectors/energia.webp",
"width": 960,
"height": 540,
"bytes": 81236,
"sha256": "b5605d9bb8645c5042baa511aaf39fcb187080a48d8e067b130fc974c4c9196d"
},
{
"file": "public/images/sectors/energia-480.webp",
"width": 480,
"height": 270,
"bytes": 21926,
"sha256": "7e53977fc6ce11755455f8092ac3f8c7126f54d909a3935e522f8dae0ab834be"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\industria.jpg",
"sourceBytes": 357131,
"original": "outputs/home-sectors-20261023/originals/industria.jpg",
"sha256": "d70c4257ac58a4b5e9f8b8b1a4cf6d98c0514043442c3ce46f5c98399038527f",
"derivatives": [
{
"file": "public/images/sectors/industria.webp",
"width": 960,
"height": 540,
"bytes": 80422,
"sha256": "ca8ddd2d65647f1ed7a9906271fa2ea3d027f310b89434fd7781a37a3d18322d"
},
{
"file": "public/images/sectors/industria-480.webp",
"width": 480,
"height": 270,
"bytes": 25194,
"sha256": "8bd695231209c0042b94e68b0e2095fa7202297708dabff0f78b337500b8c9b7"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\infraestruturas.jpg",
"sourceBytes": 395383,
"original": "outputs/home-sectors-20261023/originals/infraestruturas.jpg",
"sha256": "ac6cde89507af68991faebee19540f955146724d3be901839b85a4098fe1674b",
"derivatives": [
{
"file": "public/images/sectors/infraestruturas.webp",
"width": 960,
"height": 540,
"bytes": 86654,
"sha256": "14754a59477e5c62a62c190be812c89d9616608b3c98acb6100ad70d94d34df0"
},
{
"file": "public/images/sectors/infraestruturas-480.webp",
"width": 480,
"height": 270,
"bytes": 25772,
"sha256": "eca58096087d05dae3eea2b4d063c103f9fc85b0ea20fc5051313cf9bfa1020f"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\logistica-transportes.jpg",
"sourceBytes": 413702,
"original": "outputs/home-sectors-20261023/originals/logistica-transportes.jpg",
"sha256": "5976ead23da0d4e7d5debf875262f0229d389826aaeb7e7be4ebbac3f5129a9e",
"derivatives": [
{
"file": "public/images/sectors/logistica-transportes.webp",
"width": 960,
"height": 540,
"bytes": 96254,
"sha256": "0d235e7bbd160cccd3f97daa3337d6b27fde49db9782ad2ba0599c6a83022b6c"
},
{
"file": "public/images/sectors/logistica-transportes-480.webp",
"width": 480,
"height": 270,
"bytes": 28816,
"sha256": "32f5137e0a7f6a7894b186edb2ca38f12cdfdca04dda3588de3969fb3d2e333a"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\mineracao.jpg",
"sourceBytes": 415161,
"original": "outputs/home-sectors-20261023/originals/mineracao.jpg",
"sha256": "7e6d1e5a17d434456ad937680a6c5501bd33bd624d2cc7ebf4b643185a9440aa",
"derivatives": [
{
"file": "public/images/sectors/mineracao.webp",
"width": 960,
"height": 540,
"bytes": 96642,
"sha256": "12c93df378f54108b13260c10d29789564af7844cc84bcd9281d2be917d83354"
},
{
"file": "public/images/sectors/mineracao-480.webp",
"width": 480,
"height": 270,
"bytes": 26034,
"sha256": "be3e7763fb8cd2e02f576204269821c40d93a7c155d8088a5084064b7269e4d6"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\outros-sectores.jpg",
"sourceBytes": 328152,
"original": "outputs/home-sectors-20261023/originals/outros-sectores.jpg",
"sha256": "4aaac0869dc7e61c4c7a87e1af95beb108aa9be0da082702f6f70722e62b1e7a",
"derivatives": [
{
"file": "public/images/sectors/outros-sectores.webp",
"width": 960,
"height": 540,
"bytes": 75414,
"sha256": "f47b3d0da5b0cd5153d393c6f779484ba89043e50195e968338108e893a88077"
},
{
"file": "public/images/sectors/outros-sectores-480.webp",
"width": 480,
"height": 270,
"bytes": 24936,
"sha256": "a4fc00551d75c96a1648ad4f81d759d4d6ecd7e6fc5689689216a96934bd1ea2"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\servicos-financeiros.jpg",
"sourceBytes": 348386,
"original": "outputs/home-sectors-20261023/originals/servicos-financeiros.jpg",
"sha256": "f932a56248d5544bff92aa30f4af3a5a63044c311969d4370d06f157b097d570",
"derivatives": [
{
"file": "public/images/sectors/servicos-financeiros.webp",
"width": 960,
"height": 540,
"bytes": 72144,
"sha256": "15379485db7de7b2efebe8bdbd4cbd8e911eb34ab8a23b3dd114c849bb4ae65c"
},
{
"file": "public/images/sectors/servicos-financeiros-480.webp",
"width": 480,
"height": 270,
"bytes": 20698,
"sha256": "c21949201e35e63625d3d2e7520e10912fe65be1186954142b2784f6efca51ed"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\tic-economia-digital.jpg",
"sourceBytes": 417398,
"original": "outputs/home-sectors-20261023/originals/tic-economia-digital.jpg",
"sha256": "b09703bd079f55fb5a8ec3167ce96e1fdb1e5090813a81c817b9a33909427d94",
"derivatives": [
{
"file": "public/images/sectors/tic-economia-digital.webp",
"width": 960,
"height": 540,
"bytes": 97892,
"sha256": "b1d79c1a941085582d6a72799140bafed1bf38ec0201a4dfe5f6faf54ea55ae8"
},
{
"file": "public/images/sectors/tic-economia-digital-480.webp",
"width": 480,
"height": 270,
"bytes": 28242,
"sha256": "c4279a27ed402ca2feb62f11a8a954cbcae993912d3c8c27a2d9644fdf922114"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\turismo.jpg",
"sourceBytes": 393339,
"original": "outputs/home-sectors-20261023/originals/turismo.jpg",
"sha256": "1a76db252bc8c1a9dc1f3c650bd95e55337c36a6f604753d61cad96c19b1875f",
"derivatives": [
{
"file": "public/images/sectors/turismo.webp",
"width": 960,
"height": 540,
"bytes": 93234,
"sha256": "de46707dfdd8b98c48ec88d19f3df0b1d6c130adfcbd97d5a7c2e6fa2db62bef"
},
{
"file": "public/images/sectors/turismo-480.webp",
"width": 480,
"height": 270,
"bytes": 27012,
"sha256": "4d3d9a04b9426474dca9ba8895021b48fffbe7e4d4a4551272b8c832cf83488e"
}
]
}
],
"assetMapping": {
"agronegocio": "agronegocio",
"turismo": "turismo",
"infraestruturas": "infraestruturas",
"economia-azul": "economia-azul",
"mercado-financeiro": "servicos-financeiros",
"mineracao": "mineracao",
"energia-especifica": "energia",
"imobiliario": "outros-sectores",
"bens-de-consumo-e-franquias": "industria",
"tecnologias-de-informacao": "tic-economia-digital"
},
"assetSource": "JPG locais do projecto de referência indicado pelo proprietário, inventariados e copiados sem alteração; WebP derivados para apresentação. Sem alegação adicional de licença externa, origem oficial ou localização documental. Imagem genérica reutilizada como alternativa funcional e para sectores sem imagem específica.",
"assetBytes960": 997828,
"assetBytes480": 289572,
"verification": {
"browser": {
"results": [
{
"width": 320,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 2,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 390,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 2,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 768,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 3,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1024,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1440,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1920,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
},
{
"emptyCatalogue": true,
"status": "passed"
}
],
"errors": [],
"navigation": [
"/sectores",
"/sectores",
"/sectores",
"/sectores",
"/sectores",
"/sectores/agronegocio",
"/sectores",
"/sectores/turismo",
"/sectores",
"/sectores/infraestruturas",
"/sectores",
"/sectores/economia-azul",
"/sectores",
"/sectores/mercado-financeiro",
"/sectores",
"/sectores/mineracao",
"/sectores",
"/sectores/energia-especifica",
"/sectores",
"/sectores/imobiliario",
"/sectores",
"/sectores/bens-de-consumo-e-franquias",
"/sectores",
"/sectores/tecnologias-de-informacao",
"/sectores",
"/sectores/mercado-financeiro/fintech",
"/sectores",
"/",
"/sectores",
"/sectores"
],
"databaseAccess": false
},
"script": "tools/portal-home-sectors-qa.mjs",
"screenshots": [
"outputs/home-sectors-20261023/catalogue-1024.png",
"outputs/home-sectors-20261023/catalogue-1440.png",
"outputs/home-sectors-20261023/catalogue-1920.png",
"outputs/home-sectors-20261023/catalogue-320.png",
"outputs/home-sectors-20261023/catalogue-390.png",
"outputs/home-sectors-20261023/catalogue-768.png",
"outputs/home-sectors-20261023/fallback-all.png",
"outputs/home-sectors-20261023/fallback-primary.png",
"outputs/home-sectors-20261023/home-sectors-1024.png",
"outputs/home-sectors-20261023/home-sectors-1440.png",
"outputs/home-sectors-20261023/home-sectors-1920.png",
"outputs/home-sectors-20261023/home-sectors-320.png",
"outputs/home-sectors-20261023/home-sectors-390.png",
"outputs/home-sectors-20261023/home-sectors-768.png",
"outputs/home-sectors-20261023/homepage-1440.png"
],
"existingFrontendTests": {
"command": "node --test tests/frontend/portal-api.test.mjs tests/frontend/portal-navigation.test.mjs",
"passed": 20
},
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"assets": {
"resources/js/pages/PortalInvestidor.tsx": "assets/PortalInvestidor-Q1OJxvfZ.js",
"resources/js/pages/portal/services.tsx": "assets/services-DiuG4Zkv.js"
},
"log": "outputs/home-sectors-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"databaseChanged": false,
"migrationsRun": false,
"businessRulesChanged": false,
"routesChanged": false,
"sourceProjectChanged": false,
"newDependencies": false,
"externalDeployment": false
},
"limits": "Interface e navegação exercitadas com API e páginas públicas em fixtures; não equivale a demonstração integral dos workflows operacionais ou de critérios mais amplos da matriz.",
"matrixReferences": [
"MASTER-efd550fd-0104",
"MASTER-9f5719c8-0077"
]
}
@@ -0,0 +1,406 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: analisar e acrescentar imagens adequadas exclusivamente aos três cartões de Como Investir.",
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#fotografias-nas-etapas-de-como-investir--23102026",
"source": {
"type": "Fotografias ilustrativas geradas por IA, sem atribuição a pessoas, instituições, locais ou projectos reais.",
"tool": "image_gen, modo integrado",
"skill": "C:/Users/jorge/.codex/skills/.system/imagegen/SKILL.md",
"externalPhotographsUsed": false
},
"images": [
{
"key": "explorar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 1 EXPLORE opportunities, sector and territory: two Mozambican business professionals, a woman and man in smart casual clothing, standing outdoors by a quiet access road at a modest business park, naturally discussing a tablet held by the woman. Generic unbranded low warehouse buildings and green productive land visible in background, credible southern African environment. Eye-level medium-wide candid composition, both people three-quarter view, looking at tablet and surroundings rather than camera. Business evaluation and discovery, no construction work or hard hats.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-42eb9338-4350-40bf-9098-858c12994189.png",
"original": "outputs/investment-steps-20261023/originals/explorar.png",
"originalSha256": "a3c4ec1a0d2deaf87e0c8e765616c74ab70067eade9a862effce9e6befbbccb6",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/explorar.webp",
"width": 960,
"height": 540,
"bytes": 52266,
"sha256": "c3e151ae649ce3cb66f5babc39978fa5803d320cacc95a27e798db4ec2d45a4c"
},
{
"file": "public/images/investment-steps/explorar-480.webp",
"width": 480,
"height": 270,
"bytes": 19312,
"sha256": "d3f383d9a58b23fada37472ea853f985aca8c3146123747d777b27704d32c7e0"
},
{
"file": "public/images/investment-steps/explorar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5300,
"sha256": "ba12ac4d2e81ac8a2c2e681667ccb08a3abfdba24de39e6e942d6378b700f2a9"
}
]
},
{
"key": "preparar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 2 PREPARE investment and organize documents: a Mozambican woman entrepreneur and a male business adviser seated at a light wood office desk, calmly reviewing and sorting a small tidy set of document folders and loose sheets beside a closed laptop. One points to a page while the other organizes a folder. No visible readable writing or personal data; papers at an angle. Bright modest professional meeting room, view from slightly above table height, hands and folders clear in foreground, natural candid interaction, realistic anatomy.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-5f07618a-1e86-42d9-aaf8-3acd0abf2164.png",
"original": "outputs/investment-steps-20261023/originals/preparar.png",
"originalSha256": "679a6875bb3ec79a9b71c27c9d785334376746be2bb305f461db9e19b0a0b7ea",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/preparar.webp",
"width": 960,
"height": 540,
"bytes": 57942,
"sha256": "6de28042d3abce238a3680fb878779682f3672c3feb97b7e42b72e9a0a0ffbac"
},
{
"file": "public/images/investment-steps/preparar-480.webp",
"width": 480,
"height": 270,
"bytes": 19950,
"sha256": "671ba0fc207f85833b91027d3f6dad91599e95702cfea439e558906f92a2bfac"
},
{
"file": "public/images/investment-steps/preparar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 6008,
"sha256": "645b34cd60b31fdc8e6586dedb71061c08add9ff985ce90909333b0bd1e0aa3e"
}
]
},
{
"key": "acompanhar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 3 FOLLOW UP submitted request and protocol: a Mozambican male entrepreneur seated at a tidy desk using a laptop to check an online application, one hand naturally on trackpad, a small closed document folder nearby. Three-quarter side view showing focused face and laptop, warm daylight from side window, modest contemporary office with soft greenery out of focus. Laptop screen is oblique and softly out of focus with only indistinct neutral interface rows, no readable text, official seal, logo or invented dashboard details. Convey calm digital self-service and progress checking, not a call centre or signing documents.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f896c5f8-19a0-49b0-af8e-0d12bfe4c7aa.png",
"original": "outputs/investment-steps-20261023/originals/acompanhar.png",
"originalSha256": "17d453445f2afb4c7641909950d2ecfb8276c433a4e28eeee94d0a57d1bdad46",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/acompanhar.webp",
"width": 960,
"height": 540,
"bytes": 43722,
"sha256": "fe764c8161de36ee597f856face5341260670d1a28ab482bd01a0f5120ad0588"
},
{
"file": "public/images/investment-steps/acompanhar-480.webp",
"width": 480,
"height": 270,
"bytes": 16176,
"sha256": "79ceaecb0ef23c6729e43d04b7e91493d6784ea9f658d540dda3550702dc3623"
},
{
"file": "public/images/investment-steps/acompanhar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5298,
"sha256": "cd4530cfef4f19f23f640ceae59cfd73d0ee269643118b458f2a4748f5845fc6"
}
]
}
],
"cards": [
{
"title": "1. Explorar",
"description": "Identifique o sector, território e oportunidade.",
"href": "/oportunidades",
"image": "explorar"
},
{
"title": "2. Preparar",
"description": "Conheça o percurso e organize os documentos.",
"href": "/como-investir",
"image": "preparar"
},
{
"title": "3. Acompanhar",
"description": "Envie o pedido e acompanhe o protocolo.",
"href": "/balcao-virtual",
"image": "acompanhar"
}
],
"presentation": {
"component": "resources/js/components/investment-steps.tsx",
"homeIntegration": "resources/js/pages/PortalInvestidor.tsx",
"aspectRatio": "16:9",
"responsiveImages": [
960,
480
],
"fallback": "Variante própria de 240 px; se também falhar, espaço reservado com descrição acessível e Imagem indisponível.",
"columns": "Uma coluna abaixo de 768 px, três a partir de 768 px.",
"compactText": "16 px de preenchimento, sem altura mínima de texto.",
"accessibility": "Alt em português, nomes e descrições das âncoras, foco visível, dimensões reservadas e loading lazy.",
"headings": "Título vermelho partilhado da home preservado."
},
"verification": {
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"fail": "none",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7820512820512822
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7820512820512822
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7820512820512822
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "none",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7755102040816326
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 768,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7734375
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7734375
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7734375
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1024,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7784090909090908
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7784090909090908
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7784090909090908
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1440,
"dpr": 2,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.775
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1920,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.775
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "primary",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-fallback.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-fallback.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-fallback.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7755102040816326
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "all",
"columns": 1,
"photos": [],
"layoutShift": false,
"overflow": false
}
],
"errors": [],
"navigation": [
"/oportunidades",
"/como-investir",
"/balcao-virtual"
],
"databaseAccess": false
},
"script": "outputs/investment-steps-20261023/check.mjs",
"screenshots": [
"outputs/investment-steps-20261023/cards-1024-none.png",
"outputs/investment-steps-20261023/cards-1440-none.png",
"outputs/investment-steps-20261023/cards-1920-none.png",
"outputs/investment-steps-20261023/cards-320-none.png",
"outputs/investment-steps-20261023/cards-390-all.png",
"outputs/investment-steps-20261023/cards-390-none.png",
"outputs/investment-steps-20261023/cards-390-primary.png",
"outputs/investment-steps-20261023/cards-768-none.png"
],
"lint": {
"exitCode": 0
},
"types": {
"command": "npm run types:check",
"exitCode": 0,
"log": "outputs/investment-steps-20261023/types.log"
},
"build": {
"command": "npm run build",
"exitCode": 0,
"homeAsset": "assets/PortalInvestidor-C1QTZ3-t.js",
"log": "outputs/investment-steps-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"otherSectionsChanged": false,
"supportAndFooterChanged": false,
"databaseAccess": false,
"businessRulesChanged": false,
"routesChanged": false,
"newDependencies": false,
"externalDeployment": false
},
"matrixReferences": [
"MASTER-efd550fd-0104"
],
"limits": "Componentes reais com API sintética e destinos interceptados para verificar a navegação; não demonstra os workflows operacionais completos nem encerra o critério mais amplo da matriz."
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,258 @@
{
"status": "installed_delta_verified_partial_L1",
"base_remote_main": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"candidate": "c28e290b42a2a96c68b16dab59871581633a471e",
"compatibility": "fresh fetch;origin/main ancestor of candidate;no concurrent change;local stale main not used",
"coverage": {
"G2C": {
"P013": [
"cultural_visits_public",
"cultural_visits_nonprofit"
],
"P014": [
"religious_personnel_public",
"religious_personnel_nonprofit"
],
"P015": [
"statutory_membership"
]
},
"G2D": {
"P024": [
"author_rights"
],
"P025": [
"cultural_publications"
]
},
"new_branches": 5,
"new_treatments": 7,
"conditional_treatments_total": 32
},
"counts_before": {
"delivered": 12,
"QA": 5,
"functional_pending": 115,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 17,
"QA": 0,
"functional_pending": 115,
"documentary": 1,
"total": 133
},
"runtime_delta": [
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "577a029e24580d9c4dba0e4c19ce57da6273fe6f44185b3a32bd02fd7573578c"
}
],
"activation": "Existing Git FF/webhook installer;catalogue available in existing L1 component;no migration/import/server fiscal rule activation/permissions changes",
"preservation": "12delivered+G2C/G2Dproofs reused;four frozen books unchanged/current without recalculation;newrules scoped keys only",
"rollback": "Existing compatible readonly containment patch apply-check passed;keep catalogue/readers/snapshots/reports;prior release and fresh verified backup required;no active rollback executed",
"QA": "G2C2frontend+API1/14;G2D2frontend+API1/11;UI?API?report;types/build passed;acceptedWord/PDFunchanged",
"P001_blocks_independent": false,
"L1_complete": false,
"statistics_AI": "deferred",
"authenticated_preflight": "confirmed490527b9;installed/current/revisionagree;serviceinactive;pipelinehashunchanged",
"backup_restore": {
"verified": true,
"tables": 174,
"files": 369,
"dump_sha256": "c11ba51e60cb3ac1cad5411c2aeefcb0adaeadd6fd2c16cd42fd6b63b1449fff",
"backup": "/var/backups/investmoz-l1-g2cd-delivery-20261024/backup",
"restore": "l1_g2cd_restore_20261024:55441;networknone;174checksumsagree;containerremoved;zeroactiveDBwrites"
},
"installed_delta": "verified",
"served_commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"installation": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2cd-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "c11ba51e60cb3ac1cad5411c2aeefcb0adaeadd6fd2c16cd42fd6b63b1449fff",
"files_sha256": "21fc80e45eaa289b67e2d2ce6bcc538b51330a3fa7cfb7e9cd64367201389b5e",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2cd_restore_20261024",
"port": 55441,
"source_dump_sha256": "c11ba51e60cb3ac1cad5411c2aeefcb0adaeadd6fd2c16cd42fd6b63b1449fff",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"previous_release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"previous_release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"3b788ec0098d84dcc154239651a35c685dfc2ebd"
],
"finished_at": "2026-10-24T12:48:10.504292+00:00"
},
"log_file": "1792846007466003663.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 23.88s",
"OK (59 tests, 317 assertions)",
"# tests 251",
"# pass 251",
"# fail 0"
],
"log_bytes": 101223
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"previous_release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 1,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"audit_events": {
"before": {
"rows": 645,
"checksum": "88c2047620eb3fad4d2a2837ed3daef5"
},
"after": {
"rows": 646,
"checksum": "cf24e81547ee23d812ccaadaccc387b6"
}
},
"cache": {
"before": {
"rows": 105,
"checksum": "ef2967a3b3174300a6509d3013c1823d"
},
"after": {
"rows": 105,
"checksum": "6dfe16f04a406749beaf0a189897106b"
}
},
"sessions": {
"before": {
"rows": 5,
"checksum": "2a932f661c46631221bec768a4a23574"
},
"after": {
"rows": 8,
"checksum": "6d7f01315a1de04eadaddc0b90e0526c"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"audit_delta": {
"historical_audit_unchanged": true,
"historical_rows": 645,
"new_events": 1,
"new_event_metadata": {
"source_system": "virtual-desk",
"entity_type": "desk_cases",
"action": "consulted",
"created_at": "2026-10-24T12:47:35.31492+00:00"
},
"verification_writes": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"branch": "main",
"built_at": "2026-10-24T12:48:08.073225+00:00",
"manifest_sha256": "b00f59904a5709fbcd8eaa6b51ac8dc421ddfc8dfd2e0ce18d133240150c8810"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"cultural_visits_": [
"assets/project-dossier-BDWSVUNs.js"
],
"religious_personnel_": [
"assets/project-dossier-BDWSVUNs.js"
],
"statutory_membership": [
"assets/project-dossier-BDWSVUNs.js"
],
"author_rights": [
"assets/project-dossier-BDWSVUNs.js"
],
"cultural_publications": [
"assets/project-dossier-BDWSVUNs.js"
],
"iva-operations-l1/2": [
"assets/project-dossier-BDWSVUNs.js"
]
},
"assets": [
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-document-BVqhDRN3.js",
"status": 200,
"sha256": "56076c99222527ecc453bd245e21830618d07d26a874eede4f07cd597587922a"
},
{
"file": "assets/project-dossier-BDWSVUNs.js",
"status": 200,
"sha256": "574235d0a55380d1a0a4044b46bed1c9f47aca0ec4f61b1356ac7216b8fcc85d"
},
{
"file": "assets/services-CJfVMeO3.js",
"status": 200,
"sha256": "ae0b9fda96068b6179b16d0b7d121d4d840ba82d6763253821bb6b9ac03a3686"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-B0KlTmxs.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"Git": "freshfetch;branchpush;mainfastforward;noforce;existingwebhook",
"rollback_executed": false
}
}
@@ -0,0 +1,289 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "9b0f4370737f340b7fca606728f5ca281f6b5dfd",
"base_remote_main": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"fresh_fetch": "confirmed main3b788ec0;ancestor;no concurrent changes detected;localmainnotused",
"coverage": {
"G2E": {
"P033": "industrial_feed",
"P034": "industrial_feed_inputs",
"P036": "veterinary_goods",
"P044": "agricultural_services"
},
"G2F": {
"P023": "special_tax_games",
"P028": "stamped_values",
"P037": "public_passenger_transport"
},
"new_branches": 7,
"new_treatments": 7,
"conditional_treatments_total": 39
},
"counts_before": {
"delivered": 17,
"QA": 7,
"functional_pending": 108,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 24,
"QA": 0,
"functional_pending": 108,
"documentary": 1,
"total": 133
},
"runtime_delta": [
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "dcb141a4d0a1edb0d2b2c8f63a20a076b8362c02d652baad673e652c133c64ce"
}
],
"activation": "ExistingGitFF/webhook/installer;catalogueexistingcomponent;no migrations/imports/server fiscal rule activation/permissions changes",
"preservation": "17delivered closed;G2E/G2FacceptedQAproofsreused;sixfrozenbookscurrentwithoutrecalculation",
"rollback": "Keepcataloguereaderssnapshotsresultsreports;existingreadonlycontainmentpatchapplycheckrequired;backuprestorebeforepush;no rollback executed",
"P001": "Stilldocumentary05/06;05/07doesnotresolveit;doesnotblockindependent",
"QA": "G2E2frontend+API1/14;G2F2frontend+API1/13;UItoAPIreport;types/buildpassed;WordPDFunchanged",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"previous_release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"release_revision": {
"commit": "3b788ec0098d84dcc154239651a35c685dfc2ebd",
"branch": "main",
"built_at": "2026-10-24T12:48:08.073225+00:00",
"manifest_sha256": "b00f59904a5709fbcd8eaa6b51ac8dc421ddfc8dfd2e0ce18d133240150c8810"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2ef-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "e23ea1909ede1cb3be7a5e5751f5580e8b8c0b2452c53772c8e28d06ec999b20",
"files_sha256": "c56f7ac804b0d4f0c69a2f53a23b00cc34fa067888e62e13444192b3d41c52cf",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2ef_restore_20261024",
"port": 55441,
"source_dump_sha256": "e23ea1909ede1cb3be7a5e5751f5580e8b8c0b2452c53772c8e28d06ec999b20",
"active_database_writes": 0
}
},
"installed_delta": "verified",
"L1_complete": false,
"statistics_AI": "deferred",
"rollback_compatibility": "gitapplycheckpassed;notapplied;keepcatalogueandreaders;previousreleaseandverifiedbackupavailable",
"served_commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"installation": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2ef-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "e23ea1909ede1cb3be7a5e5751f5580e8b8c0b2452c53772c8e28d06ec999b20",
"files_sha256": "c56f7ac804b0d4f0c69a2f53a23b00cc34fa067888e62e13444192b3d41c52cf",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2ef_restore_20261024",
"port": 55441,
"source_dump_sha256": "e23ea1909ede1cb3be7a5e5751f5580e8b8c0b2452c53772c8e28d06ec999b20",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"previous_release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"previous_release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"9a56d982423d0c244850f8638290a1ce8a968619"
],
"finished_at": "2026-10-24T13:01:02.426859+00:00"
},
"log_file": "1792846776358374658.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.68s",
"OK (59 tests, 317 assertions)",
"# tests 255",
"# pass 255",
"# fail 0"
],
"log_bytes": 102308
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"previous_release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 1,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "17b5d816f82ab932dca814a8e76c1211"
},
"after": {
"rows": 105,
"checksum": "316356979dc340fc5f141679bdee5c0d"
}
},
"sessions": {
"before": {
"rows": 8,
"checksum": "d1df0268b1343c91b756052e39ca7930"
},
"after": {
"rows": 11,
"checksum": "787de58f2b0436566c2ad27161a8a759"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"branch": "main",
"built_at": "2026-10-24T13:00:59.831259+00:00",
"manifest_sha256": "b92bc7b64176675274dd934bb683f09c4a4ca3c4fe690dfce06425e89a7f3e04"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"industrial_feed": [
"assets/project-dossier-DSFHX342.js"
],
"industrial_feed_inputs": [
"assets/project-dossier-DSFHX342.js"
],
"veterinary_goods": [
"assets/project-dossier-DSFHX342.js"
],
"agricultural_services": [
"assets/project-dossier-DSFHX342.js"
],
"special_tax_games": [
"assets/project-dossier-DSFHX342.js"
],
"stamped_values": [
"assets/project-dossier-DSFHX342.js"
],
"public_passenger_transport": [
"assets/project-dossier-DSFHX342.js"
],
"iva-operations-l1/2": [
"assets/project-dossier-DSFHX342.js"
]
},
"assets": [
{
"file": "assets/project-dossier-DSFHX342.js",
"status": 200,
"sha256": "9083729b212d85c15164545718f7813f1a843627eb7dffbfa398bd8ce4a35afb"
},
{
"file": "assets/services-CfCgVoiZ.js",
"status": 200,
"sha256": "4e3c1d5d90b642e4face01d05ab47f73cc9e3e7c4286fb7b638319d8d71dc96a"
},
{
"file": "assets/project-dossier-document-7BExzGRH.js",
"status": 200,
"sha256": "3e925451351648c1dd2f7323c15e1881ba09dd3f0f27092a153958537476583f"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-CHL9O0-A.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"Git": "freshfetch;branchpush;mainfastforward;noforce;existingwebhook",
"rollback_executed": false
}
}
@@ -0,0 +1,371 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "b297058d11aee206530492a65f86e3d58eb5ba15",
"base_remote_main": "9a56d982423d0c244850f8638290a1ce8a968619",
"fresh_fetch": "main9a56d982;ancestor;no concurrent advance detected",
"coverage": {
"G2G": {
"P010": [
"public_security"
],
"P027": [
"official_military_supplies"
],
"P031": [
"sisa_subject_operation"
],
"P032": [
"exempt_activity_asset_sale",
"no_deduction_right_asset_sale",
"excluded_deduction_asset_sale"
]
},
"G2H": {
"P026": [
"listed_maize",
"listed_maize_flour",
"listed_rice",
"listed_bread",
"listed_iodised_salt",
"listed_infant_powdered_milk",
"listed_wheat",
"listed_wheat_flour",
"listed_fresh_chilled_tomato",
"listed_potato",
"listed_onion",
"listed_frozen_horse_mackerel",
"listed_lighting_kerosene",
"listed_domestic_lpg",
"listed_jet_fuel",
"listed_eligible_bicycles",
"listed_condoms",
"listed_insecticides"
]
},
"new_branches": 5,
"new_treatments": 24,
"conditional_treatments_total": 63
},
"counts_before": {
"delivered": 24,
"QA": 5,
"functional_pending": 103,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 29,
"QA": 0,
"functional_pending": 103,
"documentary": 1,
"total": 133
},
"runtime_delta": [
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "f18941067a82d18f43af4252c11b7ff26e001212e1e6cb5bff62c9b4ba48f855"
}
],
"activation": "ExistingGitFF/webhook/installer;catalogueexistingcomponent;no migrations/imports/server rule activation/permissions/other tax calculations",
"QA": "G2G2frontend+API1/16;G2H2frontend+API1/28;UItoAPIreport;types/buildpassed;acceptedWordPDFreused",
"preservation": "24delivered andeightfrozencontextscurrentwithoutrecalculation;G2G/G2Hproofsreused;G2Ftraceabilityclarifiedwithoutretests",
"rollback": "Keepcataloguereaderssnapshotsresultsreports;compatibleexistingreadonlypatch;priorreleaseandfreshbackuprestorebeforepush;no rollback executed",
"P001": "Documentary05/06stillopen;05/07doesnotresolveit;noindependentblock",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"previous_release": "/var/www/investmoz-homologacao/releases/3b788ec0098d84dcc154239651a35c685dfc2ebd-56825c6e",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"release_revision": {
"commit": "9a56d982423d0c244850f8638290a1ce8a968619",
"branch": "main",
"built_at": "2026-10-24T13:00:59.831259+00:00",
"manifest_sha256": "b92bc7b64176675274dd934bb683f09c4a4ca3c4fe690dfce06425e89a7f3e04"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2gh-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "ffe24d9e324cc1ad2354e8feec088e072db437eb54d1f5b6dfd3830865940b40",
"files_sha256": "57bcb40faf4cb5e14b0aa13eb8b274f222e51bc3cd5fd17e07d70e87165e2b94",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2gh_restore_20261024",
"port": 55441,
"source_dump_sha256": "ffe24d9e324cc1ad2354e8feec088e072db437eb54d1f5b6dfd3830865940b40",
"active_database_writes": 0
}
},
"installed_delta": "verified",
"L1_complete": false,
"statistics_AI": "deferred",
"rollback_compatibility": "gitapplycheckpassed;notapplied;keepcatalogueandreaders;previousreleaseandverifiedbackupavailable",
"served_commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"installation": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2gh-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "ffe24d9e324cc1ad2354e8feec088e072db437eb54d1f5b6dfd3830865940b40",
"files_sha256": "57bcb40faf4cb5e14b0aa13eb8b274f222e51bc3cd5fd17e07d70e87165e2b94",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2gh_restore_20261024",
"port": 55441,
"source_dump_sha256": "ffe24d9e324cc1ad2354e8feec088e072db437eb54d1f5b6dfd3830865940b40",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"previous_release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"previous_release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"d4eae917ee9c9d37f0339905a96c1e35480f324e"
],
"finished_at": "2026-10-24T13:15:14.273272+00:00"
},
"log_file": "1792847626452821855.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 26.20s",
"OK (59 tests, 317 assertions)",
"# tests 259",
"# pass 259",
"# fail 0"
],
"log_bytes": 103542
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"previous_release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 1,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "316356979dc340fc5f141679bdee5c0d"
},
"after": {
"rows": 105,
"checksum": "39b6357efbe3142e8d0e55b5fac6a935"
}
},
"sessions": {
"before": {
"rows": 11,
"checksum": "787de58f2b0436566c2ad27161a8a759"
},
"after": {
"rows": 14,
"checksum": "ba1aa4ceaf894c62a66a4186ae4e9ddc"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"branch": "main",
"built_at": "2026-10-24T13:15:11.725340+00:00",
"manifest_sha256": "4018026aac013855f2c9baf9258ed96e1b1bf808d996e8fa8eec9458ea6b35c7"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"public_security": [
"assets/project-dossier-PaHmg6s9.js"
],
"official_military_supplies": [
"assets/project-dossier-PaHmg6s9.js"
],
"sisa_subject_operation": [
"assets/project-dossier-PaHmg6s9.js"
],
"exempt_activity_asset_sale": [
"assets/project-dossier-PaHmg6s9.js"
],
"no_deduction_right_asset_sale": [
"assets/project-dossier-PaHmg6s9.js"
],
"excluded_deduction_asset_sale": [
"assets/project-dossier-PaHmg6s9.js"
],
"maize": [
"assets/project-dossier-PaHmg6s9.js"
],
"maize_flour": [
"assets/project-dossier-PaHmg6s9.js"
],
"rice": [
"assets/services-CVvFKfag.js",
"assets/project-dossier-PaHmg6s9.js"
],
"bread": [
"assets/project-dossier-PaHmg6s9.js"
],
"iodised_salt": [
"assets/project-dossier-PaHmg6s9.js"
],
"infant_powdered_milk": [
"assets/project-dossier-PaHmg6s9.js"
],
"wheat": [
"assets/project-dossier-PaHmg6s9.js"
],
"wheat_flour": [
"assets/project-dossier-PaHmg6s9.js"
],
"fresh_chilled_tomato": [
"assets/project-dossier-PaHmg6s9.js"
],
"potato": [
"assets/project-dossier-PaHmg6s9.js"
],
"onion": [
"assets/project-dossier-PaHmg6s9.js"
],
"frozen_horse_mackerel": [
"assets/project-dossier-PaHmg6s9.js"
],
"lighting_kerosene": [
"assets/project-dossier-PaHmg6s9.js"
],
"domestic_lpg": [
"assets/project-dossier-PaHmg6s9.js"
],
"jet_fuel": [
"assets/project-dossier-PaHmg6s9.js"
],
"eligible_bicycles": [
"assets/project-dossier-PaHmg6s9.js"
],
"condoms": [
"assets/project-dossier-PaHmg6s9.js"
],
"insecticides": [
"assets/project-dossier-PaHmg6s9.js"
],
"listed_": [
"assets/project-dossier-PaHmg6s9.js"
],
"iva-operations-l1/2": [
"assets/project-dossier-PaHmg6s9.js"
]
},
"assets": [
{
"file": "assets/services-CVvFKfag.js",
"status": 200,
"sha256": "3ce2515eb4d53e8c2da3f10fdca2bfea208d801616813e6dcd18331b7d25c048"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-PaHmg6s9.js",
"status": 200,
"sha256": "9fce800b1b9805b436a1d3801f8a596ad8c879604ac193d2af6cfb546d15c7e8"
},
{
"file": "assets/project-dossier-document-CNebL8r6.js",
"status": 200,
"sha256": "242eebf5c9d9dac52eb0b53009013705058cfd62aeb0c576e4cdb6cad7619c5f"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-gy0vGuME.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"Git": "freshfetch;branchpush;mainfastforward;noforce;existingwebhook",
"rollback_executed": false
}
}
@@ -0,0 +1,319 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "72f4187d3bc0727ae0c5162500d5d6f26b7eed49",
"base_remote_main": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"fresh_fetch": "main d4eae917; ancestral; no concurrent advance detected; fetch again immediately before push",
"coverage": {
"G2I": {
"P019": [
"production_agriculture"
],
"P020": [
"production_forestry",
"production_forestry_opted"
],
"P021": [
"production_livestock",
"production_livestock_opted"
],
"P022": [
"production_fishing",
"production_fishing_opted"
]
},
"G2J": {
"P016": [
"fundraising_public",
"fundraising_nonprofit"
]
},
"new_branches": 5,
"new_treatments": 9,
"conditional_treatments_total": 72,
"calendar_resolution": "Civil279(c)/296 plus CIVA11(3), production-option/2; no additional branch"
},
"counts_before": {
"delivered": 29,
"QA": 5,
"functional_pending": 98,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 34,
"QA": 0,
"functional_pending": 98,
"documentary": 1,
"total": 133
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "94e7419ee3338c9eda6418e741d72f08334dbb3f6507dd78d2bd6690d4be6b5b"
},
{
"path": "resources/js/lib/iva-fundraising.ts",
"sha256_LF": "b58fc5733eb9f7facfe00a5f4cf0acdc98ad1e4191dbfdd1189fdf379e25e227"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "844d9b634afcb6a72237ca87626e5e1bcba8df3744b35063c1657a590d17b957"
},
{
"path": "resources/js/lib/iva-production-option.ts",
"sha256_LF": "2bdbb6ed52086c2c47d9f615b2cbe1c8f1370b8fdcefaa40c07b6cda8cc47526"
}
],
"activation": "Existing Git FF/webhook/installer and existing enabled simulator panel; no migrations/imports/server-rule activation/permissions/other taxes",
"QA": "G2I fe69a16e/a5ac8ca1 reused except changed calendar; calendar2frontend+API1/10;G2J2frontend+API1/10;UI/API/report;types/buildpassed;acceptedWordPDFreused",
"preservation": "29 delivered branches and previous receipts/data retained; only changed G2I opted-rule results marked historical, never rewritten",
"rollback": "Keep catalogue/readers/snapshots/results/reports; verified compatible l1-joint-readonly-rollback-20261024.patch suspends edits/calculations only; not applied. Prior release and verified fresh backup retained; no broad rollback or DB restoration executed.",
"rollback_compatibility": "git apply --check passed; not applied",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"previous_release": "/var/www/investmoz-homologacao/releases/9a56d982423d0c244850f8638290a1ce8a968619-19d0ea6c",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"release_revision": {
"commit": "d4eae917ee9c9d37f0339905a96c1e35480f324e",
"branch": "main",
"built_at": "2026-10-24T13:15:11.725340+00:00",
"manifest_sha256": "4018026aac013855f2c9baf9258ed96e1b1bf808d996e8fa8eec9458ea6b35c7"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2ij-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "a75cb8751146ad0a59ecd62fa13e4d9ede3fd98ad2f4ebda092b48f7c2526c32",
"files_sha256": "889fe89ec3acccfc17ace98dec9e6fb8675bfb75f69efb1ae9ce7585c50ef873",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2ij_restore_20261024",
"port": 55441,
"source_dump_sha256": "a75cb8751146ad0a59ecd62fa13e4d9ede3fd98ad2f4ebda092b48f7c2526c32",
"active_database_writes": 0
}
},
"P001": "Documentary05/06only;independentoperationsnotblocked",
"L1_complete": false,
"statistics_AI": "deferred",
"served_commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"installed_delta": "verified",
"installation": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2ij-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "a75cb8751146ad0a59ecd62fa13e4d9ede3fd98ad2f4ebda092b48f7c2526c32",
"files_sha256": "889fe89ec3acccfc17ace98dec9e6fb8675bfb75f69efb1ae9ce7585c50ef873",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2ij_restore_20261024",
"port": 55441,
"source_dump_sha256": "a75cb8751146ad0a59ecd62fa13e4d9ede3fd98ad2f4ebda092b48f7c2526c32",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"previous_release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"previous_release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"e45a1394fa2ca8631593549b3af62093f25d9c13"
],
"finished_at": "2026-10-24T13:51:04.874534+00:00"
},
"log_file": "1792849778512278349.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.05s",
"OK (59 tests, 317 assertions)",
"# tests 265",
"# pass 265",
"# fail 0"
],
"log_bytes": 105228
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"previous_release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 4,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "39b6357efbe3142e8d0e55b5fac6a935"
},
"after": {
"rows": 105,
"checksum": "de9f82d4485c5358f6677efbc61c53a0"
}
},
"sessions": {
"before": {
"rows": 14,
"checksum": "ba1aa4ceaf894c62a66a4186ae4e9ddc"
},
"after": {
"rows": 15,
"checksum": "c6e69ce7f5936cefebf8b1d7b9295a15"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"branch": "main",
"built_at": "2026-10-24T13:51:02.487098+00:00",
"manifest_sha256": "2f3fd204e659ac71f0e35b59365b7342d79f1460119ef34a4daa217e4b21c0af"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"production_": [
"assets/project-dossier-CP3iqTD7.js",
"assets/services-D8gl05j7.js"
],
"agriculture": [
"assets/project-dossier-CP3iqTD7.js"
],
"forestry": [
"assets/project-dossier-CP3iqTD7.js"
],
"livestock": [
"assets/project-dossier-CP3iqTD7.js"
],
"fishing": [
"assets/project-dossier-CP3iqTD7.js"
],
"fundraising_public": [
"assets/project-dossier-CP3iqTD7.js"
],
"fundraising_nonprofit": [
"assets/project-dossier-CP3iqTD7.js",
"assets/services-D8gl05j7.js"
],
"production-option/2": [
"assets/project-dossier-CP3iqTD7.js"
],
"fundraising/1": [
"assets/project-dossier-CP3iqTD7.js"
]
},
"assets": [
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-document-RxKyJJE-.js",
"status": 200,
"sha256": "f1580c32f9b5590f65ef1caeb99bcb8838a7593837001e8f541815318bbffc65"
},
{
"file": "assets/project-dossier-CP3iqTD7.js",
"status": 200,
"sha256": "7317575f701ff3b68c5909f57bfa8b2d228fc30f3c0a8b852ebe2f98ad4431fc"
},
{
"file": "assets/services-D8gl05j7.js",
"status": 200,
"sha256": "018c16520dc0410f830de3963aa55bcf459297cd0bbebfa4562312cd2793c218"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-B5iYnxXw.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"Git": "fresh fetch; feature push; main fast-forward; no force; existing webhook",
"rollback_executed": false
}
}
@@ -0,0 +1,391 @@
{
"status": "installed_delta_verified_partial_L1",
"base_remote_main": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"fresh_fetch": "origin/main e45a1394,ancestor;fetch again immediately before main push",
"coverage": {
"G2K": {
"P008": [
"pharma_manufacturing_inputs"
]
},
"G2L": {
"P035": [
"annexI_goods"
]
},
"new_branches": 2,
"new_treatments": 2,
"documentary_rows": {
"AnexoIII": 170,
"AnexoI": 172
},
"existing_treatments_reused": "Explicit identity-preserving continuations to9(10);no new branch IDs"
},
"counts_current": {
"delivered": 36,
"QA": 0,
"functional_pending": 96,
"documentary": 1,
"total": 133
},
"counts_after_QA_and_delivery_only": {
"delivered": 36,
"QA": 0,
"functional_pending": 96,
"documentary": 1,
"total": 133
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "6e6d7b5d7f47541683dd4f32e93805b0d3068283a8ff1b3446884f5e4c626039"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "02e411659c84c00182c6c46f3af499f04648a8cf84911ce11ed9a21f12d48d78"
},
{
"path": "resources/js/lib/iva-pharma-annex.ts",
"sha256_LF": "dd56382b6edcced208efb03ebfc412f75e03b7180d084021ecbde1bac713ce3f"
},
{
"path": "resources/js/lib/iva-annex-i.ts",
"sha256_LF": "6dda21a66dd9399b911bc9839163a5e20f10808ac1937d3b2ca70dff3109424d"
}
],
"QA": {
"G2K": "8882dc54/1fe74256;accepted proofs reused",
"G2L": "4frontend/types/build accepted; manual Tempo reading/viewing and reported save/recover/report passage; actual saved UI payload verified and private API1/29 passed;12previousbooks preserved without recalculation.",
"review_controls": "Same-origin synthetic file save/recover/report clarified; manual passage reported by Tempo and saved file found; no Codex browser observation claimed."
},
"visual_gate": {
"origin": "http://127.0.0.1:18639",
"user_authorized": true,
"user_requested_retry": true,
"current_tool_result": "A saved user permission setting blocks this action; saved permission or managed policy denies access",
"alternate_origin_or_browser_workaround_attempted": false
},
"before_delivery_required": [],
"activation": "Existing Git fast-forward/webhook/installer and existing simulator panel;no migrations/imports/server fiscal activation/permissions/other taxes",
"rollback": "Existing l1-joint-readonly-rollback-20261024.patch passed git apply --check;not applied;keeps catalogue/readers/history/API/reports. Retain prior release and verified fresh backup before deployment;no DBrestore executed.",
"backup_restore_new_delivery": "Verified fresh backup and real isolated restore;no active restore executed.",
"homologation_unchanged": false,
"P001": "05/06only;notextended",
"L1_complete": false,
"statistics_AI": "deferred",
"G2L_candidate": "744682835a91f08aece9258380466ae746bc7353",
"G2K_candidate": "8882dc54d0973bc058b04009bdbc36c9da2cc31b",
"G2L_record": "iva_l1_g2_annex_i_code_qa_visual_pending_20261024",
"visual_verification_routes": {
"authority": "Express Tempo instruction,24/10/2026",
"manual_Tempo": {
"accepted": true,
"status": "manual_passage_reported_and_saved_payload_technically_verified",
"observations": {
"source": "Tempo, conversation24/10/2026",
"earlier_statement": "No failure seen in what was read and observed; save/recovery buttons not identified.",
"latest_statement": "ja procedi com a tua instrução pode verificar",
"scope": "User reports following the save/recover/report instructions after controls were clarified.",
"Codex_visual_observation": false,
"additional_individual_observations_invented": false
}
},
"Codex_browser": {
"accepted_after_tool_permission_review": true,
"saved_permission_not_changed_by_conversation_authorization": true
},
"scope": [
"Search/select an AnnexI position",
"Conditions and missing information",
"Save/recover and match selected position in report;continuitywhereapplicable"
],
"automatic_tests": "Already accepted;do not repeat",
"tool_block_is_portal_failure_evidence": false,
"circumvention": false
},
"G2L_completion_record": "iva_l1_g2l_manual_completion_and_actual_UI_payload_20261024",
"candidate": "da798dd1d8a017cfb20764b566661807b2ef0ffc",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"previous_release": "/var/www/investmoz-homologacao/releases/d4eae917ee9c9d37f0339905a96c1e35480f324e-afcda0da",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"release_revision": {
"commit": "e45a1394fa2ca8631593549b3af62093f25d9c13",
"branch": "main",
"built_at": "2026-10-24T13:51:02.487098+00:00",
"manifest_sha256": "2f3fd204e659ac71f0e35b59365b7342d79f1460119ef34a4daa217e4b21c0af"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2kl-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "8c6d8f2745ebb3dc6883d67fb8d9810593d47ad44fb0e20859e3547044adee6c",
"files_sha256": "66d42c9053508681e8f7adfe20631396272f2fb934a69a6c79347a029fa11f78",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2kl_restore_20261024",
"port": 55441,
"source_dump_sha256": "8c6d8f2745ebb3dc6883d67fb8d9810593d47ad44fb0e20859e3547044adee6c",
"active_database_writes": 0
}
},
"rollback_compatibility": "git apply --check passed on current candidate;patch not applied;catalogue/readers/history retained",
"served_commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"installed_delta": "verified",
"installation": {
"backup": {
"stage": "/var/backups/investmoz-l1-g2kl-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "8c6d8f2745ebb3dc6883d67fb8d9810593d47ad44fb0e20859e3547044adee6c",
"files_sha256": "66d42c9053508681e8f7adfe20631396272f2fb934a69a6c79347a029fa11f78",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g2kl_restore_20261024",
"port": 55441,
"source_dump_sha256": "8c6d8f2745ebb3dc6883d67fb8d9810593d47ad44fb0e20859e3547044adee6c",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"previous_release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"previous_release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"ccdecbd8d74596e729f03381d3b37ca22ce5800e"
],
"finished_at": "2026-10-24T14:40:58.261566+00:00"
},
"log_file": "1792852768694030688.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.35s",
"OK (59 tests, 317 assertions)",
"# tests 272",
"# pass 272",
"# fail 0"
],
"log_bytes": 107426
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"previous_release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 4,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "9d045636f1332b32bb65a20a35a0ffe1"
},
"after": {
"rows": 105,
"checksum": "f8fbf67b713b7dfdce6a3bacb6c46823"
}
},
"sessions": {
"before": {
"rows": 14,
"checksum": "fa2aec2278d6646c26970993447e306a"
},
"after": {
"rows": 15,
"checksum": "9c9c8b103d1429a690d8e140f1c19ad7"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"branch": "main",
"built_at": "2026-10-24T14:40:55.681401+00:00",
"manifest_sha256": "8ee52a7b3f7c4363f10d73382d85325bbfa331c2e6e44ccd08d92e578cdf2776"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"annexI_goods": [
"assets/project-dossier-DmOH9u9e.js",
"assets/services-zksozm3m.js"
],
"pharma_manufacturing_inputs": [
"assets/project-dossier-DmOH9u9e.js",
"assets/services-zksozm3m.js"
],
"annexI-lei22-2022/1": [
"assets/project-dossier-DmOH9u9e.js"
],
"annexIII-lei22-2022/1": [
"assets/project-dossier-DmOH9u9e.js"
],
"annexIItem": [
"assets/project-dossier-DmOH9u9e.js",
"assets/services-zksozm3m.js"
],
"pharmaAnnexItem": [
"assets/project-dossier-DmOH9u9e.js",
"assets/services-zksozm3m.js"
],
"2912.19.00": [
"assets/project-dossier-DmOH9u9e.js",
"assets/services-zksozm3m.js"
],
"8201.50.00": [
"assets/project-dossier-DmOH9u9e.js"
],
"8701.95.00": [
"assets/project-dossier-DmOH9u9e.js"
]
},
"assets": [
{
"file": "assets/project-dossier-DmOH9u9e.js",
"status": 200,
"sha256": "4cd3c0dbc4466661ce7e73dd4120fb956b9386c6e141b038e5a526cbf7424196"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/services-zksozm3m.js",
"status": 200,
"sha256": "5b771620208247a10da9d22e78be4fc772f8c1e02afcf38a7e6a47a5cdfefd5d"
},
{
"file": "assets/project-dossier-document-BGVr7IFw.js",
"status": 200,
"sha256": "fa7e832b28fbb762872dd5df448ef20c6f2ce5bafd5226b20c31376b566a25da"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-CQEv1lby.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"Git": "fresh fetch;feature push;main fast-forward;no force;existing webhook",
"rollback_executed": false
},
"G2L_visual_evidence": {
"method": "Verificação manual pela Tempo, autorizada expressamente na conversa;não foi observação de navegador peloCodex.",
"tool_block": "Permissão guardada/política gerida impediu o Codex de controlar a origemQA18639. Não foi alterada nem contornada.",
"manual_evidence": [
{
"statement": "conferi o SYNTHETIC QA — G2L / Anexo I",
"scope": "Abertura e leitura da páginaQA pelaTempo"
},
{
"statement": "pelo que li e observei não vi nenhuam falha mas tambem não vi nenhum botao gravação/recuperaça",
"scope": "Observação parcial semfalha noquefoivisto;gravação/recuperação ainda não conferidas"
},
{
"statement": "ja procedi com a tua instrução pode verificar",
"scope": "Confirmação pelaTempo da execução da instrução já apresentada:guardar exemploQA,recuperar gravaçãoQA eabrir relatório da gravação recuperada,após clarificação doscontrolos"
}
],
"limits": "Não se atribuem àTempo resultados individuais adicionais não descritos,nem se apresenta captura ou observação visual peloCodex. O ficheiro comprova gravação;isoladamente não comprova cliques de recuperação/abertura. Estes passos são sustentados pela comunicação daTempo.",
"technical_corroboration": {
"record": "iva_l1_g2l_manual_completion_and_actual_UI_payload_20261024",
"saved_at": "2026-10-24T14:32:44.805Z",
"saved_file_sha256": "bfa1b242671b57925d560d1b76a6065a52238f4cbd9f255b17e594384f5e0ef7",
"API_QA": "Ficheiro real→POST/GETprivado,1teste/29asserções;contexto/snapshot exactos;transacção revertida",
"report": "Mesmas funções daQA aplicadas ao snapshot real;contexto,fontes,identidades,versão evalores correspondentes"
},
"existing_references": [
"iva_l1_g2l_manual_verification_route_20261024",
"iva_l1_g2l_manual_partial_controls_20261024",
"iva_l1_g2l_manual_completion_and_actual_UI_payload_20261024",
"iva_l1_g2kl_homologation_20261024"
],
"installed_revision_check_is_visual_proof": false,
"accepted_proofs_repeated": false,
"delivery_closure_preserved": "ccdecbd8/643ba6ed"
}
}
@@ -0,0 +1,288 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "0dc2d64b20ae3d6879e0154f5507b3fdc6031733",
"base_remote_main": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"coverage": {
"group": "G3",
"branches": [
"P038",
"P039",
"P040",
"P041",
"P042",
"P043",
"P045"
],
"scope": "cessation2026/MZN;explicit continuity;no historical exemption/imports"
},
"counts_before": {
"delivered": 36,
"QA": 7,
"functional_pending": 89,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 43,
"QA": 0,
"functional_pending": 89,
"documentary": 1,
"total": 133
},
"QA": "ac948bd8/bda6d1e3;manual Tempo visual confirmation0dc2d64b;3frontend+API1/36+types/build;13frozenbooks unchanged;accepted proofs reused",
"visual_provenance": "Manual Tempo;no Codex browser observation claimed. G2L clarification908c8afc is separate from G3 confirmation0dc2d64b.",
"runtime_delta": [
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "68e0a98d9b1a3190a96d16210e1bb331c23dbbf9aaa218f973ba05dc9c90df55"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "5155a96101393e0dca5f183577587b9b3a9c4e3b981e8491adc0d640301bdcb3"
},
{
"path": "resources/js/lib/iva-temporary-benefits.ts",
"sha256_LF": "99bf065703db32709806475f7e8bfdf0d086cce9b15ab30434f44d8df6ed9230"
}
],
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"previous_release": "/var/www/investmoz-homologacao/releases/e45a1394fa2ca8631593549b3af62093f25d9c13-f5f7e07d",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"release_revision": {
"commit": "ccdecbd8d74596e729f03381d3b37ca22ce5800e",
"branch": "main",
"built_at": "2026-10-24T14:40:55.681401+00:00",
"manifest_sha256": "8ee52a7b3f7c4363f10d73382d85325bbfa331c2e6e44ccd08d92e578cdf2776"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g3-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "0a9ebaa6f883abbea456f5971a35cb2081031735d56138f0d9354a9325591d7a",
"files_sha256": "ec19f952637953c1b286a5dfd5e8cef7861a0564c7d7c5a3187103fc0305a746",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g3_restore_20261024",
"port": 55441,
"source_dump_sha256": "0a9ebaa6f883abbea456f5971a35cb2081031735d56138f0d9354a9325591d7a",
"active_database_writes": 0
}
},
"activation": "Existing Git FF/webhook/installer;no migrations/imports/permissions/newserver fiscal rule",
"rollback": {
"patch": "docs/investmoz/simulations/l1-g3-readonly-rollback-20261024.patch",
"checked": true,
"applied": false,
"preserves": "catalogue/readers/history/reports;prior release and fresh backup retained",
"old_patch": "Earlier patch no longer applies after new helper;new compatible patch generated,old artifact preserved"
},
"L1_complete": false,
"P001": "05/06only",
"statistics_AI": "deferred",
"served_commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"counts_current": {
"delivered": 43,
"QA": 0,
"functional_pending": 89,
"documentary": 1,
"total": 133
},
"installation": {
"protected": {
"installed": {
"status": "installed",
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"previous_release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 3,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "7cb0825e41abb32c82bae73bb0a58da4"
},
"after": {
"rows": 105,
"checksum": "b6d05a7ee1683f104f7fceaee0a6f63f"
}
},
"sessions": {
"before": {
"rows": 17,
"checksum": "453fd7c711ddb39bfdd0105375f3df67"
},
"after": {
"rows": 18,
"checksum": "1920f0ee8d2ddf73ba225bad6a0645d3"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"branch": "main",
"built_at": "2026-10-24T15:02:46.947668+00:00",
"manifest_sha256": "15837af27545a8691647459c00bec56b22d2e624ae9e20033d598d330d686d61"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"temporary-benefit-cessation/1": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporary_sugar": [
"assets/project-dossier-DT-hu-tU.js",
"assets/services-C3-fU-ch.js"
],
"temporary_sugar_industry_goods": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporary_oils_soap": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporary_oils_soap_factory": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporary_oils_soap_inputs": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporary_sugar_cane": [
"assets/project-dossier-DT-hu-tU.js",
"assets/services-C3-fU-ch.js"
],
"temporary_solar_inputs": [
"assets/project-dossier-DT-hu-tU.js"
],
"temporaryBenefitOrigin": [
"assets/project-dossier-DT-hu-tU.js",
"assets/services-C3-fU-ch.js"
]
},
"assets": [
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-document-CU96Nl_4.js",
"status": 200,
"sha256": "56bf3f423b6595b04c870aa8baa2118889152282d87da596f5a807bf5236cc04"
},
{
"file": "assets/project-dossier-DT-hu-tU.js",
"status": 200,
"sha256": "f8f618b305d8f76abfd193d9f73987514279e7c80160de3cfc79871bc02690f4"
},
{
"file": "assets/services-C3-fU-ch.js",
"status": 200,
"sha256": "75c042d62d3c8250b5334be1e38dd99fed88c85a04245a43a539a0c501bcbad0"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-D6KRT634.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"previous_release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"previous_release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"6eefe4b3322461b9a23166e2cd1235e3881765f4"
],
"finished_at": "2026-10-24T15:02:49.533733+00:00"
},
"log_file": "1792854081964720706.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.00s",
"OK (59 tests, 317 assertions)",
"# tests 275",
"# pass 275",
"# fail 0"
],
"log_bytes": 108361
},
"rollback_executed": false
}
}
@@ -0,0 +1,19 @@
--- a/resources/js/components/simulation-operations.tsx
+++ b/resources/js/components/simulation-operations.tsx
@@ -17,6 +17,8 @@
const change=(id:string,patch:Partial<SalesOperation>)=>run(()=>save({...book,rows:book.rows.map(r=>r.id===id?{...r,...patch}:r)}));
const continueTemporary=(id:string,target:string)=>run(()=>save({...book,rows:book.rows.map(row=>row.id===id?continueTemporaryOperation(row,target):row)}));
return <section aria-label="Operações IVA por oportunidade" className="space-y-3 rounded border p-3">
+ <p role="status">Novos cálculos temporariamente suspensos; resultados guardados e relatórios disponíveis.</p>
+ <fieldset disabled>
<h4 className="font-semibold">Operações de IVA — enquadramento das vendas</h4>
<p>Oportunidade {String(draft.context_opportunity||'entrada geral')}; moeda original {book.currency||'por indicar'}. Cobertura2026/MZN. Reutilize as vendas e complete apenas o enquadramento. Este bloco classifica as operações; não substitui nem soma novamente a execução mensal geral acima.</p>
<p>Uma empresa pode ter operações com tratamentos diferentes. Os valores são projecções sob pressupostos declarados, sem certificar facturas, reconhecer créditos ou submeter uma declaração à AT.</p>
@@ -82,6 +84,7 @@
{book.periods.map(p=><label className="block" key={p.period}><input type="checkbox" checked={p.complete} onChange={e=>run(()=>save({...book,periods:book.periods.map(v=>v.period===p.period?{...v,complete:e.target.checked}:v)}))}/> {p.period}: incluí todas as operações deste período; lista vazia significa ausência expressamente confirmada.</label>)}
<p>Limites: outras isenções/bases especiais e correspondência do campo06 permanecem por delimitar. IVA incluído a5% conserva a fracção exacta e apresenta um decimal a6casas; a aproximação de apresentação não constitui regra declarativa. O desconhecido nunca é assumido como zero.</p>
<button type="button" disabled={!book.periods.length} className="rounded bg-emerald-800 p-2 text-white disabled:opacity-50" onClick={()=>run(()=>save(recordSales(draft,book)))}>Calcular e guardar operações IVA</button>
+ </fieldset>
{book.result&&<><p role="status">{salesCurrent(draft,book)?'Resultado correspondente às entradas.':'Resultado histórico conservado; reveja as alterações antes de recalcular.'}</p><dl>{salesReportRows(draft).map(([,label,value,origin],index)=><div className="break-inside-avoid border-t py-2" key={index}><dt className="font-semibold">{label}</dt><dd>{value}<small className="block">{origin}</small></dd></div>)}</dl></>}
</section>;
}
@@ -0,0 +1,270 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "7b54efb0fca9aae0adf174169711cd1f452fe1fb",
"base_remote_main": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"coverage": {
"group": "G4A",
"branches": {
"P074": "export_railway_cfm",
"P075": "export_international_passengers",
"P076": "export_work_on_movables",
"P077": "export_gold_bom",
"P079": "export_packaging"
},
"scope": "2026/MZN/05;statutory conditions and explicit evidence/projection assumptions;no automatic input deduction/ATsubmission"
},
"counts_before": {
"delivered": 43,
"QA": 5,
"functional_pending": 84,
"documentary": 1,
"total": 133
},
"counts_after_delivery": {
"delivered": 48,
"QA": 0,
"functional_pending": 84,
"documentary": 1,
"total": 133
},
"QA": "0f0d2e56/7a58fa24;manual Tempo visual confirmation7b54efb0;3frontend+API1/36+types/build;14frozenbooks unchanged;accepted proofs reused",
"visual_provenance": "Manual Tempo;no Codex browser observation;last saved price-basis edit preserved,prior result historical;no automatic recalculation.",
"runtime_delta": [
{
"path": "resources/js/lib/iva-export-operations.ts",
"sha256_LF": "3e9927aa637db678a558beb80bf7a326afd6b010e7ab5117aacd7e82a2c52600"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "e3ae2cbecd823fc03cd019cfe721cb20ba03ed51c7d0ec2680b55570b0bc7f10"
}
],
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"previous_release": "/var/www/investmoz-homologacao/releases/ccdecbd8d74596e729f03381d3b37ca22ce5800e-0967d766",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"release_revision": {
"commit": "6eefe4b3322461b9a23166e2cd1235e3881765f4",
"branch": "main",
"built_at": "2026-10-24T15:02:46.947668+00:00",
"manifest_sha256": "15837af27545a8691647459c00bec56b22d2e624ae9e20033d598d330d686d61"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g4a-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "a8ada17d7faf38a81ef324064ba3f64d4a65e6040a3381b81cd2109d8d7664b9",
"files_sha256": "e32d2ad5d5fc9a8a65d4010ec9d658f71d120409b5eaf31e0f2de4d4c9d5405f",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g4a_restore_20261024",
"port": 55441,
"source_dump_sha256": "a8ada17d7faf38a81ef324064ba3f64d4a65e6040a3381b81cd2109d8d7664b9",
"active_database_writes": 0
}
},
"activation": "Existing Git FF/webhook/installer;no migrations/imports/permissions/newserver fiscal rule",
"rollback": {
"patch": "docs/investmoz/simulations/l1-g3-readonly-rollback-20261024.patch",
"checked": true,
"applied": false,
"preserves": "catalogue/readers/history/reports;prior release and fresh backup retained"
},
"regulatory_followup": "Official announcement30/09/2026 inventoried separately;not treated as published decree or rule activation;documentary comparison remains specific future work",
"L1_complete": false,
"P001": "05/06only",
"statistics_AI": "deferred",
"served_commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"counts_current": {
"delivered": 48,
"QA": 0,
"functional_pending": 84,
"documentary": 1,
"total": 133
},
"installation": {
"protected": {
"installed": {
"status": "installed",
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"previous_release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 2,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "e2ee1520f58e0600f3f2ae64dee97baa"
},
"after": {
"rows": 105,
"checksum": "9f7ac1ea1ff1adf7db54e32f15d8a4f8"
}
},
"sessions": {
"before": {
"rows": 20,
"checksum": "28b47ffbc97aa8265bdf40d6658deaa0"
},
"after": {
"rows": 21,
"checksum": "b08ed52e696c3a91c4e1b889efad552a"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"branch": "main",
"built_at": "2026-10-24T15:20:59.537796+00:00",
"manifest_sha256": "846e0a05a6ed579d7f9978dc8db94e2e047fecc1c2dc489e55c0716eb75156a5"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"export-direct-operations/1": [
"assets/project-dossier-Rt7qSc3z.js"
],
"export_railway_cfm": [
"assets/project-dossier-Rt7qSc3z.js"
],
"export_international_passengers": [
"assets/project-dossier-Rt7qSc3z.js"
],
"export_work_on_movables": [
"assets/project-dossier-Rt7qSc3z.js"
],
"export_gold_bom": [
"assets/project-dossier-Rt7qSc3z.js"
],
"export_packaging": [
"assets/project-dossier-Rt7qSc3z.js"
]
},
"assets": [
{
"file": "assets/services-eQvgi8ww.js",
"status": 200,
"sha256": "1d94e9315eab7d2e2e00c29bf9ae3bef1eadc86faaff73c163daea40709576c0"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-document-BeYOfJX9.js",
"status": 200,
"sha256": "1f68d9c7de6aff36a051177bf11744a75411560cfe5e8af2d18e52bb4d226d70"
},
{
"file": "assets/project-dossier-Rt7qSc3z.js",
"status": 200,
"sha256": "3ad22a0458da55242ff4d3e88cc22461e5ec6c0f0aadd452936d50a999558a68"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-BEf0yjMF.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"previous_release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"previous_release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"b898955603eb7698ab10f4c4ab4115bffd80b7b2"
],
"finished_at": "2026-10-24T15:21:02.478696+00:00"
},
"log_file": "1792855174037587994.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.42s",
"OK (59 tests, 317 assertions)",
"# tests 278",
"# pass 278",
"# fail 0"
],
"log_bytes": 109100
},
"rollback_executed": false
}
}
@@ -0,0 +1,266 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "f946364b",
"QA_record": "0b0e002d",
"Git_preparation_head": "0b0e002d1573c3da838a8a4ea296c7a9094acef6",
"fresh_remote_main": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"ancestry": "ancestor;normal nonforce push only after authenticated preflight and fresh backup/restore",
"coverage": {
"group": "G4B",
"branches": {
"P065": [
"international_ship_operations"
],
"P066": [
"international_aircraft_operations"
],
"P068": [
"international_ship_direct_services",
"international_aircraft_direct_services"
]
},
"branch_count": 3,
"treatment_count": 4,
"scope": "2026/MZN/05;eligible vessel/aircraft operations and direct needs services;no supplies/input deduction/ATsubmission"
},
"runtime_delta": [
{
"path": "resources/js/lib/iva-international-assets.ts",
"sha256_LF": "fa99cf40622d8a6aaea4e3078d6c9e41d26a4a2bda5898f5bd114aa4221eaa1c"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "795e07a1a9b81372c3124b037d6df9626501aafcd7224290bbac2b8ec44f6d9b"
}
],
"counts_current": {
"delivered": 51,
"QA": 0,
"functional_pending": 81,
"documentary": 1,
"total": 133
},
"counts_after_delivery_only": {
"delivered": 51,
"QA": 0,
"functional_pending": 81,
"documentary": 1,
"total": 133
},
"proofs": "3frontend/APIQA1/35/types/build;15previousbooks unchanged;manual Tempo visual0b0e002d;accepted proofs reused,no new browser verification required",
"rollback": "l1-g3-readonly-rollback-20261024.patch checked on current candidate,not applied;preserves catalogue/readers/history/reports;retain prior release and verified new backup",
"activation": "Existing Git FF/webhook/installer;no migrations/imports/permission changes/server fiscal activation",
"authenticated_destination": "Fresh read confirmed b8989556;installer inactive",
"new_backup_restore": "Verified fresh backup and real isolated restore,no active restore performed",
"served_revision_and_delta": "verified",
"P001": "05/06only",
"L1_complete": false,
"statistics_AI": "deferred",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"previous_release": "/var/www/investmoz-homologacao/releases/6eefe4b3322461b9a23166e2cd1235e3881765f4-e17c49ea",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"release_revision": {
"commit": "b898955603eb7698ab10f4c4ab4115bffd80b7b2",
"branch": "main",
"built_at": "2026-10-24T15:20:59.537796+00:00",
"manifest_sha256": "846e0a05a6ed579d7f9978dc8db94e2e047fecc1c2dc489e55c0716eb75156a5"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g4b-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "946e9ebc067932184a8db32e1d469edada1c0fd52eec5cabd97958b528bee060",
"files_sha256": "37d5efc4d7b4db3f2bb34bd69ddb8377c26e15fb35f1d95eb512e4ae7aa14962",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g4b_restore_20261024",
"port": 55441,
"source_dump_sha256": "946e9ebc067932184a8db32e1d469edada1c0fd52eec5cabd97958b528bee060",
"active_database_writes": 0
}
},
"served_commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"installation": {
"protected": {
"installed": {
"status": "installed",
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"previous_release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 2,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "1d9a40d14abc8a507b9f21c53214cab3"
},
"after": {
"rows": 105,
"checksum": "4ac1b3b4c92159a6c6d5b2001b33c281"
}
},
"sessions": {
"before": {
"rows": 23,
"checksum": "3416544d03e316d171c3c5b4ef17f76d"
},
"after": {
"rows": 24,
"checksum": "5c130a5a49411a488f3dd2e04a3ebf30"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"branch": "main",
"built_at": "2026-10-24T15:42:16.426339+00:00",
"manifest_sha256": "ae95aa3000f8861d3a092026b04fd18dff05c7e1955f99f7660e18b945e32f15"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"international-assets/1": [
"assets/project-dossier-DTxHeV9m.js"
],
"international_ship_operations": [
"assets/project-dossier-DTxHeV9m.js"
],
"international_aircraft_operations": [
"assets/project-dossier-DTxHeV9m.js"
],
"international_ship_direct_services": [
"assets/project-dossier-DTxHeV9m.js"
],
"international_aircraft_direct_services": [
"assets/project-dossier-DTxHeV9m.js"
]
},
"assets": [
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-DTxHeV9m.js",
"status": 200,
"sha256": "d1db999b1c04537d77ba5613230a9fb0e4cbc6ce06bc5346371bfbb65b98339f"
},
{
"file": "assets/services-Dy0KLLRZ.js",
"status": 200,
"sha256": "e942686d95f79fb4a5b00f670db08f3b70078aa5de1b46eb01c66e3de93149b5"
},
{
"file": "assets/project-dossier-document-DtAisp01.js",
"status": 200,
"sha256": "804ac2e496efeb7c4fc8150295ca8df2c736ec8f38469382ca658f65835fff5c"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-qEH7_IO_.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"previous_release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"previous_release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"a153d0782f0f1f5a553a2c6d7106bc35059a170b"
],
"finished_at": "2026-10-24T15:42:18.840229+00:00"
},
"log_file": "1792856451333116729.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 25.53s",
"OK (59 tests, 317 assertions)",
"# tests 281",
"# pass 281",
"# fail 0"
],
"log_bytes": 110076
},
"rollback_executed": false
}
}
@@ -0,0 +1,263 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "b1c8e0e3",
"QA_record": "2fccbc8ee8d0ff687c9d49a54cf2972546182f3a",
"fresh_remote_main": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"coverage": {
"group": "G4C",
"branches": {
"P072": "export_customs_related_services",
"P073": "export_dispatch_services",
"P078": "export_disclosed_intermediation"
},
"branch_count": 3,
"treatment_count": 3,
"scope": "2026/MZN/05; direct customs-related services, dispatch abroad, disclosed intermediation; own service territoriality identified"
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "284cb1bac2a2c5646d9f05c0503a57c568079f75081b6cf0cff98747d8564581"
},
{
"path": "resources/js/lib/iva-export-services.ts",
"sha256_LF": "090de228fc5563de98e0c4c3e1646804b05d71a84603d6d42e63b7cebfa32301"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "8c934a9c3126fc8e6cac005bae00e081fcf8a6d184cf9370757e3aab73995ee3"
}
],
"counts_current": {
"delivered": 54,
"QA": 0,
"functional_pending": 78,
"documentary": 1,
"total": 133
},
"counts_after_delivery_only": {
"delivered": 54,
"QA": 0,
"functional_pending": 78,
"documentary": 1,
"total": 133
},
"proofs": "4frontend;APIQA1/39;16priorbooks intact/current;types/build;Tempo manual visual reply verificada;no accepted proof repeated",
"rollback": "l1-g3-readonly-rollback-20261024.patch checked on G4C candidate, not applied; retains readers/history/reports; previous release and fresh verified backup retained",
"activation": "Existing Git normal FF/webhook/installer; no migrations/imports/permission changes or formal fiscal activation",
"authenticated_preflight_file": "outputs/iva-l1-g4-services-20261024/destination-preflight.txt",
"backup_restore": {
"backup": {
"stage": "/var/backups/investmoz-l1-g4c-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "41dd7cb9e858e4398e23950e9e34289014912f67ad55b9f7ae9f14f94b03584b",
"files_sha256": "58d984f98e2da29ee269a9da91085680c9e8e7e557c65fe4e963d1f871a63a54",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_g4c_restore_20261024",
"port": 55441,
"source_dump_sha256": "41dd7cb9e858e4398e23950e9e34289014912f67ad55b9f7ae9f14f94b03584b",
"active_database_writes": 0
}
},
"served_revision_and_delta": "verified",
"P001": "05/06 only",
"L1_complete": false,
"statistics_AI": "deferred",
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"previous_release": "/var/www/investmoz-homologacao/releases/b898955603eb7698ab10f4c4ab4115bffd80b7b2-55ab681a",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"release_revision": {
"commit": "a153d0782f0f1f5a553a2c6d7106bc35059a170b",
"branch": "main",
"built_at": "2026-10-24T15:42:16.426339+00:00",
"manifest_sha256": "ae95aa3000f8861d3a092026b04fd18dff05c7e1955f99f7660e18b945e32f15"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"authenticated_destination": "Fresh read confirmed a153d078; installer inactive",
"new_backup_restore": "Verified fresh backup and real isolated restore, no active restore performed",
"served_commit": "679203d4b13cd5b88ab05a0da539c359c37cc426",
"installation": {
"protected": {
"installed": {
"status": "installed",
"commit": "679203d4b13cd5b88ab05a0da539c359c37cc426",
"release": "/var/www/investmoz-homologacao/releases/679203d4b13cd5b88ab05a0da539c359c37cc426-6ad3a32e",
"previous_release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 3,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 105,
"checksum": "0fb368359b09686e698bb76c130bec32"
},
"after": {
"rows": 105,
"checksum": "a1a597d8371e7a308d133b1374ddc3fa"
}
},
"sessions": {
"before": {
"rows": 26,
"checksum": "e335b7f5c76ce5d198e96a1d0736ee13"
},
"after": {
"rows": 15,
"checksum": "d8d7871c3369ade4d97c078a5d67899f"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "679203d4b13cd5b88ab05a0da539c359c37cc426",
"branch": "main",
"built_at": "2026-10-24T15:58:35.074611+00:00",
"manifest_sha256": "7b37d131d7b9564d901d8fc21407a759fcded9ba734c3757ce0fda5c00cc5c56"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"export-linked-services/1": [
"assets/project-dossier-B13GvS2h.js"
],
"export_customs_related_services": [
"assets/project-dossier-B13GvS2h.js"
],
"export_dispatch_services": [
"assets/project-dossier-B13GvS2h.js"
],
"export_disclosed_intermediation": [
"assets/project-dossier-B13GvS2h.js"
],
"relatedExport": [
"assets/project-dossier-B13GvS2h.js",
"assets/services-T9xhkEbY.js"
]
},
"assets": [
{
"file": "assets/project-dossier-document-D3wD6GVC.js",
"status": 200,
"sha256": "f785b98c98fa31f087cfe4de205ff24d888b15c0d9aa7e76a1a03c8faa1afb83"
},
{
"file": "assets/project-dossier-B13GvS2h.js",
"status": 200,
"sha256": "1746a5eed08eb3cc85c98324ae5c60cea44ef9878e9e3aa495eb2d642fe0f0fa"
},
{
"file": "assets/services-T9xhkEbY.js",
"status": 200,
"sha256": "c6ffdcf297a76cf91dda66c5ca3ec338d36d638ddf59992c0e1d245f12551286"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-CKbcQpAl.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "679203d4b13cd5b88ab05a0da539c359c37cc426",
"release": "/var/www/investmoz-homologacao/releases/679203d4b13cd5b88ab05a0da539c359c37cc426-6ad3a32e",
"previous_release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "679203d4b13cd5b88ab05a0da539c359c37cc426",
"release": "/var/www/investmoz-homologacao/releases/679203d4b13cd5b88ab05a0da539c359c37cc426-6ad3a32e",
"previous_release": "/var/www/investmoz-homologacao/releases/a153d0782f0f1f5a553a2c6d7106bc35059a170b-789a22ef",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"679203d4b13cd5b88ab05a0da539c359c37cc426"
],
"finished_at": "2026-10-24T15:58:37.723730+00:00"
},
"log_file": "1792857429090761953.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 24.89s",
"OK (59 tests, 317 assertions)",
"# tests 285",
"# pass 285",
"# fail 0"
],
"log_bytes": 111289
},
"rollback_executed": false
}
}
@@ -0,0 +1,512 @@
{
"status": "installed_delta_verified_partial_L1",
"candidate": "4a35d63cd3535195e4e2a37740b2f52813ff1da9",
"base_remote_main": "1655f57e698fef4099c2886069a79cd1c920f792",
"fetch": "completed;noforce;localmainnotused",
"bundle": {
"path": "outputs\\iva-l1-g2-social-20261024\\l1-joint-4a35d63c.bundle",
"candidate": "4a35d63cd3535195e4e2a37740b2f52813ff1da9",
"base": "1655f57e698fef4099c2886069a79cd1c920f792",
"sha256": "7e23cabda77c8e7b117091a08613436f02c32a9d23d023d4d030c9041eb43146",
"bytes": 166937,
"verified": true,
"content": "FunctionalQAcommit4a35d63c+historyfromorigin/main;receiptmetadatafinalizedseparately;noactivepush"
},
"coverage": {
"initial_QA": "544068e8/d89912e5:10conditionaltreatments",
"rational_QA": "689e7cbe/8719e916;exactincluded5%andreaders",
"G1": "5030116e/89ab2883:4branches/4treatments",
"G2A": "675cf38f/0e644b55:5branches/5treatments",
"G2B": {
"AUD-SIM-L1-P009": [
"social_assistance_public",
"social_assistance_nonprofit"
],
"AUD-SIM-L1-P011": [
"social_care_public",
"social_care_nonprofit"
],
"AUD-SIM-L1-P012": [
"activity_facilities_public",
"activity_facilities_nonprofit"
]
},
"conditional_treatments_total": 25,
"indeterminate_options": 2,
"QA_covered_inventory_IDs": [
"AUD-SIM-L1-P003",
"AUD-SIM-L1-P004",
"AUD-SIM-L1-P005",
"AUD-SIM-L1-P006",
"AUD-SIM-L1-P007",
"AUD-SIM-L1-P009",
"AUD-SIM-L1-P011",
"AUD-SIM-L1-P012",
"AUD-SIM-L1-P017",
"AUD-SIM-L1-P018",
"AUD-SIM-L1-P029",
"AUD-SIM-L1-P030"
],
"pending_functional_IDs": [
"AUD-SIM-L1-P002",
"AUD-SIM-L1-P008",
"AUD-SIM-L1-P010",
"AUD-SIM-L1-P013",
"AUD-SIM-L1-P014",
"AUD-SIM-L1-P015",
"AUD-SIM-L1-P016",
"AUD-SIM-L1-P019",
"AUD-SIM-L1-P020",
"AUD-SIM-L1-P021",
"AUD-SIM-L1-P022",
"AUD-SIM-L1-P023",
"AUD-SIM-L1-P024",
"AUD-SIM-L1-P025",
"AUD-SIM-L1-P026",
"AUD-SIM-L1-P027",
"AUD-SIM-L1-P028",
"AUD-SIM-L1-P031",
"AUD-SIM-L1-P032",
"AUD-SIM-L1-P033",
"AUD-SIM-L1-P034",
"AUD-SIM-L1-P035",
"AUD-SIM-L1-P036",
"AUD-SIM-L1-P037",
"AUD-SIM-L1-P038",
"AUD-SIM-L1-P039",
"AUD-SIM-L1-P040",
"AUD-SIM-L1-P041",
"AUD-SIM-L1-P042",
"AUD-SIM-L1-P043",
"AUD-SIM-L1-P044",
"AUD-SIM-L1-P045",
"AUD-SIM-L1-P046",
"AUD-SIM-L1-P047",
"AUD-SIM-L1-P048",
"AUD-SIM-L1-P049",
"AUD-SIM-L1-P050",
"AUD-SIM-L1-P051",
"AUD-SIM-L1-P052",
"AUD-SIM-L1-P053",
"AUD-SIM-L1-P054",
"AUD-SIM-L1-P055",
"AUD-SIM-L1-P056",
"AUD-SIM-L1-P057",
"AUD-SIM-L1-P058",
"AUD-SIM-L1-P059",
"AUD-SIM-L1-P060",
"AUD-SIM-L1-P061",
"AUD-SIM-L1-P062",
"AUD-SIM-L1-P063",
"AUD-SIM-L1-P064",
"AUD-SIM-L1-P065",
"AUD-SIM-L1-P066",
"AUD-SIM-L1-P067",
"AUD-SIM-L1-P068",
"AUD-SIM-L1-P069",
"AUD-SIM-L1-P070",
"AUD-SIM-L1-P071",
"AUD-SIM-L1-P072",
"AUD-SIM-L1-P073",
"AUD-SIM-L1-P074",
"AUD-SIM-L1-P075",
"AUD-SIM-L1-P076",
"AUD-SIM-L1-P077",
"AUD-SIM-L1-P078",
"AUD-SIM-L1-P079",
"AUD-SIM-L1-P080",
"AUD-SIM-L1-P081",
"AUD-SIM-L1-P082",
"AUD-SIM-L1-P083",
"AUD-SIM-L1-P084",
"AUD-SIM-L1-P085",
"AUD-SIM-L1-P086",
"AUD-SIM-L1-P087",
"AUD-SIM-L1-P088",
"AUD-SIM-L1-P089",
"AUD-SIM-L1-P090",
"AUD-SIM-L1-P091",
"AUD-SIM-L1-P092",
"AUD-SIM-L1-P093",
"AUD-SIM-L1-P094",
"AUD-SIM-L1-P095",
"AUD-SIM-L1-P096",
"AUD-SIM-L1-P097",
"AUD-SIM-L1-P098",
"AUD-SIM-L1-P099",
"AUD-SIM-L1-P100",
"AUD-SIM-L1-P101",
"AUD-SIM-L1-P102",
"AUD-SIM-L1-P103",
"AUD-SIM-L1-P104",
"AUD-SIM-L1-P105",
"AUD-SIM-L1-P106",
"AUD-SIM-L1-P107",
"AUD-SIM-L1-P108",
"AUD-SIM-L1-P109",
"AUD-SIM-L1-P110",
"AUD-SIM-L1-P111",
"AUD-SIM-L1-P112",
"AUD-SIM-L1-P113",
"AUD-SIM-L1-P114",
"AUD-SIM-L1-P115",
"AUD-SIM-L1-P116",
"AUD-SIM-L1-P117",
"AUD-SIM-L1-P118",
"AUD-SIM-L1-P119",
"AUD-SIM-L1-P120",
"AUD-SIM-L1-P121",
"AUD-SIM-L1-P122",
"AUD-SIM-L1-P123",
"AUD-SIM-L1-P124",
"AUD-SIM-L1-P125",
"AUD-SIM-L1-P126",
"AUD-SIM-L1-P127",
"AUD-SIM-L1-P128",
"AUD-SIM-L1-P129",
"AUD-SIM-L1-P130",
"AUD-SIM-L1-P131",
"AUD-SIM-L1-P132",
"AUD-SIM-L1-P133"
],
"pending_documentary_IDs": [
"AUD-SIM-L1-P001"
]
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-monthly-iva.tsx",
"sha256_LF": "27e9f7b0a6cd011d6278d5bf507c8df0a290432006d795e9f7bf03b05fc6b350"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "ae8fafbff339c4b52bae11ad479caf0fb451e5543e59bfbf15becf9aab4c5d27"
},
{
"path": "resources/js/lib/fiscal-rational.ts",
"sha256_LF": "91234efa465a8660f71a56e48d280a602c56ecf2ccce9cf7a8d91db513a3ffd3"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "846dbd2d2dbdd54ffcddae8623eeaa2ae4f7686c6e2db05590ffa893d3ffbfb0"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "fb41bf3d6cf14ee65bf242f5a2504f9d4758c8d87bb4c4e9eda4822f74aa4d7f"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "5a6ea8a8c7261fa1d24cca56e92617cd66f72bd027dbafec22d051e686e927d7"
}
],
"schema_routes_permissions_dependencies_changed": false,
"database_imports_migrations_seeds": [],
"server_fiscal_rule_activation": false,
"activation": {
"method": "ExistingGitFF/merge+build+webhook;no new mandatory flag",
"preflight": [
"Re-fetchorigin/main;reconcileconcurrentchangeswithoutforce",
"Confirmactualservedrevisionandvalidbackup/restoreresultthroughauthenticatedexistingprocess",
"Usecompiledassets;excludeoutputs/syntheticdata/publichot/secrets",
"No globalmigration,seed,taxpublication or datareplacement"
],
"installed_delta_only": [
"servedrevisionandmanifesthash",
"simulatorusesnewasset",
"newoptions/readerscontextvisible;existingdraftrecoverable",
"prioracceptedproofsreused;nosyntheticwritesinactive"
],
"completed": true,
"database_migrations": 0,
"content_imports": 0
},
"reversal": {
"preferred": "ForwardGitcompatibilitycontainmentcommitusingpreparedreadonlypatch,notDBrestore;revertcontainmentcommitafterfix",
"patch": {
"patch": "docs\\investmoz\\simulations\\l1-joint-readonly-rollback-20261024.patch",
"patch_sha256": "d25a81f025ffeeb5869161404eb23b9762d87e07b4a820c14b63d29359d0db0e",
"component_before_sha256": "37676ccb4302e5fdf5dceb58291809f120ea204c2a8c6a59ede9585f8753aa73",
"git_apply_check": true,
"live_component_changed": false,
"purpose": "Operational compatibility rollback: suspend edits/calculations in L1 panel only;keep catalogue,readers,history,API,otherforms and reports;no DBrestore or broad path disable"
},
"QA_UI": "L1inputs/calculationdisabled;details/result600MZN/revision3/readers/reportsremain;otherforms/APIpermissionsunchanged",
"limitations": "UIoperationalcontainment,notAPIauthorizationchange;fullrollbackto1655wouldhidenewL1readersandisnotpreferred"
},
"destination_precheck": {
"public_revision_url": "https://teste-investidor.tempo.co.mz/build/revision.json",
"result": "Authenticateddestinationverified;existingdeliveryHTTPclient200;defaulturllib403/Cloudflare1010",
"served_revision_verified_this_pass": true,
"protected_installer_or_current_backup_verified": true,
"historical_initial_result": "HTTP403 before client diagnostic",
"diagnostic": [
{
"request": "default",
"status": 403,
"headers": {
"Content-Type": "text/plain; charset=UTF-8",
"Server": "cloudflare",
"CF-RAY": "a4f8f78b4cb51d20-JNB"
},
"body_sha256": "2938e9f1284180959e33ab1718d0793a72ff6e4cdb8108c34dcd14e69446de5c",
"error_excerpt": "error code: 1010\n"
},
{
"request": "existing_delivery",
"status": 200,
"headers": {
"Content-Type": "application/json",
"Server": "cloudflare",
"CF-RAY": "a4f8f78bdf3c3575-JNB"
},
"body_sha256": "ad3f581baf0ef17706246b1f87c5fd0fd3659b14c6ed8f7661a19d68d838d40b",
"commit": "1655f57e698fef4099c2886069a79cd1c920f792"
}
],
"cloudflare_reference": "https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-1xxx-errors/error-1010/",
"conclusion": "Cloudflare1010forurllibdefault;existingdeliveryclient200;specificCloudflarerulenotinspected;noapplicationpermissioncauseorconfigurationchangerequired"
},
"excluded": [
"P001mapping",
"120unimplementedbranches",
"newtaxes",
"IRPC/IRPS",
"statistics/AI",
"syntheticQArecordsandruntimefiles"
],
"delivery_performed": true,
"integration_preview": {
"remote": "1655f57e698fef4099c2886069a79cd1c920f792",
"merge_tree": "2284cf875e1b2ee6dd34ae5d182f57a3c194bf22",
"candidate_tree_equal": true,
"fast_forward_possible": true,
"conflicts": false,
"main_not_moved": true,
"scope": "Historicalpreparationpreview,beforeauthorizedmainfastforward"
},
"delivery_commit": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"previous_main": "1655f57e698fef4099c2886069a79cd1c920f792",
"installation": {
"authenticated_preflight": {
"installed": {
"status": "installed",
"commit": "1655f57e698fef4099c2886069a79cd1c920f792",
"release": "/var/www/investmoz-homologacao/releases/1655f57e698fef4099c2886069a79cd1c920f792-fe9d3b11",
"previous_release": "/var/www/investmoz-homologacao/releases/cd10cccbf45f53836d8bf7b2bd90794d99602cb9-a38feaad",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/1655f57e698fef4099c2886069a79cd1c920f792-fe9d3b11",
"release_revision": {
"commit": "1655f57e698fef4099c2886069a79cd1c920f792",
"branch": "main",
"built_at": "2026-10-24T10:18:11.360273+00:00",
"manifest_sha256": "dfb82481796aaf5826e8a5108575de3807ee787faffa92f38a56bb8d9caf5ce7"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"backup": {
"stage": "/var/backups/investmoz-l1-joint-delivery-20261024/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "6e9a2b0b350b0effe0812e7e5faa5c9c1886611a50c1be5f8b00515d7ef0c5ea",
"files_sha256": "53c170aa33714e78d997790cb7c75d672e9680052f7b2ffa5bccf2b719ca248e",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "l1_joint_restore_20261024",
"port": 55441,
"source_dump_sha256": "6e9a2b0b350b0effe0812e7e5faa5c9c1886611a50c1be5f8b00515d7ef0c5ea",
"active_database_writes": 0
},
"installer": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"previous_release": "/var/www/investmoz-homologacao/releases/1655f57e698fef4099c2886069a79cd1c920f792-fe9d3b11",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"previous_release": "/var/www/investmoz-homologacao/releases/1655f57e698fef4099c2886069a79cd1c920f792-fe9d3b11",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"490527b92cf1ca18122679440ff3a38933b7e0c2"
],
"finished_at": "2026-10-24T12:30:02.029150+00:00"
},
"log_file": "1792844919670368682.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 23.74s",
"OK (59 tests, 317 assertions)",
"# tests 247",
"# pass 247",
"# fail 0"
],
"log_bytes": 100122
},
"protected_preservation": {
"installed": {
"status": "installed",
"commit": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"release": "/var/www/investmoz-homologacao/releases/490527b92cf1ca18122679440ff3a38933b7e0c2-d41ae12f",
"previous_release": "/var/www/investmoz-homologacao/releases/1655f57e698fef4099c2886069a79cd1c920f792-fe9d3b11",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 6,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 104,
"checksum": "41ddf6abf1cc00b85fb98a5c22da0ee1"
},
"after": {
"rows": 105,
"checksum": "23e7205245a904489ac3c12248d6b1ac"
}
},
"sessions": {
"before": {
"rows": 17,
"checksum": "436718228e6cb875393809c4a84ebd43"
},
"after": {
"rows": 18,
"checksum": "becbef33ee3be158db37e1878aec832b"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "490527b92cf1ca18122679440ff3a38933b7e0c2",
"branch": "main",
"built_at": "2026-10-24T12:29:59.442400+00:00",
"manifest_sha256": "b9f7c6d05c78754dd1f9efb71bf5ff59cdfaa1167e136a71138c0fd194b19a33"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"iva-operations-l1/2": [
"assets/project-dossier-Cqjhibc1.js"
],
"financial_stamp": [
"assets/project-dossier-Cqjhibc1.js"
],
"insurance_stamp": [
"assets/project-dossier-Cqjhibc1.js"
],
"health_assistive": [
"assets/project-dossier-Cqjhibc1.js"
],
"patient_transport": [
"assets/project-dossier-Cqjhibc1.js"
],
"social_assistance_": [
"assets/project-dossier-Cqjhibc1.js"
],
"social_care_": [
"assets/project-dossier-Cqjhibc1.js"
],
"activity_facilities_": [
"assets/project-dossier-Cqjhibc1.js"
],
"nonprofit": [
"assets/project-dossier-Cqjhibc1.js"
],
"exactFields": [
"assets/project-dossier-Cqjhibc1.js"
],
"20/21": [
"assets/project-dossier-Cqjhibc1.js"
]
},
"assets": [
{
"file": "assets/services-DUPANwbE.js",
"status": 200,
"sha256": "cfdd24a5527c693b0a227726babd1a054425c19cc4a0ebe5f215f582ba5bf302"
},
{
"file": "assets/simulation-form-CPZAFZU3.js",
"status": 200,
"sha256": "c6bcf64e60a5eeac0cafe3dc055dc5544162f21942ee08b34d51bc6d52947567"
},
{
"file": "assets/project-dossier-Cqjhibc1.js",
"status": 200,
"sha256": "937fd99184c12b1321abf86bf67a196c6d74db5296304bc7a746536653560e64"
},
{
"file": "assets/project-dossier-document-91ZtwN0x.js",
"status": 200,
"sha256": "73cb4b1b4ea8928de313cfa858896bfc613dfd0adfb091744a78c81cf5f47764"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-DVti_AMl.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"git_method": "Freshfetch+ancestry/hashcheck+branchpush+fastforwardmain;noforce;normalwebhook",
"rollback_activated": false
}
}
@@ -0,0 +1,19 @@
--- a/resources/js/components/simulation-operations.tsx
+++ b/resources/js/components/simulation-operations.tsx
@@ -9,6 +9,8 @@
const save=(next:SalesBook)=>onChange('modelo_a_snapshot',saveSalesBook(draft,next));
const change=(id:string,patch:Partial<SalesOperation>)=>run(()=>save({...book,rows:book.rows.map(r=>r.id===id?{...r,...patch}:r)}));
return <section aria-label="Operações IVA por oportunidade" className="space-y-3 rounded border p-3">
+ <p role="status">Novos cálculos de operações IVA temporariamente suspensos. Resultados guardados e relatórios permanecem disponíveis.</p>
+ <fieldset disabled>
<h4 className="font-semibold">Operações de IVA — enquadramento das vendas</h4>
<p>Oportunidade {String(draft.context_opportunity||'entrada geral')}; moeda original {book.currency||'por indicar'}. Cobertura2026/MZN. Reutilize as vendas e complete apenas o enquadramento. Este bloco classifica as operações; não substitui nem soma novamente a execução mensal geral acima.</p>
<p>Uma empresa pode ter operações com tratamentos diferentes. Os valores são projecções sob pressupostos declarados, sem certificar facturas, reconhecer créditos ou submeter uma declaração à AT.</p>
@@ -36,6 +38,7 @@
{book.periods.map(p=><label className="block" key={p.period}><input type="checkbox" checked={p.complete} onChange={e=>run(()=>save({...book,periods:book.periods.map(v=>v.period===p.period?{...v,complete:e.target.checked}:v)}))}/> {p.period}: incluí todas as operações deste período; lista vazia significa ausência expressamente confirmada.</label>)}
<p>Limites: outras isenções/bases especiais e correspondência do campo06 permanecem por delimitar. IVA incluído a5% conserva a fracção exacta e apresenta um decimal a6casas; a aproximação de apresentação não constitui regra declarativa. O desconhecido nunca é assumido como zero.</p>
<button type="button" disabled={!book.periods.length} className="rounded bg-emerald-800 p-2 text-white disabled:opacity-50" onClick={()=>run(()=>save(recordSales(draft,book)))}>Calcular e guardar operações IVA</button>
+ </fieldset>
{book.result&&<><p role="status">{salesCurrent(draft,book)?'Resultado correspondente às entradas.':'Resultado histórico conservado; reveja as alterações antes de recalcular.'}</p><dl>{salesReportRows(draft).map(([,label,value,origin],index)=><div className="break-inside-avoid border-t py-2" key={index}><dt className="font-semibold">{label}</dt><dd>{value}<small className="block">{origin}</small></dd></div>)}</dl></>}
</section>;
}
@@ -1,5 +1,81 @@
# Reconciliação do IVA com o Novo Modelo A
## 24/10/2026 — lote08–10/14–18 entregue na homologação em1655f57e
**Estado actual: integrado, instalado e delta conferido; saldo deste lote: zero.** Candidata funcional `d18ff0f0`, registo QA `1655f57e`; revisão efectivamente servida `1655f57e698fef4099c2886069a79cd1c920f792`. Fetch anterior à integração encontrou `origin/main` em `cd10cccb`, antepassado da candidata; push por fast-forward, sem force ou alterações concorrentes a reconciliar. O webhook do processo existente instalou a revisão. Não se editou a pasta servida.
Conferência exclusivamente do delta instalado: `/build/revision.json` em1655f57e, branchmain; manifesto SHA256 `dfb82481796aaf5826e8a5108575de3807ee787faffa92f38a56bb8d9caf5ce7`, igual ao anunciado pela revisão; quatro assets HTTP200, com nove marcadores da nova funcionalidade e recuperação existente. `/simulador-fiscal` HTTP200 usa a entrada deste build; disponibilidade existente do IVA geral mantida. Conteúdo dos bundles verificado contra o próprio manifesto instalado, sem presumir nomes/bytes iguais entre Windows e Linux.
Fontes de moeda/tesouraria, recuperação mensal e motor fiscal publicado, schema, configuração, rotas e executor sem delta face a `cd10cccb`. Referência `276d833a` antepassada; PDF aceite S3 conserva SHA256 `7719a05136f6dba668b621f551626060d10db5fcbb84815cdad112a1eab9079b`, sem regeneração. As provas QA abaixo foram reutilizadas. Sem importações, migrações ou pedidos/cálculos sintéticos criados na homologação. Não se afirma nova auditoria autenticada à base; a prova desta entrega é revisão, manifesto, assets e entradas servidos. Evidência privada: `outputs/iva-acquisitions-delivery-20261024/installed-delta.json`.
Fecho limitado às aquisições08–10 e totais14–18 nas condições demonstradas. Não é apuramento integral do IVA. IRPC/IRPS permanecem inventariados para trabalho posterior; estatísticas/IA adiadas. Os estados QA/pendência de integração seguintes são histórico anterior a esta disponibilização, não o saldo actual.
## 24/10/2026 — aquisições08–10 e totais14–18 implementados e demonstrados em QA
**Estado actual: lote concluído em QA, candidata `d18ff0f0`, ramo `codex/modelo-a-aquisicoes-20261024`; ainda não integrado/disponibilizado na homologação.** S1–S3 continuam encerrados em `cd10cccb`, recibo `355656b5`; referência `276d833a` preservada. Esta secção sucede à proposta e ao cotejo parcial históricos abaixo. Sem IRPC/IRPS, publicação de regras, migração, mudança de permissões ou escrita em dados activos.
### Cotejo concluído antes da codificação
`VAT Return.pdf`: 285479bytes, SHA256 `9c0b99a810c7db53eb75d63c22ee22fb86a50ba57bd5509041ed80ee10f75741`, duas páginas lidas e renderizadas. Comparação com a imagem dos dois DOCX sobre fundo branco e instruções já reconciliadas. Originais intactos. O PDF não fornece critérios adicionais de elegibilidade por aquisição, nem prova nova edição/vigência pela sua existência.
| Campo/instrução | PDF versus DOCX | Tratamento executável |
|---|---|---|
|08–10|Mesma numeração: imobilizado, existências, outros bens/serviços; coluna de imposto a favor do sujeito passivo|Somar apenas IVA elegível das linhas, não orçamento, custo ou valor bruto de compras|
|14|Mesma soma `01+03+05+06+07`|Determinar apenas com parcelas conhecidas|
|15|Mesma soma `08+09+10+11+12`|Aquisições08–10 completas e11/12 determinados; sem operações deve ser declaração expressa|
|16|Mesma soma `02+04+13`|Reutilizar02 da execução mensal actual;04/13 não são zero implícito|
|17/18|Mesmas diferenças `16−15` / `15−16`, conforme o sentido|Diferenças antes de créditos anteriores; não são pagamento ou reembolso reconhecido|
|Regularizações|Ambos dizem11/12 no texto, mas as caixas são12/13|Regularizações fora deste lote; divergência não bloqueia08–10 nem somas inequívocas|
|Créditos/reembolso|Mantêm-se as remissões18/19 versus19/20 e art.20 no rodapé|Afectam o futuro tratamento19–27; não são activadas por esta passagem|
|Preenchimentos/layout|PDF tem cabeçalho completo, duas páginas, inicial/dentro do prazo assinalados, UGC/Província/Localidade Maputo; DOCX tem caixas vazias e imagem do corpo, com fluxo de leitura diferente|Não herdar selecções, prazo ou Maputo para qualquer investimento; não corrigir ou substituir originais|
### Correspondência e percurso executáveis
Componente existente de IVA mensal conserva a execução01/02 no servidor. Novo bloco ligado ao mesmo formulário e relatório guarda `modelo_a_snapshot` no mecanismo privado/versionado existente, com livros separados pela oportunidade em tratamento. Sem escolha numa entrada com várias oportunidades, pede a escolha; nunca assume a primeira. A API conserva as permissões de proprietário e a concorrência por ETag.
Compras/encomendas são reutilizadas com valor/moeda/mês de origem, por classificar como líquido ou bruto. O mês de encomenda/orçamento é conservado separadamente do mês do documento e da dedução; adoptar uma origem actualizada não altera silenciosamente o período fiscal editado. Para08/10 é possível escolher explicitamente o orçamento de activos/despesas operacionais já existente como referência, sem o converter em factura. Só se pede a diferença fiscal/documental. Mudança da origem é sinalizada e exige adopção explícita; não substitui edições deliberadas. Moeda conhecida é conservada; moeda ausente exige confirmação expressa, sem conversão de montantes.
Por linha: líquido/IVA/bruto (dois valores permitem obter o terceiro por soma/diferença, sem taxa de compra inventada), documento/referência/linha/data, fornecedor/inscrição, posse/forma legal, período, natureza projectada ou efectiva declarada, aquisição interna, afectação e exclusões. O adquirente confirma regime normal de IVA. Documento repetido sem linha distinta é recusado. Uma compra só registada, orçamento, documento incompleto, uso misto/especial ou período divergente não gera dedução. IVA expressamente zero e despesas expressamente não elegíveis ficam distintos de informação em falta.
Fundamento dirigido: CIVA republicado pela Lei13/2016, PDF14–16, arts.18(1)(a),18(3–5),19(1)(a),20 e21(1–3); Lei22/2022, art.20 (exclusões/17-A/excepções); Lei10/2025, PDF13, arts.18(2)/(6) e19(2). Reutilização das fontes oficiais aceites, sem nova validação de credibilidade. Âmbito executado: interno geral, MZN, 2026, afectação exclusiva a operações tributadas, mesmo período de emissão/dedução, sem exclusões/especialidades/dedução parcial. É o recorte técnico solicitado, não prazo de vigência legal nem nova regra organizacional. Em projecções, as condições são pressupostos explícitos, sem certificação documental.
Por mês, confirmação expressa de lista completa08–10 e de inexistência de operações nos campos fora deste lote. Sem confirmação, as parcelas e totais dependentes permanecem indeterminados; declarações em conflito com importações/vendas de outros enquadramentos registadas são recusadas.14–18 usam aritmética decimal exacta. Resultados, condições e origem ficam congelados; alterações tornam a versão histórica visivelmente desactualizada. O relatório reutiliza o resultado guardado sem recalcular e identifica oportunidade, localização, período, moeda, fontes, versão e declarações de ausência. A nota da execução isolada01/02 remete agora para o bloco separado, evitando apresentar dois estados contraditórios.
### Provas dirigidas e saldo
- **11 testes frontend aprovados:** oito do novo lote e três da correspondência afectada. Condições incompletas, exclusões, uso misto, documento/fornecedor, data/moeda, duplicações, ausência versus zero, origem alterada, orçamentos reutilizados, fórmulas08–10/14–18, histórico e segunda oportunidade. Exemplo com08=32,09=16,10=8:15=56;16=160.0048;17=104.0048. Também diferença credora18 e vendas em falta.
- **API real QA: dois testes/19 asserções aprovados**, base isolada `simulator_fiscal_delta_20261021_test:55441`, guarda de identidade e transacções revertidas. Payload calculado na interface da segunda oportunidade exportado por acção própria de QA → gravação privada real → recuperação exacta → relatório. Outra conta recusada; primeira oportunidade preservada; fingerprint de todas as regras igual. Nenhuma regra criada/publicada/suspensa.
- **Visual Edge, componentes reais numa interface isolada:** compra sem condições fica indeterminada; edição/cálculo da segunda produz17=`128.0048`; actualizar a página conserva a segunda; regressar à primeira conserva17=`144.0048`. O armazenamento da interface visual é local ao browser; a persistência no servidor foi comprovada separadamente com o mesmo payload na API real de QA.
- **Relatório da segunda oportunidade recuperada pela API:** CSV, Word e PDF apresentam `128.0048`, `160.0048`, MZN, Manica, oportunidade310, período e versão correspondentes, sem valores do livro309. PDF final com seis páginas conferidas visualmente, sem cortes/sobreposição. Abril deliberadamente sem vendas mantém01/02/14/16/17/18 indeterminados; a projecção financeira incompleta é identificada, sem fabricar resultado. Nenhum PDF ou exportação aceite de S1–S3 foi substituído.
- **TypeScript e build aprovados.** Provas privadas em `outputs/iva-operations-qa-20261024`; relatório `acquisitions-final.pdf`, hashes no recibo integrado. A interface de ensaio não é incluída nos assets do portal.
Saldo deste recorte em QA: zero. Integração e disponibilização na homologação continuam por executar. Futuro fora deste recorte: activação de taxa reduzida/isenções, mistos/pro rata/excepções, importações, regularizações, créditos19–27, juros/pagamento/reembolso e submissão AT. IRPC/IRPS permanecem apenas inventariados. Estatísticas e IA adiadas. O histórico abaixo não reabre S1–S3 nem converte esta entrega QA em homologação.
## Actualização de 24/10/2026 — comparação e próximo lote proposto
S1–S3 permanecem encerrados na homologação em `cd10cccb`, recibo `355656b5`, saldo zero. Esta passagem é reconciliação documental/código e proposta; não altera regras, dados activos ou impostos. Reutiliza a leitura visual e as provas aceites de 21/10, sem repetir ensaios.
Os dois originais nas Notas foram relidos por bytes: tamanhos, SHA256 e imagem incorporada coincidem com os valores documentados abaixo. Inventário actual completo das duas pastas: nove documentos nas Notas e quatro em Modelos, além de seis ficheiros temporários/de bloqueio inventariados separadamente, registados com nome, tamanho e hash no recibo integrado, chave `modelo_a_next_scope_20261024`. Os quatro modelos são `VAT Return.pdf`, `IRPC_IRPS.xlsx`, `Cópia de IRPS-IMOP.xlsx` e `IRPC M-22- DECLARACAO DE RENDIMENTOS.pdf`. Os três de IRPC/IRPS entram apenas no inventário; conteúdo fiscal/fórmulas ainda não analisados. `VAT Return.pdf` é exemplar adicional inventariado, ainda por cotejar com os dois DOCX antes de afirmar equivalência ou diferença. Nenhum original alterado, importado ou publicado nesta passagem.
| Bloco | Já suportado / reutilizável | Falta concreta |
|---|---|---|
| Identificação e período, quadros 1–6 | Oportunidade escolhida, dossier, organização, contactos, meses, moeda e origem | Ligar os campos fiscais; confirmar apenas diferenças de NUIT/sucursal/área fiscal/CAE/domicílio fiscal. Sector e localização do projecto não provam CAE ou domicílio fiscal. Tipo de declaração não é versão de projecção. |
| Campos 01/02 | Vendas mensais líquidas e IVA calculado pela versão publicada, recuperação pelo ID, moeda original e exportações aceites | Sem lacuna neste âmbito aceite; continua componente de planeamento, não imposto final a pagar. |
| Campos 03–07 | Calendário de vendas como origem | Classificação por operação, bases separadas, âmbito temporal das categorias e regras correspondentes; mapeamento não é cálculo implementado. |
| Campos 08–11 | Compras/encomendas mensais e pressupostos do plano | Valores líquido/IVA/bruto discriminados, documentos, fornecedor, afectação, exclusões e elegibilidade. Compras e investimento global não são IVA dedutível. |
| Campos 12/13 | Correspondência documental | Regularizações individualizadas, motivo, documento e período; resolver a remissão interna divergente. |
| Campos 14–18 | Fórmulas impressas mapeadas | Consolidação: 14=01+03+05+06+07; 15=08+09+10+11+12; 16=02+04+13; diferenças devedora/credora 17/18. Actualmente indeterminadas: parcelas ausentes não são zero. |
| Campos 19–27 | Planeamento pode conservar estimativas separadas | Créditos efectivos/comunicados, substituição, juros, pagamento, reporte e pedido de reembolso. Não implementados como apuramento declarativo. |
| Quadros 7, 12 e 13 | Autenticação e histórico do portal | Inexistência de operações exige informação completa; assinatura/submissão fiscal e campos reservados à AT não decorrem do login ou da simulação. |
**Diferenças e instruções:** os DOCX diferem por bytes e segmentação textual, com a mesma imagem do formulário; não está demonstrada alteração fiscal entre eles. Mantêm-se as divergências já documentadas: regularizações 11/12 no texto versus caixas 12/13; créditos 18/19 versus caixas 19/20; remissão de reembolso art.20 versus alteração de 2025 no art.21; remissões ambíguas ao quadro8. A duplicação de25 era artefacto de extracção, já resolvido. A edição/período aplicável e os dispositivos pertinentes devem ser cotejados para cada regra nova, reutilizando as fontes oficiais aceites.
**Proposta de lote seguinte — IVA por operação, primeiro âmbito interno geral em MZN:** reutilizar vendas e aquisições do plano por oportunidade/período; guardar origem/versionamento, previsto ou efectivo e classificação explícita. Implementar a discriminação líquido/IVA/bruto e a elegibilidade documentada das aquisições internas de imobilizado, existências e outros bens/serviços (08–10), após cotejo dirigido das condições e exclusões nas fontes existentes. Manter 01/02 e o motor publicado. Ligar 14–18 apenas quando todas as parcelas necessárias estiverem conhecidas ou expressamente declaradas sem operações, sem permitir que essa declaração apague operações existentes. Mostrar a parcela em falta quando o total não puder ser determinado.
Ficam fora deste lote proposto: activação de taxa reduzida, isenções/mistas/pro rata, importações, regularizações, créditos anteriores, substituições, juros, pagamentos, reembolsos e submissão à AT. Podem ser identificados na classificação, mas mantêm resultado indeterminado e explicação quando aplicáveis. IRPC/IRPS permanecem inventário. A proposta estreita o lote histórico abaixo; a estimativa histórica de28–52h não é orçamento deste novo recorte.
Fecho dirigido do lote proposto: reutilização sem preenchimento repetido; aquisição elegível/excluída/sem documento; zero versus ausência; alteração da segunda oportunidade preservando a primeira; mudança de origem cria versão sem reescrever histórico; gravação/recuperação e ecrã/exportações com iguais montantes, moeda, período, oportunidade, fonte e regra. Consolidar apenas os dispositivos efectivamente usados, sem nova validação genérica das fontes. Nenhuma implementação iniciada nesta reconciliação.
21/10/2026. Referência AUD-SIM-INT02, sem nova matriz/backlog. Preparação progressiva em QA; não é apuramento completo, submissão ou aceitação pela AT. A componente16% existente continua independente das restantes componentes por cadastrar/desenvolver. A leitura e aceitação documental da Tempo não é apresentada como validação jurídica independente.
## Exemplar e preservação
@@ -0,0 +1,333 @@
{
"status": "installed_in_homologation_territories_recovered_delta_verified",
"date": "2026-10-23",
"base": "8036b9b0",
"accepted_delivery_receipt": "cdf8fcfb",
"active_comparison": {
"database": {
"database": "teste_investidor",
"port": 5432,
"role": "teste_investidor_app"
},
"read_only": "on",
"published_fiches": 29,
"cluster_relations": 13,
"project_locations": 0,
"RLS": [
{
"relname": "projects",
"relrowsecurity": false,
"relforcerowsecurity": false
},
{
"relname": "project_locations",
"relrowsecurity": false,
"relforcerowsecurity": false
},
{
"relname": "cluster_projects",
"relrowsecurity": false,
"relforcerowsecurity": false
},
{
"relname": "investment_dossiers",
"relrowsecurity": false,
"relforcerowsecurity": false
},
{
"relname": "opportunity_projects",
"relrowsecurity": false,
"relforcerowsecurity": false
}
],
"missing_accepted_locations": 28,
"source_inventory": "inventory-20261007-172113.json",
"cause_scope": "Transported project identities omit accepted territorial rows and citation metadata; visibility recovery only restored publication status. Exact event/time not established."
},
"qa_recovery": {
"mode": "applied",
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"qa": true,
"manifest_sha256": "dc3ae2014da51005d95780e2e4ae87e55e000e66e0765f0671c6e44a958026a0",
"preview_sha256": "601a8603cf39f51a22cef9195e238a21c1552cb3303672b78ec52826c6342b57",
"relations": 28,
"projects": 13,
"relations_restored": 28,
"projects_updated": 13,
"new_dossiers": 0,
"publication_changes": 0
},
"tests": {
"php": {
"tests": 4,
"assertions": 116,
"passed": 4
},
"frontend": {
"tests": 2,
"passed": 2
},
"typescript": "passed",
"build": "passed",
"phpstan_new_recovery_service": "passed, zero errors"
},
"backup": {
"stage": "/var/backups/investmoz-anchor-integration-20261023/backup",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "207ff14c6af7c4b2dd280def898945cb58314e01930b51c50d502e95cbe6ac68",
"files_sha256": "8cd85ab7d5a772452111e4fe7feab48f7fc694ee3f0fbd264f50096254835fe2",
"restore_verified": false
},
"isolated_restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "anchor_restore_20261023",
"port": 55441,
"source_dump_sha256": "207ff14c6af7c4b2dd280def898945cb58314e01930b51c50d502e95cbe6ac68",
"active_database_writes": 0
},
"preserved_closures": [
"6b544548",
"d8224ba8",
"55136b44",
"8036b9b0"
],
"not_repeated": [
"native saved PDF",
"Word",
"ZIP",
"accepted portfolio via opportunity branch",
"accepted complements and four consumers"
],
"deferred": [
"statistics",
"AI"
],
"pending": [],
"screenshots": [
"outputs/anchor-integration-20261023/qa-sector-location.png",
"outputs/anchor-integration-20261023/qa-anchor-fiche.png",
"outputs/anchor-integration-20261023/qa-anchor-dossier.png",
"outputs/anchor-integration-20261023/qa-anchor-simulator.png",
"outputs/anchor-integration-20261023/homologation-sector-location.png",
"outputs/anchor-integration-20261023/homologation-anchor-fiche.png"
],
"visual_QA": {
"anchor_code": "A06",
"anchor_fiche": "57a4ee7a-4c07-4e26-b8f5-e07726e41512",
"case_id": "3fd1bac6-80cf-48c8-97f3-eb4bb3398a17",
"simulation_draft_id": "bbc9ae3d-8c0e-45d2-b93f-9eaa85bab4d4",
"sector": "Agronegócio",
"province": "Sofala",
"offer_invented": false,
"deliberate_title_preserved": true,
"source_link_visible_in_dossier_and_simulator": true,
"manifestation": "HTTP directed proof, including ownership, same-source identity and versioned binding; browser native confirmation cancelled after control timeout; no formal submission"
},
"served_commit": "cf2ddf21a1457f4852fe6aa10069ec3b854f1567",
"functional_commits": [
"3fd5128c",
"cf2ddf21"
],
"installation": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "cf2ddf21a1457f4852fe6aa10069ec3b854f1567",
"release": "/var/www/investmoz-homologacao/releases/cf2ddf21a1457f4852fe6aa10069ec3b854f1567-7749f82e",
"previous_release": "/var/www/investmoz-homologacao/releases/3fd5128c62296bc5c85dcd19f1458a7949de5784-803cd41e",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "cf2ddf21a1457f4852fe6aa10069ec3b854f1567",
"release": "/var/www/investmoz-homologacao/releases/cf2ddf21a1457f4852fe6aa10069ec3b854f1567-7749f82e",
"previous_release": "/var/www/investmoz-homologacao/releases/3fd5128c62296bc5c85dcd19f1458a7949de5784-803cd41e",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"cf2ddf21a1457f4852fe6aa10069ec3b854f1567"
],
"finished_at": "2026-10-23T17:21:57.897758+00:00"
},
"log_file": "1792776037181186915.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 24.44s",
"OK (57 tests, 309 assertions)",
"# tests 216",
"# pass 216",
"# fail 0"
],
"log_bytes": 92267
},
"recovery_preview": {
"mode": "preview",
"database": "teste_investidor",
"port": 5432,
"qa": false,
"manifest_sha256": "d2893d0a638d630435aca1890f79a8094dc58eb65bbdd65a470bb685fa075190",
"preview_sha256": "f59e324222ea480d176f1e8e6ae164efa184904c8244873d3fcf6af8497e0dac",
"relations": 28,
"projects": 13
},
"recovery_applied": {
"mode": "applied",
"database": "teste_investidor",
"port": 5432,
"qa": false,
"manifest_sha256": "d2893d0a638d630435aca1890f79a8094dc58eb65bbdd65a470bb685fa075190",
"preview_sha256": "f59e324222ea480d176f1e8e6ae164efa184904c8244873d3fcf6af8497e0dac",
"relations": 28,
"projects": 13,
"relations_restored": 28,
"projects_updated": 13,
"new_dossiers": 0,
"publication_changes": 0
},
"installed_delta": {
"published_fiches": 29,
"territorial_links": 28,
"affected_projects": 13,
"cluster_relations": 13,
"dossier_rows_unchanged": true,
"clusters_corridors_opportunity_relations_unchanged": true,
"historical_territorial_link_identities_preserved": true,
"only_project_metadata_version_timestamp_changed": true,
"functional_file_hashes_match_Git": {
"app/Http/Controllers/InvestmentPortfolioController.php": true,
"app/Http/Controllers/InvestorContextController.php": true,
"app/Services/ApprovedAnchorTerritories.php": true,
"app/Services/InvestorContext.php": true,
"resources/js/lib/investor-context.ts": true,
"resources/js/lib/project-dossier-report.ts": true,
"resources/js/lib/search-territory.ts": true,
"resources/js/pages/investment/submission.tsx": true,
"resources/js/pages/investor-path/context-start.tsx": true,
"resources/js/pages/investor-path/context.tsx": true,
"resources/js/pages/investor-path/show.tsx": true,
"resources/js/pages/portfolio/index.tsx": true,
"resources/js/pages/portfolio/show.tsx": true,
"routes/web.php": true,
"tools/restore-approved-anchor-territories.php": true
},
"pipeline_summaries": [
"OK (1 test, 3106 assertions)",
"built in 24.44s",
"OK (57 tests, 309 assertions)",
"# tests 216",
"# pass 216",
"# fail 0"
],
"table_preservation": {
"tables": 174,
"changed_tables": {
"audit_events": {
"before": {
"rows": 632,
"checksum": "d4f2e8b30c014080b33a588eb0d8afe2"
},
"after": {
"rows": 645,
"checksum": "88c2047620eb3fad4d2a2837ed3daef5"
}
},
"cache": {
"before": {
"rows": 104,
"checksum": "463aff806806b9fa2e4dff3310f516ec"
},
"after": {
"rows": 104,
"checksum": "4963d5a25fecf3352cf0d7aee73a1e63"
}
},
"project_locations": {
"before": {
"rows": 0,
"checksum": "d41d8cd98f00b204e9800998ecf8427e"
},
"after": {
"rows": 28,
"checksum": "80b4e44b11208a023fcfb989e738b95a"
}
},
"projects": {
"before": {
"rows": 16,
"checksum": "af127d727cfc1050c26b99130e397109"
},
"after": {
"rows": 16,
"checksum": "17fb48a69b09e1e8ec81b0d30e29ce80"
}
},
"sessions": {
"before": {
"rows": 11,
"checksum": "912e728cc332bfc41a7e0f94c84e118d"
},
"after": {
"rows": 15,
"checksum": "713242c22c549258fab61d1b9cd993ef"
}
}
},
"unchanged_tables": 169
},
"exact_29_approved_fiche_identities_preserved": true,
"synthetic_fiches_transported": 0
},
"Git_preservation": {
"accepted_base_receipt": "cdf8fcfb",
"previous_installed": "8036b9b0",
"candidate": "cf2ddf21a1457f4852fe6aa10069ec3b854f1567",
"protected_files_unchanged": {
"app/Services/InvestmentComplements.php": true,
"app/Services/InvestmentConsumerScope.php": true,
"app/Services/InvestorPath.php": true,
"app/Services/SimulationFormDrafts.php": true,
"resources/js/components/investment-complements.tsx": true,
"resources/js/components/dossier-prefill.tsx": true,
"resources/js/components/investment-requirements.tsx": true
},
"matrix_changed_rows_since_accepted_receipt": [
"AUD-REL-02",
"AUD-LEG-06"
],
"other_matrix_records_preserved": 3421,
"accepted_receipt_updates_preserved": [
"AUD-SIM-INT03",
"AUD-SIM-INT06"
],
"schema_migrations_added": [],
"stats_AI_code_changed": false,
"force_push": false
},
"manifest_verification": {
"Git_LF_sha256": "d2893d0a638d630435aca1890f79a8094dc58eb65bbdd65a470bb685fa075190",
"initial_QA_Windows_bytes_sha256": "dc3ae2014da51005d95780e2e4ae87e55e000e66e0765f0671c6e44a958026a0",
"canonicalization": "CRLF to LF only; identical JSON and accepted relations",
"first_active_preview": "refused before writes; corrected canonical preview and apply succeeded"
},
"next": "Tempo final navigation and presentation evaluation",
"not_a_claim_of_complete_transversal_implementation": true,
"installed_public_delta": {
"catalogue": "https://teste-investidor.tempo.co.mz/carteira?kind=project&sector=Agro-ind%C3%BAstria%20e%20agricultura&province_id=f57ff041-6275-57b9-8800-c35e46e0d475",
"results": 1,
"fiche": "57a4ee7a-4c07-4e26-b8f5-e07726e41512",
"source": "portfolio:57a4ee7a-4c07-4e26-b8f5-e07726e41512",
"territories_visible": 4,
"search_return_preserves_filters": true,
"preparation_GET_same_identity_and_province": true,
"homologation_test_dossiers_or_submissions_created": 0
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,253 @@
{
"date": "2026-10-23",
"timezone": "Africa/Johannesburg",
"status": "installed_in_homologation_delta_verified",
"baseline_commit": "4098192a056959d788e6f9ff5cd501211b001f39",
"preserved_acceptance": {
"delivery": "6b544548d3c83fc8a72ab65d8f58f84685a2877f",
"receipt": "4098192a056959d788e6f9ff5cd501211b001f39",
"cases_repeated": false
},
"cause": {
"portfolio_field": "content.focus",
"previous_contract": "string rendered as descriptive text; no complementary selection or typed origin-target relationship in the dossier",
"data_loss_claimed": false
},
"scope": {
"components": [
"irrigation",
"storage",
"cold",
"processing",
"spinning",
"logistics",
"certification",
"training",
"finance"
],
"existing_opportunity_identity_preserved": true,
"documented_sources": [
"portfolio associations including the existing accepted documentary membership",
"public complementary_project_links",
"existing publicly disclosed value-chain references",
"published offering partnerships explicitly associated with the origin"
],
"distinct_states": [
"registered opportunity",
"identified complementary need without a matched offer",
"existing service or instrument",
"previously selected relationship requiring review"
],
"dossier": [
"encrypted existing payload",
"draft",
"preview and confirmation",
"explicit removal and reselection",
"existing audit history",
"source and territory preserved",
"pending edits saved before complementary navigation"
],
"consumers": [
"dossier",
"shared prefill component for simulator, land, desk and submission",
"simulator context snapshot",
"shared report and export rows"
]
},
"validation": {
"database": "simulator_fiscal_delta_20261021_test",
"host": "127.0.0.1",
"port": 55441,
"database_identity_guard": true,
"test_transaction_rollback": true,
"feature_test_file": "tests/Feature/InvestmentComplementsTest.php",
"feature_tests_passed": 8,
"feature_assertions": 134,
"frontend_test_file": "tests/frontend/investment-complements.test.mjs",
"frontend_tests_passed": 2,
"typescript": "passed",
"build": "passed",
"php_syntax": "passed",
"diff_whitespace_check": "passed",
"public_chain_branch": "synthetic public projection contract; not evidence of new real-world chain associations",
"browser_visual_verification": "passed_for_the_requested_complement_scope"
},
"visual_verification": {
"date": "2026-10-23",
"environment": "http://127.0.0.1:18574",
"router": "tools/corridor-agribusiness-qa-router.php",
"database_guard_checked_on_requests": true,
"actor": "existing synthetic QA actor 509; existing normal browser session",
"case_id": "6fdbb963-726e-4048-9884-8cddc04e77a6",
"case_title": "SYNTHETIC QA — conferência visual de complementos 23-10-2026",
"existing_opportunity": {
"id": 286,
"reference": "INV-MZ-GEN-8128691124566423",
"slug": "inv-mz-gen-8128691124566423",
"result": "Opened the existing fiche from the storage complement; the preparation entry retained the portfolio origin and the existing identity. No reimport or duplicate."
},
"need_without_identified_offer": {
"code": "spinning",
"origin": "portfolio:a7271336-808b-42b4-8bfd-5b49c72dbe2b",
"result": "Started idea preparation in the same dossier; recovered as a complementary need with location still undetermined, without inventing an offer or inheriting Sofala."
},
"associated_service": {
"id": 17,
"synthetic_fixture": true,
"origin": "opportunity:309",
"territory": "Gaza",
"result": "Opened the existing QA service fiche, selected it through the return action, confirmed it and recovered it in the same dossier."
},
"multiple_opportunities": {
"first": {
"id": 286,
"territory": "Sofala"
},
"second": {
"id": 309,
"territory": "Gaza",
"synthetic_fixture": true
},
"complementary_opportunity": {
"id": 310,
"origin_id": 309,
"territory": "Gaza",
"synthetic_fixture": true
},
"service_origin_id": 309,
"recovered_after_confirmation_and_browser_reload": true,
"complements_assigned_to_first_automatically": false
},
"fixture_preparation": {
"previous_service_offerings_in_qa": 0,
"new_synthetic_records": "Two projects, two opportunities, one explicit complementary-project link and one associated training offering, solely in the guarded QA database; no grants or real publication/approval claims.",
"preexisting_records_preserved_by_hash": {
"opportunities": 45,
"projects": 17,
"investment_dossiers": 30,
"portal_partnerships": 0
},
"fixtures_and_visual_case_persisted_in_qa": true,
"fixture_receipt": "outputs/complements-visual-20261023/fixture.json"
},
"evidence_directory": "outputs/complements-visual-20261023",
"automated_suites_repeated": false,
"functional_code_changes_in_this_visual_pass": false,
"does_not_demonstrate": [
"multi-opportunity zones and parks",
"specific per-opportunity context in land assistance",
"specific per-opportunity context in virtual desk",
"specific per-opportunity context in manifestation",
"availability of a real training or financing service in homologation"
],
"evidence_files": [
{
"path": "outputs/complements-visual-20261023/existing-opportunity.png",
"bytes": 112261,
"sha256": "93425703b17c0976a5728acc7448faa0b7dd73e34973cb68ebf72cb9d416dd58"
},
{
"path": "outputs/complements-visual-20261023/associated-service.png",
"bytes": 117223,
"sha256": "a5d16746b4264b779430cc3843959492bea41a3da2adc00298fa2133c99aef9d"
},
{
"path": "outputs/complements-visual-20261023/recovered-opportunities.png",
"bytes": 99910,
"sha256": "eb65dd0d42af0c9f553db6756760dcc16f598b2da7b3d0157b6faea3dbebf24e"
},
{
"path": "outputs/complements-visual-20261023/recovered-complements.png",
"bytes": 147972,
"sha256": "4e2db825710665298803542fe9c7f299404962503609948ddd083c3daf195a73"
},
{
"path": "outputs/complements-visual-20261023/recovered-visible-state.json",
"bytes": 2304,
"sha256": "d2ada1b501db973f1492a54f1704e9cb2de112e38cacd4ab916f059dbbd11f18"
},
{
"path": "outputs/complements-visual-20261023/fixture.json",
"bytes": 904,
"sha256": "79fa2ac8196ca5620b258c78332a2462b44f2c5b622fc0c1895fb39199efcd67"
}
]
},
"preservation": {
"active_database_writes": false,
"homologation_installation": false,
"migration": false,
"publication": false,
"import": false,
"new_roles_or_grants": false,
"new_matrix_or_backlog": false
},
"matrix_rows": [
"RF-CLU-003",
"RF-COR-004",
"AUD-REL-02",
"AUD-LEG-06",
"AUD-SIM-INT06"
],
"limitations": [
"Visual verification is limited to the documented QA scenarios; no Tempo acceptance or destination installation is claimed.",
"The resolver covers the nine requested component scopes in available documentary contexts; unmatched expressions and absent relationships are not fabricated.",
"No matched offer means none identified in the examined relationships, not proof that the entire collection has no offer.",
"The existing first-opportunity zone/park selection and complete per-opportunity requirements in other forms remain partial.",
"No global completion of the adaptive journey is claimed."
],
"installation": {
"status": "installed_delta_verified",
"date": "2026-10-23",
"target": "https://teste-investidor.tempo.co.mz",
"served_commit": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"installer": {
"status": "installed",
"commit": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"release": "/var/www/investmoz-homologacao/releases/d8224ba84b56482e0291bc18bb1c9c29316b19b9-c0d7c675",
"previous_release": "/var/www/investmoz-homologacao/releases/6b544548d3c83fc8a72ab65d8f58f84685a2877f-b38d94da",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"d8224ba84b56482e0291bc18bb1c9c29316b19b9"
],
"finished_at": "2026-10-23T15:12:40.124788+00:00"
},
"public_revision": {
"commit": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"branch": "main",
"built_at": "2026-10-23T15:12:37.169518+00:00",
"manifest_sha256": "52a021c1281e72d2aabe4a8fad82a150857e851d917c28e6898d2d439dfb771f"
},
"verification": {
"qa_guard_assertions": 3106,
"unit_tests": 57,
"unit_assertions": 309,
"frontend_tests": 208,
"frontend_failures": 0,
"public_real_fiche_opened": "INV-MZ-GEN-6048328347519124",
"real_target_id": 48,
"origin_preserved": "portfolio:a7271336-808b-42b4-8bfd-5b49c72dbe2b",
"spinning": "need_without_identified_offer_location_undefined",
"service": "existing_publication_states_no_synthetic_fixture_transferred",
"manual_business_cases_repeated": false
},
"preservation": {
"concurrent_main": "43cd0be7cbe2450f1928b059f1456454f23943ef",
"integration": "088f2c2cf47f5b16f351e231c490e848a664e433",
"accepted_delivery": "6b544548",
"accepted_receipt": "4098192a",
"database_migrations": 0,
"content_imports": 0,
"qa_fixture_payload_shipped": false,
"transversal_coverage": "partial"
},
"screenshot": {
"path": "outputs/complements-install-20261023/installed-complements.png",
"sha256": "9d48d2a51d5fbb1c0f5e92247af399c582444b329406416c172848ee7b1cb1e4"
},
"pending": [
"multi-opportunity specific contexts in zones/parks, Terra/DUAT, Balcao and manifestation remain to be demonstrated"
]
}
}
@@ -0,0 +1,89 @@
{
"date": "2026-10-23",
"status": "installed_in_homologation_delta_verified",
"functional_commit": "1afdfee8",
"base": "bc84fbdb",
"accepted_deliveries_preserved": [
"6b544548",
"d8224ba8",
"55136b44"
],
"qa": {
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"guard": "asserted in tests and fixture preparation",
"case_id": "d279172b-8bd1-4074-b000-ee25f0d29778",
"actor": "synthetic existing QA actor 509",
"browser": "Edge http://127.0.0.1:18574",
"existing_accepted_cases_modified": false
},
"changes": [
"simulator explicit or inherited opportunity key saved and recovered",
"applicability facts reasons and stage details by opportunity without replacing common data",
"land shortcut filters dossier owner and chosen opportunity",
"requirement and return links preserve scope",
"authorised common contact proposals where duplication was found",
"Word/ZIP/print composition identifies selected scope and applicable stages"
],
"verification": {
"http_tests": 7,
"http_assertions": 170,
"http_suite": "tests/Feature/InvestmentTreatmentScopeTest.php",
"frontend_tests": 2,
"frontend_suite": "tests/frontend/treatment-scope-export.test.mjs",
"typescript": "passed",
"production_build": "passed",
"visual": "new QA dossier second Manica / first Sofala / second; general simulator selection and scoped return to dossier"
},
"remaining": [
{
"scope": "native PDF",
"status": "only saved native PDF pagination and legibility remain unverified; HTML is not that proof",
"limitation": "browser-only control does not expose system print/save dialogue; no failure attributed to application"
},
{
"scope": "anchor projects sector and location search with manifestation and investment preparation continuity",
"status": "to analyse; no inference of implementation or defect",
"matrix": "AUD-REL-02"
}
],
"limits": [
"no homologation deployment or active data/schema/config/permission change",
"no repeat of accepted complement or four-consumer tests",
"no new visual proof of every alternative entry or removal editor; directed HTTP proof only",
"no statistics or AI work",
"temporary fixture clone location confirmation and test version field corrected before passing results"
],
"artifacts": [
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-dossier.png",
"sha256": "2b5f65064c80e376efdb2d12c87725c042027296f1e4ab6536f140462482562f"
},
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-dossier.txt",
"sha256": "0887a3ab5da2c6eccd369c7ca691df9d5f8d92279f6202eddf15b1652c138c89"
},
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-simulator.txt",
"sha256": "410f91d3afe220ec46f435c9de62d34671b2096d961527d0ce97a3edb9838b34"
},
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-exports/second.docx",
"sha256": "7aeadecb3684d000d5fe0c3b93d339f380c434daf3890ae24bd79c2f723ae40b"
},
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-exports/second.zip",
"sha256": "a3c1100d9c9ffc75fbda0f0489479c17275e8fa0b3025ad3ae2ecb293a9aa1f8"
},
{
"path": "outputs/multi-opportunity-fix-20261023/treatment-exports/second-print.html",
"sha256": "dffff89a9d4f186698bbc077a8a5031bd95290e12bcdba7b00ec7cd1a095bc4a"
}
],
"installation": {
"status": "installed_in_homologation_delta_verified",
"commit": "8036b9b071229dbf7e85ea748db70abcbeefc379",
"receipt": "treatment-scope-installation-receipt-20261023.json",
"delta_verified": true
}
}
@@ -0,0 +1,123 @@
{
"scope": "Shared administrative maps stabilization",
"source_revision": "cf2ddf21",
"candidate": "066707ec",
"owner_decision": "Tempo 2026-10-24: public consultation of the exact accepted administrative contours; originals private, no parcels or other internal layers",
"diagnosis": {
"data_loss": false,
"common_consumers": "Public-only filter excluded all 408 internal administrative boundaries",
"administration": "Legacy manage-portal gate excluded both approved superusers",
"comparison": "No change in common geometry service/controller/components between 30aed7cd and cf2ddf21",
"base_map": "Provider tiles and served assets respond; browser framing is checked after installation"
},
"qa": {
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"tests": 6,
"assertions": 64,
"result": "passed",
"phpstan": "passed",
"writes": "Only isolated QA transactions, rolled back"
},
"baseline": {
"published_fiches": 29,
"territorial_relations": 28,
"geometries": 408,
"geometry_rows_checksum": "7d8b71d3e65d89ffdc43c748b0572dbc"
},
"backup": {
"tables": 174,
"files_verified": 369,
"restore_tables_verified": 174,
"restore_network": "none",
"dump_sha256": "2fb5b4488799bb6072c38ee41ccf91fc2a55561363c19e280ab066363d9e0647"
},
"public_manifest_sha256": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc",
"installed": {
"status": "installed",
"commit": "066707ece631f0a7c963031c211844fbdd68916b",
"release": "/var/www/investmoz-homologacao/releases/066707ece631f0a7c963031c211844fbdd68916b-6b7bb5bd",
"previous_release": "/var/www/investmoz-homologacao/releases/cf2ddf21a1457f4852fe6aa10069ec3b854f1567-7749f82e",
"database_migrations": 0,
"content_imports": 0
},
"deferred": [
"Statistics",
"AI"
],
"accepted_tests_repeated": false,
"public_projection": {
"available": 408,
"levels": {
"admin_post": 264,
"district": 133,
"province": 11
},
"failures": [],
"manifest_sha256": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc"
},
"preservation": {
"tables": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 104,
"checksum": "5d172b4d252c7b025f23ac70cf570cb6"
},
"after": {
"rows": 104,
"checksum": "a60f3e47e1ae28937404f05f45e33135"
}
},
"sessions": {
"before": {
"rows": 6,
"checksum": "dcdb7eba3f3e8f29f40ec3f7542be6ce"
},
"after": {
"rows": 7,
"checksum": "0059c0b0e16d532c6658fd420582f2e9"
}
}
},
"unchanged_tables": 172
},
"installed_file_sha256": {
"app/Services/ApprovedAdministrativeBoundaries.php": "401fd62795ca8f33106be6e07130d9207d6661695440bfc40f62f6f6b42bec64",
"app/Services/TerritoryGeometry.php": "00ce3e6dde92868b0d34b963b8e59a26e6663149cdc0398c645ef636ca382966",
"app/Http/Controllers/InvestmentTerritoryController.php": "3b184c6ea1b97f0abe86d01567d3d73444c49192c638478a6d53619e63d5d18d",
"app/Http/Middleware/EnsureScopedPortalAdministration.php": "1474db760f6bd6003a5325ae721698e90e2709a2354b51abde77f920a9dad81a",
"docs/investmoz/unification/approved-administrative-boundaries-20261024.json": "06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc"
},
"pipeline_summaries": [
"OK (1 test, 3106 assertions)",
"built in 24.58s",
"OK (57 tests, 309 assertions)",
"# tests 216",
"# pass 216",
"# fail 0"
],
"proofs": {
"anonymous_http": {
"status": 200,
"territory_id": "dd219b89-cc17-5944-8c7d-d2766c82b526",
"selected": "DONDO",
"ancestor": "Sofala",
"areas": 2
},
"browser": {
"province_to_district": "passed",
"framing": "selected district with ancestor context",
"reload_preserves_selection": true,
"zoom": "passed",
"visible_tiles_loaded": 36,
"visible_tiles_failed": 0,
"screenshot": "outputs/map-stabilization-20261024/dondo-installed.png",
"screenshot_sha256": "7569f3b66aceb7ef9816c31bfaa172ebcdfa10e4911961b67a129a654b5cd349"
},
"business_rows_unchanged": true,
"active_synthetic_requests_created": 0
},
"status": "installed_delta_verified",
"remaining_in_scope": []
}
@@ -0,0 +1,95 @@
{
"date": "2026-10-23",
"status": "installed_in_homologation_delta_verified",
"target": "https://teste-investidor.tempo.co.mz",
"installed_commit": "55136b446deb710adf58ce2460e571bb19e94375",
"functional_commit": "4a01e9e2b7362282f844a8c6e0b26380ab0b71e0",
"qa_receipt_commit": "55136b446deb710adf58ce2460e571bb19e94375",
"diagnosis_commit": "ad4160f04074eb54ee3e5da213ba1cba884f02de",
"previous_served_commit": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"integration": {
"mode": "normal fast-forward push to existing main; no force",
"concurrent_main_at_integration": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"previous_history_preserved": true,
"schema_configuration_dependency_delta": false,
"fixtures_or_data_payload_shipped": false
},
"public_revision": {
"commit": "55136b446deb710adf58ce2460e571bb19e94375",
"branch": "main",
"built_at": "2026-10-23T15:55:10.921100+00:00",
"manifest_sha256": "b2dd6172516f220344ede5fc9d7876b7fc8417416d03842d737452709379a12c"
},
"installed_delta": {
"browser": "Edge; existing normal homologation session",
"existing_opportunity_id": 53,
"existing_reference": "INV-MZ-GEN-8326396601945337",
"existing_case": "958df138-7980-4685-8389-fa90be02ed6b",
"links": [
{
"href": "/investidor/terra-duat/novo?context=958df138-7980-4685-8389-fa90be02ed6b&opportunity=opportunity%3A53",
"text": "Terra/DUAT desta oportunidade"
},
{
"href": "/balcao-virtual/dossiers/958df138-7980-4685-8389-fa90be02ed6b?opportunity=opportunity%3A53",
"text": "Balcão desta oportunidade"
}
],
"authenticated_scoped_get": {
"case_id": "958df138-7980-4685-8389-fa90be02ed6b",
"version": 5,
"opportunities": [
{
"key": "opportunity:53",
"territory": "Sofala",
"park": null
}
],
"land": [
{
"province_id": "f57ff041-6275-57b9-8800-c35e46e0d475"
}
],
"desk_territory": "f57ff041-6275-57b9-8800-c35e46e0d475",
"submission_location": "Sofala",
"scoped_snapshot_choices": [
"opportunity:53"
]
},
"new_requests_created": 0,
"requests_saved_or_submitted": 0,
"accepted_business_cases_repeated": false,
"qa_proof_reused": "multi-opportunity-context-qa-receipt-20261023.json",
"installer": "Existing Git-triggered isolated build and atomic promotion; public served revision confirms completion. No manual edit of served directory."
},
"preservation": {
"protected_files_unchanged": {
"app/Services/InvestmentComplements.php": true,
"resources/js/components/investment-complements.tsx": true,
"docs/investmoz/unification/continuity-corrections-installation-receipt-20261023.json": true
},
"complements_delivery": "d8224ba8",
"previous_closes": [
"6b544548",
"4098192a"
],
"qa_fixtures_remain_qa_only": true,
"real_publication_states_not_changed": true
},
"deferred": [
"statistics",
"AI"
],
"limits": [
"Installed delta only; does not claim a new business acceptance or repeat second-opportunity QA cases.",
"No new native PDF acceptance.",
"Overall transversal implementation remains partial beyond this delivered scope."
],
"rollback": "Existing atomic pipeline rollback, retaining shared database, uploads, configuration and later history; prior served reference d8224ba8.",
"evidence_sha256": {
"installed-context-summary.json": "7f167ff8e13455eacf3a326aa0d0644870f849af33d0744e941f6afa9feefe9e",
"installed-links.json": "6de8a43461394870bb5b8f0462b13a71c29610c843d029d9bae32177849748f4",
"installed-scope.png": "04b1c7290305f8e2bafbfdd2fb77bb1d38207b3d30763dd3576e5aea154358aa",
"public-revision.json": "ffc2c30c02ced31797ed900f25dbb05c0274e2ff4a9cdb8bc0ef6ed7deddc653"
}
}
@@ -0,0 +1,118 @@
{
"date": "2026-10-23",
"status": "executable_correction_verified_in_isolated_qa_not_installed",
"functional_commit": "4a01e9e2b7362282f844a8c6e0b26380ab0b71e0",
"branch": "codex/opportunity-consumer-scope-20261023",
"diagnosis_commit": "ad4160f0",
"preserved_delivery": "d8224ba8",
"preserved_closes": [
"6b544548",
"4098192a"
],
"cause_and_correction": {
"parks": "Per-choice park reference and validation against that choice corridor and territory. Own lookup refreshes on own corridor/site. Previous common park is retained on its original first choice when reading legacy data.",
"consumer_scope": "Explicit opportunity key is resolved within the authorised dossier. Known fiche entry retains that key; multiple choices without a key show a chooser and propose only common data. No positional fallback for the three consumers.",
"persistence": "Canonical server-generated snapshot in each existing encrypted payload: identity, territory, corridor, park, source/version and scoped requirements. Client snapshots are replaced; foreign dossier identities are rejected.",
"fields": "Existing inheritance reconciliation retains deliberate local edits and parcel details. Returned desk request field restrictions retain locked association/snapshot.",
"reporting": "Land printable report displays saved identity and context; desk receipt displays saved scope; manifestation revision and intake metadata retain canonical association; common dossier report rows pair each park with its own opportunity."
},
"qa": {
"database": "simulator_fiscal_delta_20261021_test",
"port": 55441,
"browser": "Edge",
"url": "http://127.0.0.1:18574",
"actor_id": 509,
"new_case": "1017980b-a61c-44a4-b8d5-bd909c2d1316",
"first_choice_exactly_preserved": true,
"second_change": "309: Gaza/Limpopo/QA Gaza park -> Manica/Beira/QA Manica park",
"consumers": {
"land": {
"key": "opportunity:309",
"territory": "Manica",
"park": "SYNTHETIC QA — parque de ensaio Manica",
"context_revision": 2,
"requirement_keys": [
"opportunity:309"
]
},
"desk": {
"key": "opportunity:309",
"territory": "Manica",
"park": "SYNTHETIC QA — parque de ensaio Manica",
"context_revision": 2,
"requirement_keys": [
"opportunity:309"
]
},
"submission": {
"key": "opportunity:309",
"territory": "Manica",
"park": "SYNTHETIC QA — parque de ensaio Manica",
"context_revision": 2,
"requirement_keys": [
"opportunity:309"
]
}
},
"temporary_fixtures": "Three clearly marked synthetic parks only in isolated QA. Existing opportunity identities 286/309 reused; no new opportunity or service. Accepted complements case left intact."
},
"checks": {
"feature_tests": 4,
"feature_assertions": 104,
"frontend_tests": 3,
"typescript": "passed",
"build": "passed",
"browser": [
"second-only edit, park options, confirmation and recovery",
"land entry from identified second choice, save, recovery and printable report",
"desk scoped entry, draft save and reload",
"manifestation from existing fiche, explicit dossier binding, draft save and reload",
"unscoped multi-choice entry asks for a choice; selecting second recovers its Manica scope"
],
"additional_checks": [
"canonical snapshot rejects client forgery",
"foreign identity and other actor rejected",
"intermediate unknown territory draft recovered without restoring the source location",
"returned request preserves locked association",
"desk receipt template renders canonical second scope; manifestation revision retains association; report park rows retain both identities"
],
"limits": [
"No external submission or institutional decision was made. Desk receipt template was exercised with an isolated transaction fixture, not claimed as a real receipt.",
"Land HTML printable report was visually checked; no new native PDF export acceptance is claimed.",
"Accepted complement functional evidence was reused; no new visual round of those cases.",
"Initial test invoker used default arguments and started the default suite; it was interrupted and fixed to target this file. That incomplete run is not acceptance evidence."
]
},
"preservation": {
"protected_files_unchanged": {
"app/Services/InvestmentComplements.php": true,
"resources/js/components/investment-complements.tsx": true,
"docs/investmoz/unification/continuity-corrections-installation-receipt-20261023.json": true
},
"accepted_case_choices_and_sites": true,
"accepted_complements_retained": 4,
"migrations": 0,
"content_imports": 0,
"active_database_writes": 0,
"publication_changes_in_homologation": 0,
"qa_fixtures_shipped": false
},
"homologation": {
"unchanged": true,
"served_commit": "d8224ba84b56482e0291bc18bb1c9c29316b19b9",
"main_not_updated": true
},
"evidence_directory": "outputs/multi-opportunity-fix-20261023",
"evidence_sha256": {
"desk-recovered.txt": "a294e3d1a439e7ff42b66c59e9b4edc4a960a606384880faba02b78a4da884cc",
"explicit-choice-selected.txt": "f2a7432816b3b39881111ea7f4ccb2ac29a586ac407e5cd1a0f54f9b901cd359",
"explicit-choice.txt": "437ea9df20c437b8781c2279c8aa0f847a4dc45ffb1d3d0b455e4520b2c38297",
"land-report.png": "a586050af1f58d279fe2733f03861bf8f8d4e3f76e5076aee2e013a9ca7f4802",
"land-report.txt": "b274f72934d4717ffc08c75dc6574840b7f0b0ec0e6e987ebc52ce1fa56549e5",
"submission-recovered.png": "5dc5da5ff7bdb48a06649fd287e5c22f606e8bcc8035331821c0cd0c4cc0668e",
"submission-recovered.txt": "ac64e391cdaaa59a479e0ff3a829dc6daddf40d0d28b89a940cdfc35f223d6e1",
"verified-state.json": "a709caae0e6877128848dbb51d7bca929fd8457ace4331a565b422edef4e290f",
"visual-fixture.json": "6828f245430b938f0f6253186e81211af26641d959af0d7321d7c0d51bec5d55"
},
"transversal_status": "partial; this receipt covers the four named QA consumers only"
}
@@ -0,0 +1,122 @@
{
"date": "2026-10-23",
"status": "assessment_completed_gaps_confirmed_not_corrected",
"code_revision": "af9261809c6fece9ea3c7c79b49a80562f2ace68",
"accepted_complements_delivery": "d8224ba8",
"prior_closes": [
"6b544548",
"4098192a"
],
"accepted_cases_repeated": false,
"homologation_changed": false,
"probe": {
"date": "2026-10-23",
"qa_database": "simulator_fiscal_delta_20261021_test",
"qa_port": 55441,
"case_id": "6fdbb963-726e-4048-9884-8cddc04e77a6",
"transaction_rolled_back": true,
"first_choice_exactly_preserved": true,
"second_before": {
"key": "opportunity:309",
"territory": "Gaza",
"corridor": "limpopo"
},
"second_after_recovered": {
"key": "opportunity:309",
"territory": "Manica",
"corridor": "beira"
},
"third_choice_preserved": true,
"consumers": {
"land": {
"unchanged_after_second_change": true,
"before": {
"project_reference": "SYNTHETIC QA — conferência visual de complementos 23-10-2026",
"activity": "Agronegócio",
"purpose": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"parcels": [
{
"province_id": "f57ff041-6275-57b9-8800-c35e46e0d475"
}
]
},
"after": {
"project_reference": "SYNTHETIC QA — conferência visual de complementos 23-10-2026",
"activity": "Agronegócio",
"purpose": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"parcels": [
{
"province_id": "f57ff041-6275-57b9-8800-c35e46e0d475"
}
]
}
},
"desk": {
"unchanged_after_second_change": false,
"before": {
"title": "SYNTHETIC QA — conferência visual de complementos 23-10-2026",
"territory_id": "f57ff041-6275-57b9-8800-c35e46e0d475",
"location_source": "Referência consultada no contexto v2: Sofala. Não confirma disponibilidade.",
"description": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"sector": "Agronegócio",
"province_id": "f57ff041-6275-57b9-8800-c35e46e0d475"
},
"after": {
"title": "SYNTHETIC QA — conferência visual de complementos 23-10-2026",
"territory_id": "f57ff041-6275-57b9-8800-c35e46e0d475",
"location_source": "Referência consultada no contexto v3: Sofala. Não confirma disponibilidade.",
"description": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"sector": "Agronegócio",
"province_id": "f57ff041-6275-57b9-8800-c35e46e0d475"
}
},
"submission": {
"unchanged_after_second_change": true,
"before": {
"sector": "Agronegócio",
"objective": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"location": "Sofala"
},
"after": {
"sector": "Agronegócio",
"objective": "Produção, silos, moagem e processamento de milho, trigo e arroz.",
"location": "Sofala"
}
}
},
"parks": {
"ui_request_origin": "choices[0]",
"first_context": {
"corridor": "beira",
"territory": "Sofala"
},
"first_options": [],
"second_options_before": [],
"second_options_after": [],
"separate_park_slot_available": false
},
"revision_before": 2,
"revision_inside_transaction": 3,
"complement_acceptance_retested": false,
"original_case_exactly_preserved": true
},
"cause": {
"parks": "context.tsx derives request parameters and effect dependencies solely from choices[0]; selection.park and server compatibility validation are common and based on the first choice.",
"land": "InvestorContext::prefill generates one parcel from common fields; form.tsx applies only v[0] to the first parcel. No opportunity identity is attached to that proposal.",
"desk": "prefill uses common fields and first territory. A second-choice change updates the context revision text but retains first-choice territory and description.",
"submission": "prefill uses common sector, summary and location. No second-choice scope is supplied.",
"display": "DossierPrefill renders OpportunityChoices only for simulator; the other three consumers show common selection. Complement relations retain their independent existing display and are not retested."
},
"evidence_limits": [
"Commit/recovery exercised through existing application services inside a rolled-back QA transaction, not a new browser-session acceptance.",
"QA park option sets were empty for the sampled locations; no positive park availability or loss of a registered park is claimed.",
"Terra/DUAT current UI inspected read-only; desk and submission conclusions are based on executed prefill and source contracts, not submitted operations.",
"Deliberate form edits, save/recovery of the three destination forms and per-opportunity park selection remain acceptance criteria for a correction."
],
"visual_land": {
"path": "outputs/multi-opportunity-review-20261023/land-visible.txt",
"sha256": "5a2be5f9d0f6f0073d053bfdcb4523cf6e531ad3c929c2dbe6a8d4aaa34dfe4d"
},
"next_correction": "Scope zone selection and destination form proposals to an explicit opportunity identity; preserve other choices and deliberate edits; verify a second-only change and save/recovery in each destination.",
"transversal_status": "partial"
}
@@ -0,0 +1,63 @@
{
"date": "2026-10-23",
"candidate": "1afdfee8",
"native_report_fix": "2856240c",
"deployment_status": "installed_in_homologation_delta_verified",
"origin_main_checked": "55136b44",
"accepted_scopes_retested": false,
"new_test": "tests/frontend/native-pdf-scope.test.mjs: 1 passed",
"types": "passed",
"build": "passed",
"qa_report": {
"revision": 13,
"opportunity": "opportunity:309",
"location": "Manica",
"declared_funding_total": "123456 MZN",
"declared_secured": "45678 MZN",
"expected_gap": "77778.00 MZN",
"native_pdf_expected": "outputs/multi-opportunity-fix-20261023/candidata-1afdfee8.pdf",
"pdf_saved_verified": true,
"native_pdf_actual": "C:\\laragon\\www\\portal-investidor\\outputs\\multi-opportunity-fix-20261023\\Relatório — SYNTHETIC QA - escolha comum aos tres consumidores.pdf",
"native_pdf_sha256": "010eb4ea12015563c1b2f8bc255b1078c276f824c50690732541d5bffe34b8a6",
"native_pdf_pages": 10,
"visual_pagination": "passed pages1-10",
"file_discovery": {
"machine": "ONALA",
"user": "macbook",
"session": "Console",
"extension": ".pdf",
"size_bytes": 191637,
"requested_basename_not_found": "candidata-1afdfee8.pdf",
"actual_basename": "Relatório — SYNTHETIC QA - escolha comum aos tres consumidores.pdf",
"resolution": "existing file discovered by listing the exact requested directory; no rename, copy or PDF regeneration"
}
},
"anchor_analysis": {
"status": "analysed_not_implemented",
"confirmed_code_gaps": [
"sector filter absent from portfolio UI and query contract",
"no direct idea preparation from anchor fiche without an associated opportunity"
],
"directed_verification_remaining": [
"reconcile territorial data with demonstrated and destination state using equivalent access",
"anonymous interest authentication return and same-fiche identity"
],
"existing_accepted_branch": "portfolio origin via associated opportunity to dossier and simulator is preserved, not retested",
"qa_documentary_anchors": 15,
"qa_document_sector_location_region_present": true,
"qa_canonical_primary_territories": 0,
"qa_public_location_links": 0,
"qa_published_opportunity_links": 0,
"synthetic_anchor_excluded": true,
"inventory_sha256": "7d2c0c36fa51b05ce97dfd25c997b77eccf7136a99220ed8607fcd2436fd3d39",
"no_homologation_loss_inferred": true
},
"statistics_and_AI": "deferred",
"installation": {
"status": "installed_in_homologation_delta_verified",
"commit": "8036b9b071229dbf7e85ea748db70abcbeefc379",
"receipt": "treatment-scope-installation-receipt-20261023.json",
"delta_verified": true
},
"status": "installed_in_homologation_delta_verified"
}
@@ -35,8 +35,9 @@
"number": 3,
"component": "Navegação contextual e manifestação de interesse",
"historic_status": "Disponível",
"current_preservation_status": "Navegação/percurso preservados; carteira documental reposta em 23/10: 29 dossiers, incluindo 15 projectos âncora.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investimentos/iniciar) · Início, contexto e navegação abrem; gravação/recuperação aceites em QA reutilizadas. Sem dossier real no destino."
"current_preservation_status": "Continuity and multi-opportunity consumers delivered: 55136b44, 8036b9b0, cf2ddf21. Accepted proofs preserved.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/investimentos/iniciar) · Início, contexto e navegação abrem; gravação/recuperação aceites em QA reutilizadas. Sem dossier real no destino.",
"status_before_stabilization_closure": "Navegação/percurso preservados; carteira documental reposta em 23/10: 29 dossiers, incluindo 15 projectos âncora."
},
{
"number": 4,
@@ -175,8 +176,9 @@
"number": 23,
"component": "Cartografia e consumidores territoriais restantes",
"historic_status": "Não demonstrado",
"current_preservation_status": "Demarcação reposta: 408 geometrias. Polígonos de localidades e correspondências já pendentes não são nova regressão.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos/mapas abrem. 1 921 referências geográficas no alvo versus 1 990 locais; diferença não reconciliada por item fora do manifesto."
"current_preservation_status": "Shared maps delivered 066707ec/5d45541a: 408 accepted contours publicly available; originals private, 29 fiches and 28 relations preserved. Missing locality polygons remain future work.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos/mapas abrem. 1 921 referências geográficas no alvo versus 1 990 locais; diferença não reconciliada por item fora do manifesto.",
"status_before_stabilization_closure": "Demarcação reposta: 408 geometrias. Polígonos de localidades e correspondências já pendentes não são nova regressão."
},
{
"number": 24,
@@ -210,8 +212,9 @@
"number": 28,
"component": "Pesquisa — estados do recorte R2",
"historic_status": "Disponível",
"current_preservation_status": "Pesquisa e selectores corrigidos em 22/10; a carteira vazia é tratada como perda separada.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos abrem; quatro estados e protecção contra respostas antigas preservados do R2, sem repetir ensaios aceites."
"current_preservation_status": "Accepted search/selectors preserved; portfolio visibility and anchor continuity restored and delivered cf2ddf21. No current portfolio-empty fault.",
"evidence": "[Abrir](https://teste-investidor.tempo.co.mz/oportunidades) · Catálogos abrem; quatro estados e protecção contra respostas antigas preservados do R2, sem repetir ensaios aceites.",
"status_before_stabilization_closure": "Pesquisa e selectores corrigidos em 22/10; a carteira vazia é tratada como perda separada."
},
{
"number": 29,
@@ -945,5 +948,79 @@
"new_roles_or_approvers": false,
"new_content_approval": false
},
"qa_recovery_preparation_note": "An initial QA audit-key collision rolled back atomically. Audit identity was scoped per original before the successful QA and destination recovery; no active attempt used the faulty key."
"qa_recovery_preparation_note": "An initial QA audit-key collision rolled back atomically. Audit identity was scoped per original before the successful QA and destination recovery; no active attempt used the faulty key.",
"stabilization_closure_20261024": {
"basis": "Tempo explicit sequence and technical preservation responsibility, 24/10/2026",
"installed_functional_baseline": "066707ece631f0a7c963031c211844fbdd68916b",
"map_receipt": "5d45541a",
"known_open_faults_in_delimited_stabilization_scope": [],
"does_not_close_all_43_components": true,
"prior_losses_do_not_share_a_proven_single_cause": true,
"accepted_closures": [
"6b544548/4098192a",
"d8224ba8/af926180",
"55136b44/b6a626c9",
"8036b9b0/cdf8fcfb",
"cf2ddf21/c1f4a719",
"066707ec/5d45541a"
],
"documentary_limits": [
"Six legacy opportunity/anchor-cluster pairs without documented identity remain indeterminate: AUD-REL-02",
"Two incomplete legacy originals retain their existing documentary limit"
],
"not_yet_proven_component_numbers": [
6,
18,
21,
22,
24,
25,
35
],
"future_requirement_ids": [
"AUD-MARKET-01",
"AUD-ESTABLISHMENT-01",
"AUD-FUND-01",
"AUD-COMPANY-01",
"AUD-COMPANY-02",
"AUD-CAPITAL-01",
"AUD-CAPITAL-02",
"AUD-FINTECH-01"
],
"territorial_count_reconciliation": {
"source": "outputs/preservation-inventory-20261023/local.json and homologation.json",
"public_active_local": 1921,
"public_active_target": 1921,
"local_archived_internal_groups": [
32,
32,
5
],
"individual_identity_comparison_of_archived_69_claimed": false,
"reactivation_authorized": false
},
"new_control": {
"test": "tests/Unit/ApprovedAdministrativeBoundariesTest.php",
"automatic_delivery_suite": "Unit",
"tests": 2,
"assertions": 8,
"result": "passed",
"scope": "Approved public snapshot identity; changed geometry/metadata, wrong territory and new internal identity rejected",
"http_access_contract": "tests/Feature/TerritoryGeometryConsumerAccessTest.php",
"http_contract_run_when": "Geometry/access/hierarchy changes, on isolated QA only; existing accepted result reused here"
},
"technical_preservation_owner": "Codex and programmers",
"Tempo_review": "Utility, clarity and presentation; no obligation to rediscover technical regressions",
"sequence": [
"Corrections and stabilization",
"Fiscal simulator with defined scope",
"Real estate",
"Consumer goods and franchises",
"Statistics and dashboards",
"AI"
],
"accepted_acceptance_tests_repeated": false,
"active_database_writes": 0,
"runtime_application_source_changes": 0
}
}
@@ -0,0 +1,80 @@
{
"reference_commit": "276d833a4b4f9071db328b653f48529b2dfac4f9",
"runtime_files_changed_since_066707ec": [],
"matrix_records": 3423,
"matrix_columns": 49,
"updated_existing_rows": [
"AUD-GEO-01",
"AUD-GEO-02",
"AUD-GEO-03",
"AUD-REL-01",
"AUD-REL-02",
"AUD-DESK-01",
"AUD-DESK-02",
"AUD-SIM-01",
"AUD-LEG-06"
],
"accepted_receipts_unchanged_sha256": {
"map-stabilization-receipt-20261024.json": "2b69216b644f2244897431a10f3e6828e822d1317fab326a457a5934261c1618",
"anchor-integration-receipt-20261023.json": "86b0d01aa2fb03be84c1b1c6254ea0932abe813375f00560aaf39ce78d199f3d",
"treatment-scope-installation-receipt-20261023.json": "a0904250e1ed201276fce0318b9cc131edf4c8ec0ab6d449536b1e1344906798",
"multi-opportunity-context-installation-receipt-20261023.json": "3e1030de9aafd916252926a33d18cf808a05e389ddce5d9a3cd5230f039bc8f2"
},
"new_tests": {
"tests": 2,
"assertions": 8,
"passed": true
},
"active_database_writes": 0,
"status": "installed_reference_verified",
"date_Africa_Johannesburg": "2026-10-24",
"git_tag": "reference/stabilization-20261024",
"served_revision": {
"commit": "276d833a4b4f9071db328b653f48529b2dfac4f9",
"branch": "main",
"built_at": "2026-10-24T09:10:08.359035+00:00",
"manifest_sha256": "949d1047867f5879e724e5ddc38d4865b06aeb92641337d3952ea7b5ad55bb7a"
},
"previous_functional_revision": "066707ece631f0a7c963031c211844fbdd68916b",
"verification_method": "New unit control tested; semantic matrix/inventory reconciliation; canonical accepted receipt hashes; empty Git diff for runtime/schema/config/permissions/deploy; public installed revision. Prior accepted technical and visual proofs reused.",
"accepted_tests_repeated_by_this_review": false,
"automatic_installer": "Normal existing pipeline; no extra manual acceptance round",
"fresh_authenticated_database_read_claimed": false,
"business_data_preservation": "Accepted map receipt 5d45541a reused: 29 fiches, 28 links, 408 geometries, 172 business/nonvolatile tables equal; no runtime or data mutation introduced by this reference delta",
"known_open_stabilization_faults": [],
"documentary_pending": [
"AUD-REL-02: six legacy opportunity/anchor-cluster pairs remain indeterminate without documented relationships",
"Two incomplete originals in the legacy collection retain the accepted documentary limit"
],
"not_yet_proven_existing_components": [
6,
18,
21,
22,
24,
25,
35
],
"future_requirements": [
"AUD-MARKET-01",
"AUD-ESTABLISHMENT-01",
"AUD-FUND-01",
"AUD-COMPANY-01",
"AUD-COMPANY-02",
"AUD-CAPITAL-01",
"AUD-CAPITAL-02",
"AUD-FINTECH-01"
],
"technical_preservation_owner": "Codex and programmers",
"Tempo_evaluation": "Usefulness, clarity, presentation; does not need to rediscover technical regressions",
"next": "Fiscal simulator scope definition; not started by this consolidation",
"reference_sequence": [
"Stabilization",
"Defined fiscal simulator scope",
"Real estate",
"Consumer goods and franchises",
"Statistics and dashboards",
"AI"
],
"not_complete_portal_acceptance": true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,174 @@
{
"status": "installed_in_homologation_delta_verified",
"date": "2026-10-23",
"target": "https://teste-investidor.tempo.co.mz",
"served_commit": "8036b9b071229dbf7e85ea748db70abcbeefc379",
"functional_commits": [
"1afdfee8",
"2856240c"
],
"previous_main": "55136b446deb710adf58ce2460e571bb19e94375",
"public_revision": {
"commit": "8036b9b071229dbf7e85ea748db70abcbeefc379",
"branch": "main",
"built_at": "2026-10-23T16:46:11.203132+00:00",
"manifest_sha256": "6021421c4ab12146c5fae9c8966e3dae5c8bd1361132e12184e65e00b7e8951e"
},
"installer": {
"status": "installed",
"commit": "8036b9b071229dbf7e85ea748db70abcbeefc379",
"release": "/var/www/investmoz-homologacao/releases/8036b9b071229dbf7e85ea748db70abcbeefc379-5e851af2",
"previous_release": "/var/www/investmoz-homologacao/releases/55136b446deb710adf58ce2460e571bb19e94375-cad6589e",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"8036b9b071229dbf7e85ea748db70abcbeefc379"
],
"finished_at": "2026-10-23T16:46:13.798467+00:00"
},
"pipeline_summaries": [
"OK (1 test, 3106 assertions)",
"built in 24.30s",
"OK (57 tests, 309 assertions)",
"# tests 214",
"# pass 214",
"# fail 0"
],
"preservation": {
"fast_forward": true,
"force": false,
"protected_files": {
"app/Services/InvestmentComplements.php": true,
"resources/js/components/investment-complements.tsx": true,
"docs/investmoz/unification/continuity-corrections-installation-receipt-20261023.json": true
},
"matrix_changed_rows": [
"AUD-REL-02",
"AUD-LEG-06",
"AUD-SIM-INT03",
"AUD-SIM-INT06"
],
"unrelated_matrix_records_preserved": 3419,
"schema_config_fixtures_shipped": false
},
"native_saved_pdf": {
"actual_file": "C:\\laragon\\www\\portal-investidor\\outputs\\multi-opportunity-fix-20261023\\Relatório — SYNTHETIC QA - escolha comum aos tres consumidores.pdf",
"sha256": "010eb4ea12015563c1b2f8bc255b1078c276f824c50690732541d5bffe34b8a6",
"pages": 10,
"revision": 13,
"checks": {
"second_opportunity": true,
"manica": true,
"land_requirement": true,
"sector_requirement": true,
"human_state": true,
"technical_state_absent": true,
"first_location_absent": true,
"total": true,
"secured": true,
"gap": true
},
"visual_review": {
"status": "passed",
"pages_inspected": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"pagination": "1/10 through 10/10; A4; repeated table headers; no clipped rows or visible overlaps",
"last_page": "sparse final page contains final source rows and annex statement; not blank"
},
"discovery": {
"machine": "ONALA",
"user": "macbook",
"session": "Console",
"extension": ".pdf",
"size_bytes": 191637,
"requested_basename_not_found": "candidata-1afdfee8.pdf",
"actual_basename": "Relatório — SYNTHETIC QA - escolha comum aos tres consumidores.pdf",
"resolution": "existing file discovered by listing the exact requested directory; no rename, copy or PDF regeneration"
},
"regenerated": false
},
"installed_delta": {
"real_opportunity": 53,
"scope": {
"case_id": "958df138-7980-4685-8389-fa90be02ed6b",
"case_version": 5,
"context_revision": 1,
"simulator_opportunity": "opportunity:53",
"snapshot_choices": [
"opportunity:53"
],
"snapshot_territory": "Sofala",
"land_need": "no",
"land_step": {
"code": "S10",
"title": "Regularização da terra",
"state": "dispensed",
"applicability": "not_needed_for_preparation",
"reason": "",
"context_review_required": true
},
"requirements_scopes": [
"opportunity:53"
]
},
"checks": [
"new fiche links preserve opportunity53",
"dossier explicitly selects same opportunity and keeps tool query scope",
"authenticated context GET returns canonical simulator opportunity53 and its own requirements",
"existing no-land decision hides land action in the inspected dossier",
"15 changed functional file hashes equal Git release sources"
],
"case_version_unchanged_from_prior_receipt": true,
"requests_created_updated_submitted": 0,
"accepted_business_tests_repeated": false,
"qa_second_opportunity_cases_reused": true
},
"remaining_scope": {
"anchors": "analysis6985f82e: two implementation gaps, territorial reconciliation and directed interest/authentication proof; not implemented by this delivery",
"statistics_and_AI": "deferred"
},
"evidence": [
{
"path": "outputs/treatment-install-20261023/integration-preservation.json",
"sha256": "c6fcae5f64986d13216948589a35d1fa2d9f62229f4bd7a8a8c9f559f463fd6b"
},
{
"path": "outputs/treatment-install-20261023/installer-status.json",
"sha256": "f7875ffe9fa47092e5f0288ecbd97f4f016413628b2faed6815977287c26461e"
},
{
"path": "outputs/treatment-install-20261023/public-revision.json",
"sha256": "23325ab4cce9fced625b237c9793e3af309d923f12abbd047de96670611c8cac"
},
{
"path": "outputs/treatment-install-20261023/installed-hashes.json",
"sha256": "91f9df68c0d3b9c0ace6948145362f303291c5698bb2594bff9bb9c3aabc159c"
},
{
"path": "outputs/treatment-install-20261023/installed-links.json",
"sha256": "bf73f59ecfaccf8d10f45a72c36bd684e1b12abb667a65e0d2cda4dd396eb324"
},
{
"path": "outputs/treatment-install-20261023/installed-scope-summary.json",
"sha256": "fd410fa10ee63b8c09c311530cab78ca4f1f2b961c3d31cc78c40b86bc7af255"
},
{
"path": "outputs/treatment-install-20261023/installed-dossier.txt",
"sha256": "b5577b82ad0bce03131ffddbc365f1d039229549d6b83227ad57baffd1037f07"
},
{
"path": "outputs/treatment-install-20261023/installed-dossier.png",
"sha256": "9a3133a9fb6ca11fc64e0681393d518676bb72bceb75bfc95950466271158509"
}
]
}
@@ -1,4 +1,4 @@
Exemplar/caminho,Bytes,SHA256,Tipo,Nota de leitura,Disponibilidade,Uso em cálculo,Situação jurídica/documental,Edição/versão identificada,Disponibilidade conferida 12/10/2026,Caminho atual/alias,SHA256 atual,Correspondência binária,Observação da reconciliação
Exemplar/caminho,Bytes,SHA256,Tipo,Nota de leitura,Disponibilidade,Uso em cálculo,Situação jurídica/documental,Edição/versão identificada,Disponibilidade conferida 12/10/2026,Caminho atual/alias,SHA256 atual,Correspondência binária,Observação da reconciliação
C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\~WRL2550.tmp,451286,0ae1dc970cc219a57791483bf22f134b2fab1ff5a6d3cd98eba98a5737f23010,original,,Acervo inventariado; consulta/publicação individual não inferida,Nenhum cálculo ativado pela auditoria,Situação documental não determinada por inventário,,Exemplar acessível,C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\~WRL2550.tmp,0ae1dc970cc219a57791483bf22f134b2fab1ff5a6d3cd98eba98a5737f23010,Idêntico ao hash histórico,Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx,6005783,ece2c2edee8df625e712ff9f285df5c787378fa3477e466303b5a46ee0971c09,original,,Acervo inventariado; consulta/publicação individual não inferida,Nenhum cálculo ativado pela auditoria,Situação documental não determinada por inventário,,Exemplar acessível,C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx,ece2c2edee8df625e712ff9f285df5c787378fa3477e466303b5a46ee0971c09,Idêntico ao hash histórico,Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx#word/media/image1.png,1208097,1495ef144a048018723db1c0e11217fa14b4d7b14d8e65e32a3adeea23d08c4c,anexo embebido,,Acervo inventariado; consulta/publicação individual não inferida,Nenhum cálculo ativado pela auditoria,Situação documental não determinada por inventário,,Anexo embebido inventariado,C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx,,Não aplicável/sem bytes disponíveis,Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
@@ -606,3 +606,5 @@ C:\laragon\www\portal-investidor\docs\investmoz\v2\auditoria-portal\legado-sitem
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\segmentar processos v1.docx,104147,bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5,.docx,Original integral907parágrafos/14tabelas; relações externas/notas/alterações verificadas; hash e cópia privada preservados. Identidade binária com v1(3).docx confirmada pelo responsável em 11/10/2026; v1.docx é o nome local do mesmo exemplar.,PrivadoQA/biblioteca recurso29,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,"v1; propriedadeOOXMLrevision15; modificado11/10/2026 12:29UTC; mesmo exemplar de v1(3).docx, confirmado pelo responsável em 11/10/2026.",Exemplar acessível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\segmentar processos v1.docx,bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5,Idêntico ao hash histórico,Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~$gmentar processos v1.docx,162,dd30703646feabe737708b9072861ce24e7ebd953e25847edcb23143383d5ae2,.docx,Inventariado integralmente no mesmo diretório antes da seleção; conteúdo não promovido a implementação. Not a valid DOCX ZIP; inventoried without discarding.,Origem acessível; divulgação não inferida.,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,Nome/hash do exemplar; versão substantiva não inferida.,Original indisponível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~$gmentar processos v1.docx,,Não aplicável/sem bytes disponíveis,"Ficheiro temporário Word indisponível; referência histórica preservada, não omitir do inventário."
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~WRL2698.tmp,20868,fb8a11801469536438e9e85cacc3468d33253d22e94bb366f249d109ba9ab827,.tmp,Inventariado integralmente no mesmo diretório antes da seleção; conteúdo não promovido a implementação. ,Origem acessível; divulgação não inferida.,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,Nome/hash do exemplar; versão substantiva não inferida.,Original indisponível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~WRL2698.tmp,,Não aplicável/sem bytes disponíveis,"Ficheiro temporário Word indisponível; referência histórica preservada, não omitir do inventário."
https://archive.gazettes.africa/archive/mz/2025/mz-government-gazette-series-i-supplement-dated-2025-05-21-no-95.pdf,329070,e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358,original oficial PDF,"BR95,I Série,Suplemento,21/05/2025;Lei3/2025 arts.1/2 eAnexoII;2páginas conferidas",Exemplar privado disponível para consulta;sem publicação automática,"Aplicado emG3cessação2026/P038–P043,emcódigoQA;semprorrogação presumida,benefíciohistórico ou activaçãoemservidor.",Origem oficial identificada;9(13) com termo31/12/2025;sem prorrogação presumida,Lei3/2025 de21/05/2025,Conferido em24/10/2026,C:\laragon\www\portal-investidor\docs\investmoz\simulations\source-archive\BR-95-I-Suplemento-2025-05-21.pdf,e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358,Original preservado porbytes/hash,G3 candidatoac948bd8b7ff34d661dd4cb7cbe88221093dfd83:termo31/12/2025 executável no percurso2026;P038–P043 comcode/APIaprovados evisualpendente. Original/proveniência/publicação preservados;zero importação/publicação embaseactiva. Histórico: Aquisição documental apenas;zero importação/publicação em base activa. Fonte aceite conforme decisãoTempo08/10;P038–P043 permanecem funcionais pendentes.
https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/,,,"Notícia oficial online,sem original porbytes preservado",Governo30/09/2026:aprovação dealterações regulamentaresIVA/IRPC/IRPS,Consulta online livre;sem importação/publicação peloportal,Não usada paraactivar cálculo;inventariada paracotejo dodiploma,"Comunicado não substitui decreto,publicação ou períodoaplicável","RegulamentoCIVA/Decreto7/2008:artigos mencionados3,7,8,15,16-A,18,21,23,28,36,37",Consultado24/10/2026,URLonline;semficheirooriginallocal,,Proveniência oficial dapágina;semafirmar vigência dodiploma,Cotejar publicação/texto/período eafectarapenas regrasdependentes;sem bloqueio genéricoG4A
1 Exemplar/caminho Bytes SHA256 Tipo Nota de leitura Disponibilidade Uso em cálculo Situação jurídica/documental Edição/versão identificada Disponibilidade conferida 12/10/2026 Caminho atual/alias SHA256 atual Correspondência binária Observação da reconciliação
2 C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\~WRL2550.tmp 451286 0ae1dc970cc219a57791483bf22f134b2fab1ff5a6d3cd98eba98a5737f23010 original Acervo inventariado; consulta/publicação individual não inferida Nenhum cálculo ativado pela auditoria Situação documental não determinada por inventário Exemplar acessível C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\~WRL2550.tmp 0ae1dc970cc219a57791483bf22f134b2fab1ff5a6d3cd98eba98a5737f23010 Idêntico ao hash histórico Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
3 C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx 6005783 ece2c2edee8df625e712ff9f285df5c787378fa3477e466303b5a46ee0971c09 original Acervo inventariado; consulta/publicação individual não inferida Nenhum cálculo ativado pela auditoria Situação documental não determinada por inventário Exemplar acessível C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx ece2c2edee8df625e712ff9f285df5c787378fa3477e466303b5a46ee0971c09 Idêntico ao hash histórico Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
4 C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx#word/media/image1.png 1208097 1495ef144a048018723db1c0e11217fa14b4d7b14d8e65e32a3adeea23d08c4c anexo embebido Acervo inventariado; consulta/publicação individual não inferida Nenhum cálculo ativado pela auditoria Situação documental não determinada por inventário Anexo embebido inventariado C:\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\diagramas.docx Não aplicável/sem bytes disponíveis Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
606 https://archive.gazettes.africa/archive/mz/2025/mz-government-gazette-series-i-supplement-dated-2025-05-21-no-95.pdf 329070 e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358 original oficial PDF BR95,I Série,Suplemento,21/05/2025;Lei3/2025 arts.1/2 eAnexoII;2páginas conferidas Exemplar privado disponível para consulta;sem publicação automática Aplicado emG3cessação2026/P038–P043,emcódigoQA;semprorrogação presumida,benefíciohistórico ou activaçãoemservidor. Origem oficial identificada;9(13) com termo31/12/2025;sem prorrogação presumida Lei3/2025 de21/05/2025 Conferido em24/10/2026 C:\laragon\www\portal-investidor\docs\investmoz\simulations\source-archive\BR-95-I-Suplemento-2025-05-21.pdf e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358 Original preservado porbytes/hash G3 candidatoac948bd8b7ff34d661dd4cb7cbe88221093dfd83:termo31/12/2025 executável no percurso2026;P038–P043 comcode/APIaprovados evisualpendente. Original/proveniência/publicação preservados;zero importação/publicação embaseactiva. Histórico: Aquisição documental apenas;zero importação/publicação em base activa. Fonte aceite conforme decisãoTempo08/10;P038–P043 permanecem funcionais pendentes.
607 https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ Notícia oficial online,sem original porbytes preservado Governo30/09/2026:aprovação dealterações regulamentaresIVA/IRPC/IRPS Consulta online livre;sem importação/publicação peloportal Não usada paraactivar cálculo;inventariada paracotejo dodiploma Comunicado não substitui decreto,publicação ou períodoaplicável RegulamentoCIVA/Decreto7/2008:artigos mencionados3,7,8,15,16-A,18,21,23,28,36,37 Consultado24/10/2026 URLonline;semficheirooriginallocal Proveniência oficial dapágina;semafirmar vigência dodiploma Cotejar publicação/texto/período eafectarapenas regrasdependentes;sem bloqueio genéricoG4A
608
609
610
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

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